e8a077a21be8cd18d221e7b81786e96660f86faf
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 */
106 }
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)
117 {
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;
126 }
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)
136 {
137 dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
138 tiload_opened--;
139 return 0;
140 }
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)
152 {
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(®_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;
211 }
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)
222 {
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;
291 }
293 static void tiload_route_IO(unsigned int bLock)
294 {
295 if (bLock) {
296 g_TAS2555->write(g_TAS2555, 0xAFFEAFFE, 0xBABEBABE);
297 } else {
298 g_TAS2555->write(g_TAS2555, 0xBABEBABE, 0xAFFEAFFE);
299 }
300 }
302 static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
303 {
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;
342 }
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)
362 {
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;
397 }
399 MODULE_AUTHOR("Texas Instruments Inc.");
400 MODULE_DESCRIPTION("Utility for TAS2555 Android in-system tuning");
401 MODULE_LICENSE("GPLv2");
402 //#endif