stereo solution first commit
[tas2555sw-android/tas2555-android-device-driver-stereo.git] / tiload.c
1 /*
2 ** =============================================================================
3 ** Copyright (c) 2016  Texas Instruments Inc.
4 **
5 ** This program is free software; you can redistribute it and/or modify it under
6 ** the terms of the GNU General Public License as published by the Free Software 
7 ** Foundation; version 2.
8 **
9 ** This program is distributed in the hope that it will be useful, but WITHOUT
10 ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 ** FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 **
13 ** You should have received a copy of the GNU General Public License along with
14 ** this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 ** Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 **
17 ** File:
18 **     tiload.c
19 **
20 ** Description:
21 **     utility for TAS2555 Android in-system tuning
22 **
23 ** =============================================================================
24 */
27 #include <linux/module.h>
28 #include <linux/moduleparam.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
31 #include <linux/fs.h>
32 #include <linux/types.h>
33 #include <linux/kdev_t.h>
34 #include <linux/cdev.h>
35 #include <linux/device.h>
36 #include <asm/io.h>
37 #include <linux/delay.h>
38 #include <linux/i2c.h>
39 #include <linux/platform_device.h>
40 #include <asm/uaccess.h>
42 #include "tiload.h"
44 /* enable debug prints in the driver */
45 #define DEBUG
47 #ifdef DEBUG
48 #define dprintk(x...)   printk(x)
49 #else
50 #define dprintk(x...)
51 #endif
53 //#ifdef TI_LOAD
55 /* Function prototypes */
56 #ifdef REG_DUMP
57 static void dump_page(struct i2c_client *i2c, u8 page);
58 #endif
60 /* externs */
61 //extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
62 //extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
63 //extern int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
64 //             unsigned int value);
66 static struct cdev *tiload_cdev;
67 static int tiload_major = 0;    /* Dynamic allocation of Mjr No. */
68 static int tiload_opened = 0;   /* Dynamic allocation of Mjr No. */
69 static struct tas2555_priv *g_TAS2555;
70 struct class *tiload_class;
71 static unsigned int magic_num = 0x00;
72 //static int (*codec_write) (struct snd_soc_codec *, unsigned int, unsigned int) = 0;
73 //static unsigned int (*codec_read) (struct snd_soc_codec *, unsigned int) = 0; 
75 static char gPage = 0;
76 static char gBook = 0;
77 /******************************** Debug section *****************************/
79 #ifdef REG_DUMP
80 /*
81  *----------------------------------------------------------------------------
82  * Function : dump_page
83  * Purpose  : Read and display one codec register page, for debugging purpose
84  *----------------------------------------------------------------------------
85  */
86 static void dump_page(struct i2c_client *i2c, u8 page)
87 {
88 /*
89     int i;
90     u8 data;
91     u8 test_page_array[8];
93     dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
94 //    aic3262_change_page(codec, page);
96     data = 0x0;
98     i2c_master_send(i2c, data, 1);
99     i2c_master_recv(i2c, test_page_array, 8);
101     printk("\n------- aic3262 PAGE %d DUMP --------\n", page);
102     for (i = 0; i < 8; i++) {
103         printk(" [ %d ] = 0x%x\n", i, test_page_array[i]);
104     }
105 */
107 #endif
109 /*
110  *----------------------------------------------------------------------------
111  * Function : tiload_open
112  *
113  * Purpose  : open method for tiload programming interface
114  *----------------------------------------------------------------------------
115  */
116 static int tiload_open(struct inode *in, struct file *filp)
118         dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
119         if (tiload_opened) {
120                 printk("%s device is already opened\n", "tiload");
121                 printk("%s: only one instance of driver is allowed\n", "tiload");
122                 return -1;
123         }
124         tiload_opened++;
125         return 0;
128 /*
129  *----------------------------------------------------------------------------
130  * Function : tiload_release
131  *
132  * Purpose  : close method for tiload programming interface
133  *----------------------------------------------------------------------------
134  */
135 static int tiload_release(struct inode *in, struct file *filp)
137         dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
138         tiload_opened--;
139         return 0;
142 #define MAX_LENGTH 128
143 /*
144  *----------------------------------------------------------------------------
145  * Function : tiload_read
146  *
147  * Purpose  : read from codec
148  *----------------------------------------------------------------------------
149  */
150 static ssize_t tiload_read(struct file *file, char __user * buf,
151         size_t count, loff_t * offset)
153         static char rd_data[MAX_LENGTH + 1];
154         unsigned int nCompositeRegister = 0, Value;
155         //unsigned int n;
156         char reg_addr;
157         size_t size;
158         int ret = 0;
159 #ifdef DEBUG
160         int i;
161 #endif
162 //    struct i2c_client *i2c = g_codec->control_data;
164         dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
165         if (count > MAX_LENGTH) {
166                 printk("Max %d bytes can be read\n", MAX_LENGTH);
167                 return -1;
168         }
170         /* copy register address from user space  */
171         size = copy_from_user(&reg_addr, buf, 1);
172         if (size != 0) {
173                 printk("read: copy_from_user failure\n");
174                 return -1;
175         }
177         size = count;
179         nCompositeRegister = BPR_REG(gBook, gPage, reg_addr);
180         if (count == 1) {
181                 ret =
182                         g_TAS2555->read(g_TAS2555, 0x80000000 | nCompositeRegister, &Value);
183                 if (ret >= 0)
184                         rd_data[0] = (char) Value;
185         } else if (count > 1) {
186                 ret =
187                         g_TAS2555->bulk_read(g_TAS2555, 0x80000000 | nCompositeRegister,
188                         rd_data, size);
189         }
190         if (ret < 0)
191                 printk("%s, %d, ret=%d, count=%zu error happen!\n", __FUNCTION__,
192                         __LINE__, ret, count);
193 //    size = i2c_master_recv(i2c, rd_data, count);
194 #ifdef DEBUG
195         printk(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n",
196                 (int) size, reg_addr, (int) count);
197         for (i = 0; i < (int) size; i++) {
198                 printk(KERN_ERR "rd_data[%d]=%x\n", i, rd_data[i]);
199         }
200 #endif
201         if (size != count) {
202                 printk("read %d registers from the codec\n", (int) size);
203         }
205         if (copy_to_user(buf, rd_data, size) != 0) {
206                 dprintk("copy_to_user failed\n");
207                 return -1;
208         }
210         return size;
213 /*
214  *----------------------------------------------------------------------------
215  * Function : tiload_write
216  *
217  * Purpose  : write to codec
218  *----------------------------------------------------------------------------
219  */
220 static ssize_t tiload_write(struct file *file, const char __user * buf,
221         size_t count, loff_t * offset)
223         static char wr_data[MAX_LENGTH + 1];
224         char *pData = wr_data;
225         size_t size;
226         unsigned int nCompositeRegister = 0;
227 //    u8 pg_no;
228 //    unsigned int n;   
229         unsigned int nRegister;
230         int ret = 0;
231 #ifdef DEBUG
232         int i;
233 #endif
234 //    struct i2c_client *i2c = g_codec->control_data;
236         dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
238         if (count > MAX_LENGTH) {
239                 printk("Max %d bytes can be read\n", MAX_LENGTH);
240                 return -1;
241         }
243         /* copy buffer from user space  */
244         size = copy_from_user(wr_data, buf, count);
245         if (size != 0) {
246                 printk("copy_from_user failure %d\n", (int) size);
247                 return -1;
248         }
249 #ifdef DEBUG
250         printk(KERN_ERR "write size = %zu\n", count);
251         for (i = 0; i < (int) count; i++) {
253                 printk(KERN_INFO "\nwr_data[%d]=%x\n", i, wr_data[i]);
254         }
255 #endif
256         nRegister = wr_data[0];
257         size = count;
258         if ((nRegister == 127) && (gPage == 0)) {
259                 gBook = wr_data[1];
260                 return size;
261         }
263         if (nRegister == 0) {
264                 gPage = wr_data[1];
265                 pData++;
266                 count--;
267         }
268 #if 1
269         nCompositeRegister = BPR_REG(gBook, gPage, nRegister);
270         if (count == 2) {
271                 ret =
272                         g_TAS2555->write(g_TAS2555, 0x80000000 | nCompositeRegister,
273                         pData[1]);
274         } else if (count > 2) {
275                 ret =
276                         g_TAS2555->bulk_write(g_TAS2555, 0x80000000 | nCompositeRegister,
277                         &pData[1], count - 1);
278         }
279         if (ret < 0)
280                 printk("%s, %d, ret=%d, count=%zu, ERROR Happen\n", __FUNCTION__,
281                         __LINE__, ret, count);
282 #else
283         for (n = 1; n < count; n++) {
284                 nCompositeRegister = BPR_REG(gBook, gPage, nRegister + n - 1);
285                 g_codec->driver->write(g_codec, 0x80000000 | nCompositeRegister,
286                         pData[n]);
287         }
288 #endif
290         return size;
293 static void tiload_route_IO(unsigned int bLock)
295         if (bLock) {
296                 g_TAS2555->write(g_TAS2555, 0xAFFEAFFE, 0xBABEBABE);
297         } else {
298                 g_TAS2555->write(g_TAS2555, 0xBABEBABE, 0xAFFEAFFE);
299         }
302 static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
304         long num = 0;
305         void __user *argp = (void __user *) arg;
306         int val;
308         BPR bpr;
310         printk(KERN_ERR "tiload_ioctl\n\r");
311 //    if (_IOC_TYPE(cmd) != TILOAD_IOC_MAGIC)
312 //        return -ENOTTY;
314         dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
315         switch (cmd) {
316         case TILOAD_IOMAGICNUM_GET:
317                 num = copy_to_user(argp, &magic_num, sizeof(int));
318                 break;
319         case TILOAD_IOMAGICNUM_SET:
320                 num = copy_from_user(&magic_num, argp, sizeof(int));
321                 tiload_route_IO(magic_num);
322                 break;
323         case TILOAD_BPR_READ:
324                 break;
325         case TILOAD_BPR_WRITE:
326                 num = copy_from_user(&bpr, argp, sizeof(BPR));
327                 printk("TILOAD_BPR_WRITE: 0x%02X, 0x%02X, 0x%02X\n\r", bpr.nBook,
328                         bpr.nPage, bpr.nRegister);
329                 break;
330         case TILOAD_IOCTL_SET_CONFIG:
331                 num = copy_from_user(&val, argp, sizeof(val));
332                 g_TAS2555->set_config(g_TAS2555, val);
333                 break;
334         case TILOAD_IOCTL_SET_CALIBRATION:
335                 num = copy_from_user(&val, argp, sizeof(val));
336                 g_TAS2555->set_calibration(g_TAS2555, val);
337                 break;                          
338         default:
339                 break;
340         }
341         return num;
344 /*********** File operations structure for tiload *************/
345 static struct file_operations tiload_fops = {
346         .owner = THIS_MODULE,
347         .open = tiload_open,
348         .release = tiload_release,
349         .read = tiload_read,
350         .write = tiload_write,
351         .unlocked_ioctl = tiload_ioctl,
352 };
354 /*
355  *----------------------------------------------------------------------------
356  * Function : tiload_driver_init
357  *
358  * Purpose  : Register a char driver for dynamic tiload programming
359  *----------------------------------------------------------------------------
360  */
361 int tiload_driver_init(struct tas2555_priv *pTAS2555)
363         int result;
365         dev_t dev = MKDEV(tiload_major, 0);
366         dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
367         g_TAS2555 = pTAS2555;
369         dprintk("allocating dynamic major number\n");
371         result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
372         if (result < 0) {
373                 dprintk("cannot allocate major number %d\n", tiload_major);
374                 return result;
375         }
376         tiload_class = class_create(THIS_MODULE, DEVICE_NAME);
377         tiload_major = MAJOR(dev);
378         dprintk("allocated Major Number: %d\n", tiload_major);
380         tiload_cdev = cdev_alloc();
381         cdev_init(tiload_cdev, &tiload_fops);
382         tiload_cdev->owner = THIS_MODULE;
383         tiload_cdev->ops = &tiload_fops;
385         if (device_create(tiload_class, NULL, dev, NULL, "tiload_node") == NULL)
386                 dprintk(KERN_ERR "Device creation failed\n");
388         if (cdev_add(tiload_cdev, dev, 1) < 0) {
389                 dprintk("tiload_driver: cdev_add failed \n");
390                 unregister_chrdev_region(dev, 1);
391                 tiload_cdev = NULL;
392                 return 1;
393         }
394         printk("Registered TiLoad driver, Major number: %d \n", tiload_major);
395         //class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0);
396         return 0;
399 MODULE_AUTHOR("Texas Instruments Inc.");
400 MODULE_DESCRIPTION("Utility for TAS2555 Android in-system tuning");
401 MODULE_LICENSE("GPLv2");
402 //#endif