]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tas2555sw-android/tas2555-android-device-driver-stereo.git/blob - tiload.c
add stereo as keyword for ALSA
[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 */
25 /* enable debug prints in the driver */
26 #define DEBUG
28 #include <linux/module.h>
29 #include <linux/moduleparam.h>
30 #include <linux/init.h>
31 #include <linux/kernel.h>
32 #include <linux/fs.h>
33 #include <linux/types.h>
34 #include <linux/kdev_t.h>
35 #include <linux/cdev.h>
36 #include <linux/device.h>
37 #include <asm/io.h>
38 #include <linux/slab.h>
39 #include <linux/delay.h>
40 #include <linux/i2c.h>
41 #include <linux/platform_device.h>
42 #include <asm/uaccess.h>
44 #include "tiload.h"
45 /* Function prototypes */
47 /* externs */
48 //static struct cdev *tiload_cdev;
49 //static int tiload_major = 0;  /* Dynamic allocation of Mjr No. */
50 //static int tiload_opened = 0; /* Dynamic allocation of Mjr No. */
51 static struct tas2555_priv *g_TAS2555;
52 //struct class *tiload_class;
53 //static unsigned int magic_num = 0x00;
55 //static char gPage = 0;
56 //static char gBook = 0;
57 /******************************** Debug section *****************************/
59 /*
60  *----------------------------------------------------------------------------
61  * Function : tiload_open
62  *
63  * Purpose  : open method for tiload programming interface
64  *----------------------------------------------------------------------------
65  */
66 static int tiload_open(struct inode *in, struct file *filp)
67 {
68         struct tas2555_priv *pTAS2555 = g_TAS2555;
69         const unsigned char *pFileName;
70         struct tiload_data *pTiLoad;
71         
72         dev_info(pTAS2555->dev, "%s\n", __FUNCTION__);
73         
74         pFileName = filp->f_path.dentry->d_name.name;
75         if(strcmp(pFileName, CHL_DEVICE_NAME) == 0)
76                 pTiLoad = pTAS2555->chl_private_data;
77         else if(strcmp(pFileName, CHR_DEVICE_NAME) == 0)
78                 pTiLoad = pTAS2555->chr_private_data;
79         else{
80                 dev_err(pTAS2555->dev, "channel err,dev (%s)\n", pFileName);
81                 return -1;              
82         }
83         
84         if(pTiLoad == NULL)
85                 return -1;
86         else{
87                 if(pTiLoad->mnTiload_Opened!=0){
88                         dev_info(pTAS2555->dev, "%s device is already opened\n", "tiload");
89                         dev_info(pTAS2555->dev, "%s: only one instance of driver is allowed\n", "tiload");
90                         return -1;
91                 }
92         }
93         
94         filp->private_data = (void*)pTAS2555;
95         pTiLoad->mnTiload_Opened++;
96         
97         return 0;
98 }
100 /*
101  *----------------------------------------------------------------------------
102  * Function : tiload_release
103  *
104  * Purpose  : close method for tiload programming interface
105  *----------------------------------------------------------------------------
106  */
107 static int tiload_release(struct inode *in, struct file *filp)
109         struct tas2555_priv *pTAS2555 = (struct tas2555_priv *)filp->private_data;
110         const unsigned char *pFileName;
111         struct tiload_data *pTiLoad;
112         
113         dev_info(pTAS2555->dev, "%s\n", __FUNCTION__);
114         
115         pFileName = filp->f_path.dentry->d_name.name;
116         if(strcmp(pFileName, CHL_DEVICE_NAME) == 0)
117                 pTiLoad = pTAS2555->chl_private_data;
118         else if(strcmp(pFileName, CHR_DEVICE_NAME) == 0)
119                 pTiLoad = pTAS2555->chr_private_data;
120         else{
121                 dev_err(pTAS2555->dev, "channel err,dev (%s)\n", pFileName);
122                 return 0;               
123         }
124         
125         if(pTiLoad == NULL)
126                 return 0;
127         
128         pTiLoad->mnTiload_Opened--;
129         return 0;
132 /*
133  *----------------------------------------------------------------------------
134  * Function : tiload_read
135  *
136  * Purpose  : read from codec
137  *----------------------------------------------------------------------------
138  */
139 static ssize_t tiload_read(struct file *filp, char __user * buf,
140         size_t count, loff_t * offset)
142         struct tas2555_priv *pTAS2555 = (struct tas2555_priv *)filp->private_data;      
143         const unsigned char *pFileName;
144         unsigned char channel;
145         struct tiload_data *pTiLoad;
146         unsigned int nCompositeRegister = 0, Value;
147         //unsigned int n;
148         char reg_addr;
149         size_t size;
150         int ret = 0;
151         unsigned char nBook, nPage;
152 #ifdef DEBUG
153         int i;
154 #endif
156         dev_dbg(pTAS2555->dev, "%s\n", __FUNCTION__);
157         
158         pFileName = filp->f_path.dentry->d_name.name;
159         if(strcmp(pFileName, CHL_DEVICE_NAME) == 0){
160                 pTiLoad = pTAS2555->chl_private_data;
161                 channel = channel_left;
162         }else if(strcmp(pFileName, CHR_DEVICE_NAME) == 0){
163                 pTiLoad = pTAS2555->chr_private_data;
164                 channel = channel_right;
165         }else{
166                 dev_err(pTAS2555->dev, "channel err,dev (%s)\n", pFileName);
167                 return -1;              
168         }
169         
170         if(pTiLoad == NULL)
171                 return -1;
172         
173         nBook = pTiLoad->mnBook;
174         nPage = pTiLoad->mnPage;
175         
176         if (count > MAX_LENGTH) {
177                 dev_err(pTAS2555->dev, "Max %d bytes can be read\n", MAX_LENGTH);
178                 return -1;
179         }
181         /* copy register address from user space  */
182         size = copy_from_user(&reg_addr, buf, 1);
183         if (size != 0) {
184                 dev_err(pTAS2555->dev, "read: copy_from_user failure\n");
185                 return -1;
186         }
188         size = count;
190         nCompositeRegister = BPR_REG(nBook, nPage, reg_addr);
191         if (count == 1) {
192                 ret = pTAS2555->read(pTAS2555, 
193                                         channel, 
194                                         0x80000000 | nCompositeRegister, &Value);
195                 if (ret >= 0)
196                         pTiLoad->mpRd_data[0] = (char) Value;
197         } else if (count > 1) {
198                 ret = pTAS2555->bulk_read(pTAS2555, 
199                                         channel, 
200                                         0x80000000 | nCompositeRegister, pTiLoad->mpRd_data, size);
201         }
202         if (ret < 0)
203                 dev_err(pTAS2555->dev, 
204                                 "%s, %d, ret=%d, count=%zu error happen!\n", 
205                                 __FUNCTION__, __LINE__, ret, count);
207 #ifdef DEBUG
208         dev_dbg(pTAS2555->dev, 
209                 "read size = %d, reg_addr= 0x%x , count = %d\n",
210                 (int) size, reg_addr, (int) count);
211         for (i = 0; i < (int) size; i++) {
212                 dev_dbg(pTAS2555->dev, 
213                         "chl[%d] rd_data[%d]=0x%x\n", 
214                         channel,i, pTiLoad->mpRd_data[i]);
215         }
216 #endif
217         if (size != count) {
218                 dev_err(pTAS2555->dev, 
219                         "read %d registers from the codec\n", (int) size);
220         }
222         if (copy_to_user(buf, pTiLoad->mpRd_data, size) != 0) {
223                 dev_err(pTAS2555->dev, "copy_to_user failed\n");
224                 return -1;
225         }
227         return size;
230 /*
231  *----------------------------------------------------------------------------
232  * Function : tiload_write
233  *
234  * Purpose  : write to codec
235  *----------------------------------------------------------------------------
236  */
237 static ssize_t tiload_write(struct file *filp, const char __user * buf,
238         size_t count, loff_t * offset)
240         struct tas2555_priv *pTAS2555 = (struct tas2555_priv *)filp->private_data;              
241         const unsigned char *pFileName;
242         unsigned char channel;
243         struct tiload_data *pTiLoad;
244         char *pData;// = wr_data;
245         size_t size;
246         unsigned int nCompositeRegister = 0;
247         unsigned int nRegister;
248         int ret = 0;
249 #ifdef DEBUG
250         int i;
251 #endif
253         dev_info(pTAS2555->dev, "%s\n", __FUNCTION__);
255         pFileName = filp->f_path.dentry->d_name.name;
256         if(strcmp(pFileName, CHL_DEVICE_NAME) == 0){
257                 channel = channel_left;
258                 pTiLoad = pTAS2555->chl_private_data;
259         }else if(strcmp(pFileName, CHR_DEVICE_NAME) == 0){
260                 channel = channel_right;
261                 pTiLoad = pTAS2555->chr_private_data;
262         }else{
263                 dev_err(pTAS2555->dev, "channel err,dev (%s)\n", pFileName);
264                 return -1;              
265         }
266         
267         dev_dbg(pTAS2555->dev, "file:%s, channel=%d\n", pFileName, channel);
268         
269         if(pTiLoad == NULL)
270                 return -1;
271         
272         if (count > MAX_LENGTH) {
273                 dev_err(pTAS2555->dev,"Max %d bytes can be read\n", MAX_LENGTH);
274                 return -1;
275         }
276         
277         pData = pTiLoad->mpWr_data;
279         /* copy buffer from user space  */
280         size = copy_from_user(pTiLoad->mpWr_data, buf, count);
281         if (size != 0) {
282                 dev_err(pTAS2555->dev,
283                         "copy_from_user failure %d\n", (int) size);
284                 return -1;
285         }
286 #ifdef DEBUG
287         dev_dbg(pTAS2555->dev, "write size = %zu\n", count);
288         for (i = 0; i < (int) count; i++) {
290                 dev_dbg(pTAS2555->dev,"wr_data[%d]=%x\n", i, pTiLoad->mpWr_data[i]);
291         }
292 #endif
293         nRegister = pTiLoad->mpWr_data[0];
294         size = count;
295         if ((nRegister == 127) && (pTiLoad->mnPage == 0)) {
296                 pTiLoad->mnBook = pTiLoad->mpWr_data[1];
297                 return size;
298         }
300         if (nRegister == 0) {
301                 pTiLoad->mnPage = pTiLoad->mpWr_data[1];
302                 if(count == 2) return size;
303                 pData++;
304                 count--;
305         }
306 #if 1
307         nCompositeRegister = BPR_REG(pTiLoad->mnBook, pTiLoad->mnPage, nRegister);
308         if (count == 2) {
309                 ret = pTAS2555->write(pTAS2555, 
310                                 channel, 
311                                 0x80000000 | nCompositeRegister, pData[1]);
312         } else if (count > 2) {
313                 ret = pTAS2555->bulk_write(pTAS2555, 
314                                 channel, 
315                                 0x80000000 | nCompositeRegister, &pData[1], count - 1);
316         }
317         if (ret < 0)
318                 dev_err(pTAS2555->dev,
319                         "%s, %d, ret=%d, count=%zu, ERROR Happen\n", 
320                         __FUNCTION__, __LINE__, ret, count);
321 #else
322         for (n = 1; n < count; n++) {
323                 nCompositeRegister = BPR_REG(gBook, gPage, nRegister + n - 1);
324                 g_codec->driver->write(g_codec, 0x80000000 | nCompositeRegister,
325                         pData[n]);
326         }
327 #endif
329         return size;
332 static void tiload_route_IO(struct tas2555_priv *pTAS2555, 
333         unsigned int bLock)
335         if (bLock) {
336                 pTAS2555->write(pTAS2555, 
337                         channel_both, 
338                         0xAFFEAFFE, 0xBABEBABE);
339         } else {
340                 pTAS2555->write(pTAS2555, 
341                         channel_both, 
342                         0xBABEBABE, 0xAFFEAFFE);
343         }
346 static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
348         long num = 0;
349         struct tas2555_priv *pTAS2555 = (struct tas2555_priv *)filp->private_data;      
350         const unsigned char *pFileName; 
351         struct tiload_data *pTiLoad;
352         int magic_num;
353         void __user *argp = (void __user *) arg;
354         int val;
355         BPR bpr;
357         dev_info(pTAS2555->dev, "%s, cmd=0x%x\n", __FUNCTION__, cmd);
358 //    if (_IOC_TYPE(cmd) != TILOAD_IOC_MAGIC)
359 //        return -ENOTTY;
361         pFileName = filp->f_path.dentry->d_name.name;
362         if(strcmp(pFileName, CHL_DEVICE_NAME) == 0)
363                 pTiLoad = pTAS2555->chl_private_data;
364         else if(strcmp(pFileName, CHR_DEVICE_NAME) == 0)
365                 pTiLoad = pTAS2555->chr_private_data;
366         else{
367                 dev_err(pTAS2555->dev, "channel err,dev (%s)\n", pFileName);
368                 return 0;               
369         }
370         
371         switch (cmd) {
372         case TILOAD_IOMAGICNUM_GET:
373                 magic_num = pTiLoad->mnMagicNum;
374                 num = copy_to_user(argp, &magic_num, sizeof(int));
375                 break;
376         case TILOAD_IOMAGICNUM_SET:
377                 num = copy_from_user(&magic_num, argp, sizeof(int));
378                 if(num==0) {
379                         pTiLoad->mnMagicNum = magic_num;
380                         tiload_route_IO(pTAS2555, magic_num);
381                 }
382                 break;
383         case TILOAD_BPR_READ:
384                 break;
385         case TILOAD_BPR_WRITE:
386                 num = copy_from_user(&bpr, argp, sizeof(BPR));
387                 dev_dbg(pTAS2555->dev, 
388                         "TILOAD_BPR_WRITE: 0x%02X, 0x%02X, 0x%02X\n\r", bpr.nBook,
389                         bpr.nPage, bpr.nRegister);
390                 break;
391         case TILOAD_IOCTL_SET_CONFIG:
392                 num = copy_from_user(&val, argp, sizeof(val));
393                 pTAS2555->set_config(pTAS2555, val);
394                 break;
395         case TILOAD_IOCTL_SET_CALIBRATION:
396                 num = copy_from_user(&val, argp, sizeof(val));
397                 pTAS2555->set_calibration(pTAS2555, val);
398                 break;                          
399         default:
400                 break;
401         }
402         return num;
405 /*********** File operations structure for tiload *************/
406 static struct file_operations tiload_fops = {
407         .owner = THIS_MODULE,
408         .open = tiload_open,
409         .release = tiload_release,
410         .read = tiload_read,
411         .write = tiload_write,
412         .unlocked_ioctl = tiload_ioctl,
413 };
415 /*
416  *----------------------------------------------------------------------------
417  * Function : tiload_driver_init
418  *
419  * Purpose  : Register a char driver for dynamic tiload programming
420  *----------------------------------------------------------------------------
421  */
422 int tiload_driver_init(struct tas2555_priv *pTAS2555, unsigned char channel)
424         int result;
425         int tiload_major = 0;
426         struct cdev *tiload_cdev;
427         struct class *tiload_class;
428         dev_t dev;
429         const char *pDeviceName;
430         struct tiload_data *private_data;
432         dev_info(pTAS2555->dev, "%s\n", __FUNCTION__);
433         
434         private_data = kzalloc(sizeof(struct tiload_data), GFP_KERNEL);
435         if(private_data == NULL){
436                 dev_err(pTAS2555->dev, "no mem\n");
437                 return -ENOMEM;
438         }
439                 
440         if(channel == channel_left){
441                 pDeviceName = CHL_DEVICE_NAME;
442                 if(pTAS2555->chl_private_data != NULL)
443                         kfree(pTAS2555->chl_private_data);
444                 pTAS2555->chl_private_data = private_data;
445         }else if(channel == channel_right){             
446                 pDeviceName = CHR_DEVICE_NAME;
447                 if(pTAS2555->chr_private_data != NULL)
448                         kfree(pTAS2555->chr_private_data);              
449                 pTAS2555->chr_private_data = private_data;
450         }else{
451                 result = -EINVAL;
452                 goto err;
453         }
454         
455         dev = MKDEV(tiload_major, 0);
456         g_TAS2555 = pTAS2555;
458         result = alloc_chrdev_region(&dev, 0, 1, pDeviceName);
459         if (result < 0) {
460                 dev_err(pTAS2555->dev,
461                         "cannot allocate major number %d\n", tiload_major);
462                 goto err;
463         }
464         tiload_class = class_create(THIS_MODULE, pDeviceName);
465         tiload_major = MAJOR(dev);
466         dev_info(pTAS2555->dev,
467                 "allocated Major Number: %d\n", tiload_major);
469         tiload_cdev = cdev_alloc();
470         cdev_init(tiload_cdev, &tiload_fops);
471         tiload_cdev->owner = THIS_MODULE;
472         tiload_cdev->ops = &tiload_fops;
474         if (device_create(tiload_class, NULL, dev, NULL, pDeviceName) == NULL){
475                 dev_err(pTAS2555->dev,
476                         "Device creation failed\n");
477         }
479         if (cdev_add(tiload_cdev, dev, 1) < 0) {
480                 dev_err(pTAS2555->dev,
481                                 "tiload_driver: cdev_add failed \n");
482                 unregister_chrdev_region(dev, 1);
483                 tiload_cdev = NULL;
484                 goto err;
485         }
486         
487         dev_info(pTAS2555->dev,
488                 "Registered TiLoad driver, Major number: %d \n", tiload_major);
489                 
490         return 0;
491         
492 err:
493         if(private_data!=NULL)
494                 kfree(private_data);
495         
496         return result;
499 MODULE_AUTHOR("Texas Instruments Inc.");
500 MODULE_DESCRIPTION("Utility for TAS2555 Android in-system tuning");
501 MODULE_LICENSE("GPLv2");
502 //#endif