kernel: sound: Adding TI codec support
[linux-2.6.git] / sound / soc / codecs / tlv320aic326x_minidsp_config.c
1 /*
2  * linux/sound/soc/codecs/tlv320aic326x_minidsp_config.c
3  *
4  * Copyright (C) 2011 Mistral Solutions Pvt Ltd.
5  *
6  * This package is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
11  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
12  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13  *
14  * The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio
15  * codec with digital microphone inputs and programmable outputs.
16  *
17  * History:
18  *
19  * Rev 0.1   Added the multiconfig support      Mistral         17-08-2011
20  *
21  * Rev 0.2   Migrated for aic3262 nVidia
22  *     Mistral         21-10-2011
23  */
24
25 /*
26  *****************************************************************************
27  * INCLUDES
28  *****************************************************************************
29  */
30 #include <linux/module.h>
31 #include <linux/moduleparam.h>
32 #include <linux/init.h>
33 #include <linux/kernel.h>
34 #include <linux/fs.h>
35 #include <linux/types.h>
36 #include <linux/kdev_t.h>
37 #include <linux/cdev.h>
38 #include <linux/device.h>
39 #include <linux/io.h>
40 #include <linux/delay.h>
41 #include <linux/i2c.h>
42 #include <linux/platform_device.h>
43 #include <sound/soc.h>
44 #include <sound/core.h>
45 #include <sound/soc-dapm.h>
46 #include <sound/control.h>
47 #include <linux/time.h>         /* For timing computations */
48 #include "tlv320aic326x.h"
49 #include "tlv320aic326x_mini-dsp.h"
50
51 #include "Patch_base_jazz_Rate48_pps_driver.h"
52 #include "Patch_base_main_Rate48_pps_driver.h"
53 #include "Patch_base_pop_Rate48_pps_driver.h"
54 #include "Patch_base_rock_Rate48_pps_driver.h"
55
56 #ifdef CONFIG_MINI_DSP
57
58 #define MAX_CONFIG_D_ARRAYS 4
59 #define MAX_CONFIG_A_ARRAYS 0
60 #define MAX_CONFIG_ARRAYS   4
61 #define MINIDSP_DMODE 0
62 #define MINIDSP_AMODE 1
63
64 /*
65  *****************************************************************************
66  * LOCAL STATIC DECLARATIONS
67  *****************************************************************************
68  */
69 static int multibyte_coeff_change(struct snd_soc_codec *codec, int);
70
71 static int m_control_get(struct snd_kcontrol *kcontrol,
72                         struct snd_ctl_elem_value *ucontrol);
73 static int m_control_put(struct snd_kcontrol *kcontrol,
74                         struct snd_ctl_elem_value *ucontrol);
75
76 /* k-control macros used for miniDSP related Kcontrols */
77 #define SOC_SINGLE_VALUE_M(xmax, xinvert) \
78         ((unsigned long)&(struct soc_mixer_control) \
79         {.max = xmax, \
80         .invert = xinvert})
81 #define SOC_SINGLE_M(xname, max, invert) \
82 {\
83         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
84         .info = m_control_info, .get = m_control_get,\
85         .put = m_control_put, \
86         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
87         .private_value = SOC_SINGLE_VALUE_M(max, invert) }
88 #define SOC_SINGLE_AIC3262_M(xname) \
89 {\
90         .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
91         .info = m_control_info, .get = m_control_get,\
92         .put = m_control_put, \
93         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
94 }
95
96
97 /* The Multi-Configurations generated through PPS GDE has been
98  * named as Rock, Pop, Jazz and Main. These were the Configurations
99  * that were used while testing this AUdio Driver. If the user
100  * creates Process-flow with different names, it is advised to
101  * modify the names present in the below array.
102  */
103 static const char *multi_config_support_DAC[] = {
104         "ROCK",
105         "POP",
106         "JAZZ",
107         "MAIN",
108 };
109
110 /* SOC_ENUM Declaration and kControl for switching Configurations
111  * at run-time.
112  */
113 static const struct soc_enum aic3262_enum =
114         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(multi_config_support_DAC),
115                         multi_config_support_DAC);
116
117 static const struct snd_kcontrol_new aic3262_minidsp_controls1[] = {
118
119         SOC_ENUM_EXT("Multiconfig support for DAC",
120                 aic3262_enum, m_control_get, m_control_put),
121
122 };
123
124
125 /*
126  * multibyte_config
127  *
128  * This structure has been devised to maintain information about each
129  * configuration provided with the PPS GDE Processflow. For each
130  * configuration, the Driver needs to know where the starting offset
131  * of the Coefficient change, Total Size of Coefficients being affected,
132  * and the Instruction Sizes.
133  * This has to be replicated for both miniDSP_A and miniDSP_D
134  */
135 struct multibyte_config {
136         reg_value *regs;
137         unsigned int d_coeff_start;
138         unsigned int d_coeff_size;
139         unsigned int d_inst_start;
140         unsigned int d_inst_size;
141         unsigned int a_coeff_start;
142         unsigned int a_coeff_size;
143         unsigned int a_inst_start;
144         unsigned int a_inst_size;
145 } config_array[][2][MAX_CONFIG_ARRAYS] = {
146         /* Process flow 1 */
147         {
148                 {
149                         /* DAC */
150                         {rock_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
151                         {pop_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
152                         {jazz_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
153                         {main_D_reg_values, 0, 67, 67, 0, 0, 0, 0, 0},
154                 },
155                 /* ADC */
156                 {},
157         },
158
159         /* Process flow 2 */
160         {
161 #if 0
162                 {
163                         {main, 0, 0, 0, 0, 0, 0, 0, 0},
164                         {pop, 0, 0, 0, 0, 0, 0, 0, 0},
165                         {jazz, 0, 0, 0, 0, 0, 0, 0, 0},
166                         {rock, 0, 0, 0, 0, 0, 0, 0, 0},
167                 },
168                 /* ADC */
169                 {},
170 #endif
171         },
172 };
173
174 /*
175  *----------------------------------------------------------------------------
176  * Function : m_control_get
177  * Purpose  : This function is to read data of new control for
178  *            program the AIC3262 registers.
179  *
180  *----------------------------------------------------------------------------
181  */
182 static int m_control_get(struct snd_kcontrol *kcontrol,
183                          struct snd_ctl_elem_value *ucontrol)
184 {
185
186         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
187         struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
188         u32 val = 0;
189         u32 mode = aic326x->process_flow;
190
191
192         if (!strcmp(kcontrol->id.name, "Multiconfig support for DAC"))
193                 val = aic326x->current_dac_config[mode];
194         else if (!strcmp(kcontrol->id.name, "Multiconfig support for ADC"))
195                 val = aic326x->current_adc_config[mode];
196
197
198         ucontrol->value.integer.value[0] = val;
199         return 0;
200 }
201
202 /*
203  *----------------------------------------------------------------------------
204  * Function : m_new_control_put
205  * Purpose  : new_control_put is called to pass data from user/application to
206  *            the driver.
207  *
208  *----------------------------------------------------------------------------
209  */
210 static int m_control_put(struct snd_kcontrol *kcontrol,
211                          struct snd_ctl_elem_value *ucontrol)
212 {
213         struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
214         struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
215         u32 val;
216         u8 value;
217         int pf = aic326x->process_flow;
218         struct multibyte_config *array;
219
220         val = ucontrol->value.integer.value[0];
221         if (!strcmp(kcontrol->id.name, "Multiconfig support for DAC")) {
222                 if (aic326x->process_flow == MINIDSP_DMODE) {
223                         if (val > MAX_CONFIG_D_ARRAYS) {
224                                 dev_err(codec->dev, "Value not in range\n");
225                                 return -1;
226                         }
227
228                         value = aic3262_read(codec, ADC_CHANNEL_POW);
229                         value = aic3262_read(codec, PASI_DAC_DP_SETUP);
230
231                         array = &config_array[pf][MINIDSP_DMODE][val];
232                         minidsp_i2c_multibyte_transfer(codec,
233                                 array->regs,
234                                 (array->d_inst_size + array->d_coeff_size));
235
236
237                         /*coefficent buffer change*/
238                         multibyte_coeff_change(codec, 0x50);
239
240                         minidsp_i2c_multibyte_transfer(codec,
241                                 array->regs,
242                                 (array->d_inst_size + array->d_coeff_size));
243
244
245
246                         value = aic3262_read(codec, ADC_CHANNEL_POW);
247                         value = aic3262_read(codec, PASI_DAC_DP_SETUP);
248                 }
249                 aic326x->current_dac_config[pf] = val;
250
251         } else {
252                 if (aic326x->process_flow == MINIDSP_AMODE) {
253                         if (val > MAX_CONFIG_A_ARRAYS) {
254                                 dev_err(codec->dev, "Value not in range\n");
255                                 return -1;
256                         }
257                         array = &config_array[pf][MINIDSP_AMODE][val];
258                         minidsp_i2c_multibyte_transfer(codec,
259                                 array->regs,
260                                 (array->a_inst_size + array->a_coeff_size));
261                 }
262                 aic326x->current_adc_config[pf] = val;
263         }
264         return val;
265 }
266
267
268 /*
269  *--------------------------------------------------------------------------
270  * Function : aic3262_add_multiconfig_controls
271  * Purpose :  Configures the AMIXER Control Interfaces that can be exercised by
272  *            the user at run-time. Utilizes the  the snd_adaptive_controls[]
273  *            array to specify two run-time controls.
274  *---------------------------------------------------------------------------
275  */
276 int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec)
277 {
278         int i, err;
279
280         DBG(KERN_INFO
281                 "#%s: Invoked to add controls for Multi-Configuration\n",
282                 __func__);
283
284         /* add mode k control */
285         for (i = 0; i < ARRAY_SIZE(aic3262_minidsp_controls1); i++) {
286                 err = snd_ctl_add(codec->card->snd_card,
287                                 snd_ctl_new1(&aic3262_minidsp_controls1[i],
288                                 codec));
289                 if (err < 0) {
290                         printk(KERN_ERR
291                         "Cannot add controls for mulibyte configuration\n");
292                         return err;
293                 }
294         }
295         DBG(KERN_INFO "#%s: Completed control addition.\n", __func__);
296         return 0;
297 }
298
299 /*
300  *--------------------------------------------------------------------------
301  * Function : config_multibyte_for_mode
302  * Purpose :  Function which is invoked when user changes the configuration
303  *            at run-time. Internally configures/switches both
304  *            miniDSP_D and miniDSP_A Coefficient arrays.
305  *---------------------------------------------------------------------------
306  */
307 void config_multibyte_for_mode(struct snd_soc_codec *codec, int mode)
308 {
309         int val;
310         int pf = mode;
311         struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec);
312         struct multibyte_config *array;
313
314         DBG(KERN_INFO "#%s: Invoked for miniDSP Mode %d\n", __func__, mode);
315
316         array = config_array[pf][MINIDSP_DMODE];
317           if ((aic326x->current_dac_config[pf] >= 0) &&
318                 (aic326x->current_dac_config[pf] < MAX_CONFIG_ARRAYS)) {
319                         val = aic326x->current_dac_config[pf];
320                         array = &config_array[pf][MINIDSP_DMODE][val];
321                         byte_i2c_array_transfer(codec,
322                                 array->regs,
323                                 (array->d_inst_size +
324                                 array->d_coeff_size));
325         } else {
326                 DBG(KERN_INFO "#%s: Invalid Configuration ID %d specified.\n",
327                         __func__, aic326x->current_dac_config[pf]);
328         }
329
330         array = config_array[pf][MINIDSP_AMODE];
331         if ((aic326x->current_adc_config[pf] >= 0) &&
332                 (aic326x->current_adc_config[pf] < MAX_CONFIG_ARRAYS)) {
333                 val = aic326x->current_adc_config[pf];
334                 minidsp_i2c_multibyte_transfer(codec,
335                                 array[val].regs,
336                                 array[val].a_inst_size +
337                                 array[val].a_coeff_size);
338         } else {
339                 DBG(KERN_INFO "#%s: Invalid Configuration ID %d specified.\n",
340                         __func__, aic326x->current_dac_config[pf]);
341         }
342         return;
343 }
344
345 /*
346  *--------------------------------------------------------------------------
347  * Function : config_multibyte_for_mode
348  * Purpose :  Function which is invoked when user changes the configuration
349  *            at run-time. Internally configures/switches both
350  *            miniDSP_D and miniDSP_A Coefficient arrays.
351  *---------------------------------------------------------------------------
352  */
353 static int multibyte_coeff_change(struct snd_soc_codec *codec, int bk)
354 {
355
356         u8 value[2], swap_reg_pre, swap_reg_post;
357         struct i2c_client *i2c;
358         i2c = codec->control_data;
359
360         aic3262_change_book(codec, bk);
361
362         value[0] = 1;
363
364         if (i2c_master_send(i2c, value, 1) != 1)
365                 printk(KERN_ERR "Can not write register address\n");
366         else {
367                 /* Read the Value of the Page 8 Register 1 which controls the
368                    Adaptive Switching Mode */
369                 if (i2c_master_recv(i2c, value, 1) != 1) {
370                         printk(KERN_ERR "Can not read codec registers\n");
371                         goto err;
372                 }
373                 swap_reg_pre = value[0];
374
375                 /* Write the Register bit updates */
376                 value[1] = value[0] | 1;
377                 value[0] = 1;
378
379                 if (i2c_master_send(i2c, value, 2) != 2) {
380                         printk(KERN_ERR "Can not write register address\n");
381                         goto err;
382                 }
383                 value[0] = 1;
384                 /* verify buffer swap */
385                 if (i2c_master_send(i2c, value, 1) != 1)
386                         printk(KERN_ERR "Can not write register address\n");
387
388                 /* Read the Value of the Page 8 Register 1 which controls the
389                    Adaptive Switching Mode */
390                 if (i2c_master_recv(i2c, &swap_reg_post, 1) != 1)
391                         printk(KERN_ERR "Can not read codec registers\n");
392
393                 if ((swap_reg_pre == 4 && swap_reg_post == 6)
394                         || (swap_reg_pre == 6 && swap_reg_post == 4))
395                         DBG(KERN_INFO "Buffer swap success\n");
396                 else
397                         printk(KERN_ERR
398                         "Buffer swap...FAILED\nswap_reg_pre=%x, swap_reg_post=%x\n",
399                         swap_reg_pre, swap_reg_post);
400         }
401
402 err:
403         return 0;
404 }
405
406 #endif
407
408 MODULE_DESCRIPTION("ASoC AIC3262 miniDSP multi-configuration");
409 MODULE_AUTHOR("Barani Prashanth <gvbarani@mistralsolutions.com>");
410 MODULE_LICENSE("GPL");