aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/aic326x_tiload.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/aic326x_tiload.c')
-rw-r--r--sound/soc/codecs/aic326x_tiload.c312
1 files changed, 312 insertions, 0 deletions
diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c
new file mode 100644
index 00000000000..00aa4d4ce7d
--- /dev/null
+++ b/sound/soc/codecs/aic326x_tiload.c
@@ -0,0 +1,312 @@
1/*
2 * linux/sound/soc/codecs/AIC3262_tiload.c
3 *
4 *
5 * Copyright (C) 2010 Texas Instruments, Inc.
6 *
7 *
8 *
9 * This package is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * History:
18 *
19 * Rev 0.1 Tiload support 16-09-2010
20 *
21 * The Tiload programming support is added to AIC3262.
22 *
23 */
24
25#include <linux/module.h>
26#include <linux/moduleparam.h>
27#include <linux/init.h>
28#include <linux/kernel.h>
29#include <linux/fs.h>
30#include <linux/types.h>
31#include <linux/kdev_t.h>
32#include <linux/cdev.h>
33#include <linux/device.h>
34#include <asm/io.h>
35#include <linux/delay.h>
36#include <linux/i2c.h>
37#include <linux/platform_device.h>
38#include <sound/soc.h>
39#include <sound/control.h>
40
41#include "tlv320aic326x.h"
42#include "aic326x_tiload.h"
43
44/* enable debug prints in the driver */
45#define DEBUG
46//#undef DEBUG
47
48#ifdef DEBUG
49#define dprintk(x...) printk(x)
50#else
51#define dprintk(x...)
52#endif
53
54#ifdef AIC3262_TiLoad
55
56/* Function prototypes */
57#ifdef REG_DUMP_aic3262
58static void aic3262_dump_page(struct i2c_client *i2c, u8 page);
59#endif
60
61/* externs */
62extern int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page);
63extern int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book);
64extern int aic3262_write(struct snd_soc_codec *codec, u16 reg, u8 value);
65int aic3262_driver_init(struct snd_soc_codec *codec);
66/************** Dynamic aic3262 driver, TI LOAD support ***************/
67
68static struct cdev *aic3262_cdev;
69static int aic3262_major = 0; /* Dynamic allocation of Mjr No. */
70static int aic3262_opened = 0; /* Dynamic allocation of Mjr No. */
71static struct snd_soc_codec *aic3262_codec;
72struct class *tiload_class;
73static unsigned int magic_num = 0xE0;
74
75/******************************** Debug section *****************************/
76
77#ifdef REG_DUMP_aic3262
78/*
79 *----------------------------------------------------------------------------
80 * Function : aic3262_dump_page
81 * Purpose : Read and display one codec register page, for debugging purpose
82 *----------------------------------------------------------------------------
83 */
84static void aic3262_dump_page(struct i2c_client *i2c, u8 page)
85{
86 int i;
87 u8 data;
88 u8 test_page_array[8];
89
90 dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
91 aic3262_change_page(codec, page);
92
93 data = 0x0;
94
95 i2c_master_send(i2c, data, 1);
96 i2c_master_recv(i2c, test_page_array, 8);
97
98 printk("\n------- aic3262 PAGE %d DUMP --------\n", page);
99 for (i = 0; i < 8; i++) {
100 printk(" [ %d ] = 0x%x\n", i, test_page_array[i]);
101 }
102}
103#endif
104
105/*
106 *----------------------------------------------------------------------------
107 * Function : tiload_open
108 *
109 * Purpose : open method for aic3262-tiload programming interface
110 *----------------------------------------------------------------------------
111 */
112static int tiload_open(struct inode *in, struct file *filp)
113{
114 dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
115 if (aic3262_opened) {
116 printk("%s device is already opened\n", "aic3262");
117 printk("%s: only one instance of driver is allowed\n",
118 "aic3262");
119 return -1;
120 }
121 aic3262_opened++;
122 return 0;
123}
124
125/*
126 *----------------------------------------------------------------------------
127 * Function : tiload_release
128 *
129 * Purpose : close method for aic3262_tilaod programming interface
130 *----------------------------------------------------------------------------
131 */
132static int tiload_release(struct inode *in, struct file *filp)
133{
134 dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
135 aic3262_opened--;
136 return 0;
137}
138
139/*
140 *----------------------------------------------------------------------------
141 * Function : tiload_read
142 *
143 * Purpose : read method for mini dsp programming interface
144 *----------------------------------------------------------------------------
145 */
146static ssize_t tiload_read(struct file *file, char __user * buf,
147 size_t count, loff_t * offset)
148{
149 static char rd_data[8];
150 char reg_addr;
151 size_t size;
152 #ifdef DEBUG
153 int i;
154 #endif
155 struct i2c_client *i2c = aic3262_codec->control_data;
156
157 dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
158 if (count > 128) {
159 printk("Max 128 bytes can be read\n");
160 count = 128;
161 }
162
163 /* copy register address from user space */
164 size = copy_from_user(&reg_addr, buf, 1);
165 if (size != 0) {
166 printk("read: copy_from_user failure\n");
167 return -1;
168 }
169 /* Send the address to device thats is to be read */
170
171 if (i2c_master_send(i2c, &reg_addr, 1) != 1) {
172 dprintk("Can not write register address\n");
173 return -1;
174 }
175 /* read the codec device registers */
176 size = i2c_master_recv(i2c, rd_data, count);
177#ifdef DEBUG
178 printk(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n",
179 (int)size, reg_addr, (int)count);
180 for (i = 0; i < (int)size; i++) {
181 printk(KERN_ERR "rd_data[%d]=%x\n", i, rd_data[i]);
182 }
183#endif
184 if (size != count) {
185 printk("read %d registers from the codec\n", size);
186 }
187
188 if (copy_to_user(buf, rd_data, size) != 0) {
189 dprintk("copy_to_user failed\n");
190 return -1;
191 }
192
193 return size;
194}
195
196/*
197 *----------------------------------------------------------------------------
198 * Function : tiload_write
199 *
200 * Purpose : write method for aic3262_tiload programming interface
201 *----------------------------------------------------------------------------
202 */
203static ssize_t tiload_write(struct file *file, const char __user * buf,
204 size_t count, loff_t * offset)
205{
206 static char wr_data[8];
207 u8 pg_no;
208 #ifdef DEBUG
209 int i;
210 #endif
211 struct i2c_client *i2c = aic3262_codec->control_data;
212 struct aic3262_priv *aic3262_private = snd_soc_codec_get_drvdata(aic3262_codec);
213
214 dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
215 /* copy buffer from user space */
216 if (copy_from_user(wr_data, buf, count)) {
217 printk("copy_from_user failure\n");
218 return -1;
219 }
220#ifdef DEBUG
221 printk(KERN_ERR "write size = %d\n", (int)count);
222 for (i = 0; i < (int)count; i++) {
223 printk(KERN_INFO "\nwr_data[%d]=%x\n", i, wr_data[i]);
224 }
225#endif
226 if (wr_data[0] == 0) {
227 aic3262_change_page(aic3262_codec, wr_data[1]);
228 return count;
229 }
230 pg_no = aic3262_private->page_no;
231
232 if ((wr_data[0] == 127) && (pg_no == 0)) {
233 aic3262_change_book(aic3262_codec, wr_data[1]);
234 return count;
235 }
236 return i2c_master_send(i2c, wr_data, count);
237}
238
239static int tiload_ioctl( struct file *filp,
240 unsigned int cmd, unsigned long arg)
241{
242 int num = 0;
243 void __user *argp = (void __user *)arg;
244 if (_IOC_TYPE(cmd) != aic3262_IOC_MAGIC)
245 return -ENOTTY;
246
247 dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
248 switch (cmd) {
249 case aic3262_IOMAGICNUM_GET:
250 num = copy_to_user(argp, &magic_num, sizeof(int));
251 break;
252 case aic3262_IOMAGICNUM_SET:
253 num = copy_from_user(&magic_num, argp, sizeof(int));
254 break;
255 }
256 return num;
257}
258
259/*********** File operations structure for aic3262-tiload programming *************/
260static struct file_operations aic3262_fops = {
261 .owner = THIS_MODULE,
262 .open = tiload_open,
263 .release = tiload_release,
264 .read = tiload_read,
265 .write = tiload_write,
266 .unlocked_ioctl = tiload_ioctl,
267};
268
269/*
270 *----------------------------------------------------------------------------
271 * Function : aic3262_driver_init
272 *
273 * Purpose : Register a char driver for dynamic aic3262-tiload programming
274 *----------------------------------------------------------------------------
275 */
276int aic3262_driver_init(struct snd_soc_codec *codec)
277{
278 int result;
279
280 dev_t dev = MKDEV(aic3262_major, 0);
281 printk("TiLoad DRIVER : %s\n", __FUNCTION__);
282 aic3262_codec = codec;
283
284 printk("allocating dynamic major number\n");
285
286 result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
287 if (result < 0) {
288 printk("cannot allocate major number %d\n", aic3262_major);
289 return result;
290 }
291 tiload_class = class_create(THIS_MODULE, DEVICE_NAME);
292 aic3262_major = MAJOR(dev);
293 printk("allocated Major Number: %d\n", aic3262_major);
294
295 aic3262_cdev = cdev_alloc();
296 cdev_init(aic3262_cdev, &aic3262_fops);
297 aic3262_cdev->owner = THIS_MODULE;
298 aic3262_cdev->ops = &aic3262_fops;
299
300 if (cdev_add(aic3262_cdev, dev, 1) < 0) {
301 dprintk("aic3262_driver: cdev_add failed \n");
302 unregister_chrdev_region(dev, 1);
303 aic3262_cdev = NULL;
304 return 1;
305 }
306 printk("Registered aic3262 TiLoad driver, Major number: %d \n",
307 aic3262_major);
308 //class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0);
309 return 0;
310}
311
312#endif