Change Magic Number for kernel 4.19 support
[tas2557sw-android/tas2557-android-driver.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 ** File:
14 **     tiload.c
15 **
16 ** Description:
17 **     utility for TAS2557 Android in-system tuning
18 **
19 ** =============================================================================
20 */
23 #include <linux/module.h>
24 #include <linux/moduleparam.h>
25 #include <linux/init.h>
26 #include <linux/kernel.h>
27 #include <linux/fs.h>
28 #include <linux/types.h>
29 #include <linux/kdev_t.h>
30 #include <linux/cdev.h>
31 #include <linux/device.h>
32 #include <linux/io.h>
33 #include <linux/delay.h>
34 #include <linux/i2c.h>
35 #include <linux/platform_device.h>
36 #include <linux/uaccess.h>
38 #include "tiload.h"
40 /* enable debug prints in the driver */
41 #define DEBUG
43 static struct cdev *tiload_cdev;
44 static int tiload_major; /* Dynamic allocation of Mjr No. */
45 static int tiload_opened; /* Dynamic allocation of Mjr No. */
46 static struct tas2557_priv *g_TAS2557;
47 struct class *tiload_class;
48 static unsigned int magic_num;
50 static char gPage;
51 static char gBook;
52 /******************************** Debug section *****************************/
55 /*----------------------------------------------------------------------------
56  * Function : tiload_open
57  *
58  * Purpose  : open method for tiload programming interface
59  *----------------------------------------------------------------------------
60  */
61 static int tiload_open(struct inode *in, struct file *filp)
62 {
63         struct tas2557_priv *pTAS2557 = g_TAS2557;
65         dev_info(pTAS2557->dev, "%s\n", __func__);
67         if (tiload_opened) {
68                 dev_info(pTAS2557->dev, "%s device is already opened\n", "tiload");
69                 return -EINVAL;
70         }
71         filp->private_data = (void *)pTAS2557;
72         tiload_opened++;
73         return 0;
74 }
76 /*----------------------------------------------------------------------------
77  * Function : tiload_release
78  *
79  * Purpose  : close method for tiload programming interface
80  *----------------------------------------------------------------------------
81  */
82 static int tiload_release(struct inode *in, struct file *filp)
83 {
84         struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
86         dev_info(pTAS2557->dev, "%s\n", __func__);
87         filp->private_data = NULL;
88         tiload_opened--;
89         return 0;
90 }
92 #define MAX_LENGTH 128
93 /*----------------------------------------------------------------------------
94  * Function : tiload_read
95  *
96  * Purpose  : read from codec
97  *----------------------------------------------------------------------------
98  */
99 static ssize_t tiload_read(struct file *filp, char __user *buf,
100         size_t count, loff_t *offset)
102         struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
103         static char rd_data[MAX_LENGTH + 1];
104         unsigned int nCompositeRegister = 0, Value = 0;
105         char reg_addr;
106         size_t size;
107         int ret = 0;
108 #ifdef DEBUG
109         /* int i; */
110 #endif
112         dev_info(pTAS2557->dev, "%s\n", __func__);
113         if (count > MAX_LENGTH) {
114                 dev_err(pTAS2557->dev, "Max %d bytes can be read\n", MAX_LENGTH);
115                 return -EINVAL;
116         }
118         /* copy register address from user space  */
119         size = copy_from_user(&reg_addr, buf, 1);
120         if (size != 0) {
121                 dev_err(pTAS2557->dev, "read: copy_from_user failure\n");
122                 return -EINVAL;
123         }
125         size = count;
127         nCompositeRegister = BPR_REG(gBook, gPage, reg_addr);
128         if (count == 1) {
129                 ret =
130                         pTAS2557->read(pTAS2557, 0x80000000 | nCompositeRegister, &Value);
131                 if (ret >= 0)
132                         rd_data[0] = (char) Value;
133         } else if (count > 1) {
134                 ret =
135                         pTAS2557->bulk_read(pTAS2557, 0x80000000 | nCompositeRegister,
136                         rd_data, size);
137         }
138         if (ret < 0)
139                 dev_err(pTAS2557->dev, "%s, %d, ret=%d, count=%zu error happen!\n",
140                         __func__, __LINE__, ret, count);
142 #ifdef DEBUG
143         dev_info(pTAS2557->dev, "read size = %d, reg_addr= %x , count = %d\n",
144                 (int) size, reg_addr, (int) count);
145 /*      for (i = 0; i < (int) size; i++) {
146 *               dev_dbg(pTAS2557->dev, "rd_data[%d]=%x\n", i, rd_data[i]);
147 *       }
148 */
149 #endif
150         if (size != count)
151                 dev_err(pTAS2557->dev, "read %d registers from the codec\n", (int) size);
153         if (copy_to_user(buf, rd_data, size) != 0) {
154                 dev_err(pTAS2557->dev, "copy_to_user failed\n");
155                 return -EINVAL;
156         }
158         return size;
161 /*
162  *----------------------------------------------------------------------------
163  * Function : tiload_write
164  *
165  * Purpose  : write to codec
166  *----------------------------------------------------------------------------
167  */
168 static ssize_t tiload_write(struct file *filp, const char __user *buf,
169         size_t count, loff_t *offset)
171         struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
172         static char wr_data[MAX_LENGTH + 1];
173         char *pData = wr_data;
174         size_t size;
175         unsigned int nCompositeRegister = 0;
176         unsigned int nRegister;
177         int ret = 0;
178 #ifdef DEBUG
179         /* int i; */
180 #endif
181         dev_info(pTAS2557->dev, "%s\n", __func__);
183         if (count > MAX_LENGTH) {
184                 dev_err(pTAS2557->dev, "Max %d bytes can be read\n", MAX_LENGTH);
185                 return -EINVAL;
186         }
188         /* copy buffer from user space  */
189         size = copy_from_user(wr_data, buf, count);
190         if (size != 0) {
191                 dev_err(pTAS2557->dev, "copy_from_user failure %d\n", (int) size);
192                 return -EINVAL;
193         }
194 #ifdef DEBUG
195         dev_info(pTAS2557->dev, "write size = %zu\n", count);
196 /* for (i = 0; i < (int) count; i++) {
197 *               dev_info(pTAS2557->dev, "wr_data[%d]=%x\n", i, wr_data[i]);
198 *       }
199 */
200 #endif
201         nRegister = wr_data[0];
202         size = count;
203         if ((nRegister == 127) && (gPage == 0)) {
204                 gBook = wr_data[1];
205                 return size;
206         }
208         if (nRegister == 0) {
209                 gPage = wr_data[1];
210                 pData++;
211                 count--;
212         }
214         nCompositeRegister = BPR_REG(gBook, gPage, nRegister);
215         if (count == 2) {
216                 ret =
217                         pTAS2557->write(pTAS2557, 0x80000000 | nCompositeRegister,
218                         pData[1]);
219         } else if (count > 2) {
220                 ret =
221                         pTAS2557->bulk_write(pTAS2557, 0x80000000 | nCompositeRegister,
222                         &pData[1], count - 1);
223         }
225         if (ret < 0)
226                 dev_err(pTAS2557->dev, "%s, %d, ret=%d, count=%zu, ERROR Happen\n", __func__,
227                         __LINE__, ret, count);
229         return size;
232 static void tiload_route_IO(struct tas2557_priv *pTAS2557, unsigned int bLock)
234         if (bLock)
235                 pTAS2557->write(pTAS2557, 0xAFFEAFFE, 0xBABEBABE);
236         else
237                 pTAS2557->write(pTAS2557, 0xBABEBABE, 0xAFFEAFFE);
240 static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
242         struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
243         long num = 0;
244         void __user *argp = (void __user *) arg;
245         int val;
246         struct BPR bpr;
248         dev_info(pTAS2557->dev, "%s, cmd=0x%x\n", __func__, cmd);
249 /*  if (_IOC_TYPE(cmd) != TILOAD_IOC_MAGIC)
250  *      return -ENOTTY;
251  */
253         switch (cmd) {
254         case TILOAD_IOMAGICNUM_GET:
255                 num = copy_to_user(argp, &magic_num, sizeof(int));
256                 break;
257         case TILOAD_IOMAGICNUM_SET:
258                 num = copy_from_user(&magic_num, argp, sizeof(int));
259                 dev_info(pTAS2557->dev, "TILOAD_IOMAGICNUM_SET\n");
260                 tiload_route_IO(pTAS2557, magic_num);
261                 break;
262         case TILOAD_BPR_READ:
263                 break;
264         case TILOAD_BPR_WRITE:
265                 num = copy_from_user(&bpr, argp, sizeof(struct BPR));
266                 dev_info(pTAS2557->dev, "TILOAD_BPR_WRITE: 0x%02X, 0x%02X, 0x%02X\n\r", bpr.nBook,
267                         bpr.nPage, bpr.nRegister);
268                 break;
269         case TILOAD_IOCTL_SET_CHL:
270                 break;
271         case TILOAD_IOCTL_SET_CONFIG:
272                 num = copy_from_user(&val, argp, sizeof(val));
273                 pTAS2557->set_config(pTAS2557, val);
274                 break;
275         case TILOAD_IOCTL_SET_CALIBRATION:
276                 num = copy_from_user(&val, argp, sizeof(val));
277                 pTAS2557->set_calibration(pTAS2557, val);
278                 break;
279         default:
280                 break;
281         }
282         return num;
285 #ifdef CONFIG_COMPAT
286 static long tiload_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
288         struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data;
289         long nResult = 0;
291         switch (cmd) {
292         case TILOAD_COMPAT_IOMAGICNUM_GET:
293                 dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOMAGICNUM_GET=0x%x\n",
294                         __func__, cmd);
295                 nResult = tiload_ioctl(filp, TILOAD_IOMAGICNUM_GET,
296                         (unsigned long) compat_ptr(arg));
297                 break;
299         case TILOAD_COMPAT_IOMAGICNUM_SET:
300                 dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOMAGICNUM_SET=0x%x\n",
301                         __func__, cmd);
302                 nResult = tiload_ioctl(filp, TILOAD_IOMAGICNUM_SET,
303                         (unsigned long) compat_ptr(arg));
304                 break;
306         case TILOAD_COMPAT_BPR_READ:
307                 dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_BPR_READ=0x%x\n",
308                         __func__, cmd);
309                 nResult = tiload_ioctl(filp, TILOAD_BPR_READ,
310                         (unsigned long) compat_ptr(arg));
311                 break;
313         case TILOAD_COMPAT_BPR_WRITE:
314                 dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_BPR_WRITE=0x%x\n",
315                         __func__, cmd);
316                 nResult = tiload_ioctl(filp, TILOAD_BPR_WRITE,
317                         (unsigned long) compat_ptr(arg));
318                 break;
320         case TILOAD_COMPAT_IOCTL_SET_CHL:
321                 dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOCTL_SET_CHL=0x%x\n",
322                         __func__, cmd);
323                 nResult = tiload_ioctl(filp, TILOAD_IOCTL_SET_CHL,
324                         (unsigned long) compat_ptr(arg));
325                 break;
327         case TILOAD_COMPAT_IOCTL_SET_CONFIG:
328                 dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOCTL_SET_CONFIG=0x%x\n",
329                         __func__, cmd);
330                 nResult = tiload_ioctl(filp, TILOAD_IOCTL_SET_CONFIG,
331                         (unsigned long) compat_ptr(arg));
332                 break;
334         case TILOAD_COMPAT_IOCTL_SET_CALIBRATION:
335                 dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOCTL_SET_CALIBRATION=0x%x\n",
336                         __func__, cmd);
337                 nResult = tiload_ioctl(filp, TILOAD_IOCTL_SET_CALIBRATION,
338                         (unsigned long) compat_ptr(arg));
339                 break;
341         default:
342                 dev_err(pTAS2557->dev, "%s, unsupport compat ioctl=0x%x\n",
343                         __func__, cmd);
344                 break;
345         }
347         return nResult;
349 #endif
351 /*********** File operations structure for tiload *************/
352 static const struct file_operations tiload_fops = {
353         .owner = THIS_MODULE,
354         .open = tiload_open,
355         .release = tiload_release,
356         .read = tiload_read,
357         .write = tiload_write,
358         .unlocked_ioctl = tiload_ioctl,
359 #ifdef CONFIG_COMPAT
360         .compat_ioctl = tiload_compat_ioctl,
361 #endif
362 };
364 /*----------------------------------------------------------------------------
365  * Function : tiload_driver_init
366  *
367  * Purpose  : Register a char driver for dynamic tiload programming
368  *----------------------------------------------------------------------------
369  */
370 int tiload_driver_init(struct tas2557_priv *pTAS2557)
372         int result;
373         dev_t dev = MKDEV(tiload_major, 0);
375         g_TAS2557 = pTAS2557;
377         dev_info(pTAS2557->dev, "%s\n", __func__);
379         result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
380         if (result < 0) {
381                 dev_err(pTAS2557->dev, "cannot allocate major number %d\n", tiload_major);
382                 return result;
383         }
384         tiload_class = class_create(THIS_MODULE, DEVICE_NAME);
385         tiload_major = MAJOR(dev);
386         dev_info(pTAS2557->dev, "allocated Major Number: %d\n", tiload_major);
388         tiload_cdev = cdev_alloc();
389         cdev_init(tiload_cdev, &tiload_fops);
390         tiload_cdev->owner = THIS_MODULE;
391         tiload_cdev->ops = &tiload_fops;
393         if (device_create(tiload_class, NULL, dev, NULL, "tiload_node") == NULL)
394                 dev_err(pTAS2557->dev, "Device creation failed\n");
396         if (cdev_add(tiload_cdev, dev, 1) < 0) {
397                 dev_err(pTAS2557->dev, "tiload_driver: cdev_add failed\n");
398                 unregister_chrdev_region(dev, 1);
399                 tiload_cdev = NULL;
400                 return 1;
401         }
402         dev_info(pTAS2557->dev, "Registered TiLoad driver, Major number: %d\n", tiload_major);
403         /* class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0); */
404         return 0;
407 MODULE_AUTHOR("Texas Instruments Inc.");
408 MODULE_DESCRIPTION("Utility for TAS2557 Android in-system tuning");
409 MODULE_LICENSE("GPL v2");