diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic326x_mini-dsp.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic326x_mini-dsp.c | 1796 |
1 files changed, 1796 insertions, 0 deletions
diff --git a/sound/soc/codecs/tlv320aic326x_mini-dsp.c b/sound/soc/codecs/tlv320aic326x_mini-dsp.c new file mode 100644 index 00000000000..6d55abb4dac --- /dev/null +++ b/sound/soc/codecs/tlv320aic326x_mini-dsp.c | |||
@@ -0,0 +1,1796 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/codecs/tlv320aic326x_mini-dsp.c | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments, Inc. | ||
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 miniDSP Support 01-03-2011 | ||
20 | * | ||
21 | * Rev 0.2 Updated the code-base for miniDSP switching and | ||
22 | * mux control update. 21-03-2011 | ||
23 | * | ||
24 | * Rev 0.3 Updated the code-base to support Multi-Configuration feature | ||
25 | * of PPS GDE | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | ***************************************************************************** | ||
30 | * INCLUDES | ||
31 | ***************************************************************************** | ||
32 | */ | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/moduleparam.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/fs.h> | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/kdev_t.h> | ||
40 | #include <linux/cdev.h> | ||
41 | #include <linux/device.h> | ||
42 | #include <linux/io.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/i2c.h> | ||
45 | #include <linux/platform_device.h> | ||
46 | #include <sound/soc.h> | ||
47 | #include <sound/core.h> | ||
48 | #include <sound/soc-dapm.h> | ||
49 | #include <sound/control.h> | ||
50 | #include <linux/time.h> /* For timing computations */ | ||
51 | #include "tlv320aic326x.h" | ||
52 | #include "tlv320aic326x_mini-dsp.h" | ||
53 | |||
54 | #include "base_main_Rate48_pps_driver.h" | ||
55 | #include "second_rate_pps_driver.h" | ||
56 | //#include "one_mic_aec_nc_latest.h" | ||
57 | #ifdef CONFIG_MINI_DSP | ||
58 | |||
59 | #ifdef REG_DUMP_MINIDSP | ||
60 | static void aic3262_dump_page(struct i2c_client *i2c, u8 page); | ||
61 | #endif | ||
62 | |||
63 | /* | ||
64 | ***************************************************************************** | ||
65 | * LOCAL STATIC DECLARATIONS | ||
66 | ***************************************************************************** | ||
67 | */ | ||
68 | static int m_control_info(struct snd_kcontrol *kcontrol, | ||
69 | struct snd_ctl_elem_info *uinfo); | ||
70 | static int m_control_get(struct snd_kcontrol *kcontrol, | ||
71 | struct snd_ctl_elem_value *ucontrol); | ||
72 | static int m_control_put(struct snd_kcontrol *kcontrol, | ||
73 | struct snd_ctl_elem_value *ucontrol); | ||
74 | |||
75 | /* | ||
76 | ***************************************************************************** | ||
77 | * MINIDSP RELATED GLOBALS | ||
78 | ***************************************************************************** | ||
79 | */ | ||
80 | /* The below variable is used to maintain the I2C Transactions | ||
81 | * to be carried out during miniDSP switching. | ||
82 | */ | ||
83 | #if 1 | ||
84 | minidsp_parser_data dsp_parse_data[MINIDSP_PARSER_ARRAY_SIZE*2]; | ||
85 | |||
86 | struct i2c_msg i2c_transaction[MINIDSP_PARSER_ARRAY_SIZE * 2]; | ||
87 | /* Total count of I2C Messages are stored in the i2c_count */ | ||
88 | int i2c_count; | ||
89 | |||
90 | /* The below array is used to store the burst array for I2C Multibyte | ||
91 | * Operations | ||
92 | */ | ||
93 | minidsp_i2c_page i2c_page_array[MINIDSP_PARSER_ARRAY_SIZE]; | ||
94 | int i2c_page_count; | ||
95 | #else | ||
96 | minidsp_parser_data dsp_parse_data; | ||
97 | |||
98 | struct i2c_msg i2c_transaction; | ||
99 | /* Total count of I2C Messages are stored in the i2c_count */ | ||
100 | int i2c_count; | ||
101 | |||
102 | /* The below array is used to store the burst array for I2C Multibyte | ||
103 | * Operations | ||
104 | */ | ||
105 | minidsp_i2c_page i2c_page_array; | ||
106 | int i2c_page_count; | ||
107 | #endif | ||
108 | |||
109 | /* kcontrol structure used to register with ALSA Core layer */ | ||
110 | static struct snd_kcontrol_new snd_mux_controls[MAX_MUX_CONTROLS]; | ||
111 | |||
112 | /* mode variables */ | ||
113 | static int amode; | ||
114 | static int dmode; | ||
115 | |||
116 | /* k-control macros used for miniDSP related Kcontrols */ | ||
117 | #define SOC_SINGLE_VALUE_M(xmax, xinvert) \ | ||
118 | ((unsigned long)&(struct soc_mixer_control) \ | ||
119 | {.max = xmax, \ | ||
120 | .invert = xinvert}) | ||
121 | #define SOC_SINGLE_M(xname, max, invert) \ | ||
122 | {\ | ||
123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
124 | .info = m_control_info, .get = m_control_get,\ | ||
125 | .put = m_control_put, \ | ||
126 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
127 | .private_value = SOC_SINGLE_VALUE_M(max, invert) } | ||
128 | #define SOC_SINGLE_AIC3262_M(xname) \ | ||
129 | {\ | ||
130 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
131 | .info = m_control_info, .get = m_control_get,\ | ||
132 | .put = m_control_put, \ | ||
133 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * aic3262_minidsp_controls | ||
138 | * | ||
139 | * Contains the list of the Kcontrol macros required for modifying the | ||
140 | * miniDSP behavior at run-time. | ||
141 | */ | ||
142 | static const struct snd_kcontrol_new aic3262_minidsp_controls[] = { | ||
143 | SOC_SINGLE_AIC3262_M("Minidsp mode") , | ||
144 | SOC_SINGLE_AIC3262_M("ADC Adaptive mode Enable") , | ||
145 | SOC_SINGLE_AIC3262_M("DAC Adaptive mode Enable") , | ||
146 | SOC_SINGLE_AIC3262_M("Dump Regs Book0") , | ||
147 | SOC_SINGLE_AIC3262_M("Verify minidsp program") , | ||
148 | }; | ||
149 | |||
150 | #ifdef REG_DUMP_MINIDSP | ||
151 | /* | ||
152 | *---------------------------------------------------------------------------- | ||
153 | * Function : aic3262_dump_page | ||
154 | * Purpose : Read and display one codec register page, for debugging purpose | ||
155 | *---------------------------------------------------------------------------- | ||
156 | */ | ||
157 | static void aic3262_dump_page(struct i2c_client *i2c, u8 page) | ||
158 | { | ||
159 | int i; | ||
160 | u8 data; | ||
161 | u8 test_page_array[256]; | ||
162 | |||
163 | aic3262_change_page(codec, page); | ||
164 | |||
165 | data = 0x0; | ||
166 | |||
167 | i2c_master_send(i2c, data, 1); | ||
168 | i2c_master_recv(i2c, test_page_array, 128); | ||
169 | |||
170 | DBG("\n------- MINI_DSP PAGE %d DUMP --------\n", page); | ||
171 | for (i = 0; i < 128; i++) | ||
172 | DBG(KERN_INFO " [ %d ] = 0x%x\n", i, test_page_array[i]); | ||
173 | |||
174 | } | ||
175 | #endif | ||
176 | |||
177 | /* | ||
178 | *---------------------------------------------------------------------------- | ||
179 | * Function : update_kcontrols | ||
180 | * Purpose : Given the miniDSP process flow, this function reads the | ||
181 | * corresponding Page Numbers and then performs I2C Read for those | ||
182 | * Pages. | ||
183 | *---------------------------------------------------------------------------- | ||
184 | */ | ||
185 | void update_kcontrols(struct snd_soc_codec *codec, int process_flow) | ||
186 | { | ||
187 | int i, val1, array_size; | ||
188 | char **knames; | ||
189 | control *cntl; | ||
190 | |||
191 | #if 0 | ||
192 | if (process_flow == 1) { | ||
193 | knames = Second_Rate_MUX_control_names; | ||
194 | cntl = Second_Rate_MUX_controls; | ||
195 | array_size = ARRAY_SIZE(Second_Rate_MUX_controls); | ||
196 | } else { | ||
197 | #endif | ||
198 | knames = main44_MUX_control_names; | ||
199 | cntl = main44_MUX_controls; | ||
200 | array_size = ARRAY_SIZE(main44_MUX_controls); | ||
201 | // } | ||
202 | |||
203 | DBG(KERN_INFO "%s: ARRAY_SIZE = %d\tmode=%d\n", __func__, | ||
204 | array_size, process_flow); | ||
205 | for (i = 0; i < array_size; i++) { | ||
206 | aic3262_change_book(codec, cntl[i].control_book); | ||
207 | aic3262_change_page(codec, cntl[i].control_page); | ||
208 | val1 = i2c_smbus_read_byte_data(codec->control_data, | ||
209 | cntl[i].control_base); | ||
210 | snd_mux_controls[i].private_value = 0; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | *---------------------------------------------------------------------------- | ||
216 | * Function : byte_i2c_array_transfer | ||
217 | * Purpose : Function used only for debugging purpose. This function will | ||
218 | * be used while switching miniDSP Modes register by register. | ||
219 | * This needs to be used only during development. | ||
220 | *----------------------------------------------------------------------------- | ||
221 | */ | ||
222 | #if 1 | ||
223 | int byte_i2c_array_transfer(struct snd_soc_codec *codec, | ||
224 | reg_value *program_ptr, | ||
225 | int size) | ||
226 | { | ||
227 | int j; | ||
228 | u8 buf[3]; | ||
229 | |||
230 | for (j = 0; j < size; j++) { | ||
231 | /* Check if current Reg offset is zero */ | ||
232 | if (program_ptr[j].reg_off == 0) { | ||
233 | /* Check for the Book Change Request */ | ||
234 | if ((j < (size - 1)) && | ||
235 | (program_ptr[j+1].reg_off == 127)) { | ||
236 | aic3262_change_book(codec, | ||
237 | program_ptr[j+1].reg_val); | ||
238 | /* Increment for loop counter across Book Change */ | ||
239 | j++; | ||
240 | continue; | ||
241 | } | ||
242 | /* Check for the Page Change Request in Current book */ | ||
243 | aic3262_change_page(codec, program_ptr[j].reg_val); | ||
244 | continue; | ||
245 | } | ||
246 | |||
247 | buf[AIC3262_REG_OFFSET_INDEX] = program_ptr[j].reg_off % 128; | ||
248 | buf[AIC3262_REG_DATA_INDEX] = | ||
249 | program_ptr[j].reg_val & AIC3262_8BITS_MASK; | ||
250 | |||
251 | if (codec->hw_write(codec->control_data, buf, 2) != 2) { | ||
252 | printk(KERN_ERR "Error in i2c write\n"); | ||
253 | return -EIO; | ||
254 | } | ||
255 | } | ||
256 | aic3262_change_book(codec, 0); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | #else | ||
261 | int byte_i2c_array_transfer(struct snd_soc_codec *codec, | ||
262 | reg_value *program_ptr, | ||
263 | int size) | ||
264 | { | ||
265 | int j; | ||
266 | u8 buf[3]; | ||
267 | printk(KERN_INFO "%s: started with array size %d\n", __func__, size); | ||
268 | for (j = 0; j < size; j++) { | ||
269 | /* Check if current Reg offset is zero */ | ||
270 | buf[AIC3262_REG_OFFSET_INDEX] = program_ptr[j].reg_off % 128; | ||
271 | buf[AIC3262_REG_DATA_INDEX] = | ||
272 | program_ptr[j].reg_val & AIC3262_8BITS_MASK; | ||
273 | |||
274 | if (codec->hw_write(codec->control_data, buf, 2) != 2) { | ||
275 | printk(KERN_ERR "Error in i2c write\n"); | ||
276 | return -EIO; | ||
277 | } | ||
278 | } | ||
279 | printk(KERN_INFO "%s: ended\n", __func__); | ||
280 | return 0; | ||
281 | } | ||
282 | #endif | ||
283 | /* | ||
284 | *---------------------------------------------------------------------------- | ||
285 | * Function : byte_i2c_array_read | ||
286 | * Purpose : This function is used to perform Byte I2C Read. This is used | ||
287 | * only for debugging purposes to read back the Codec Page | ||
288 | * Registers after miniDSP Configuration. | ||
289 | *---------------------------------------------------------------------------- | ||
290 | */ | ||
291 | int byte_i2c_array_read(struct snd_soc_codec *codec, | ||
292 | reg_value *program_ptr, int size) | ||
293 | { | ||
294 | int j; | ||
295 | u8 val1; | ||
296 | u8 cur_page = 0; | ||
297 | u8 cur_book = 0; | ||
298 | for (j = 0; j < size; j++) { | ||
299 | /* Check if current Reg offset is zero */ | ||
300 | if (program_ptr[j].reg_off == 0) { | ||
301 | /* Check for the Book Change Request */ | ||
302 | if ((j < (size - 1)) && | ||
303 | (program_ptr[j+1].reg_off == 127)) { | ||
304 | aic3262_change_book(codec, | ||
305 | program_ptr[j+1].reg_val); | ||
306 | cur_book = program_ptr[j+1].reg_val; | ||
307 | /* Increment for loop counter across Book Change */ | ||
308 | j++; | ||
309 | continue; | ||
310 | } | ||
311 | /* Check for the Page Change Request in Current book */ | ||
312 | aic3262_change_page(codec, program_ptr[j].reg_val); | ||
313 | cur_page = program_ptr[j].reg_val; | ||
314 | continue; | ||
315 | } | ||
316 | |||
317 | val1 = i2c_smbus_read_byte_data(codec->control_data, | ||
318 | program_ptr[j].reg_off); | ||
319 | if (val1 < 0) | ||
320 | printk(KERN_ERR "Error in smbus read\n"); | ||
321 | |||
322 | if(val1 != program_ptr[j].reg_val) | ||
323 | /*printk(KERN_INFO "mismatch [%d][%d][%d] = %x %x\n", | ||
324 | cur_book, cur_page, program_ptr[j].reg_off, val1, program_ptr[j].reg_val);*/ | ||
325 | DBG(KERN_INFO "[%d][%d][%d]= %x\n", | ||
326 | cur_book, cur_page, program_ptr[j].reg_off, val1); | ||
327 | } | ||
328 | aic3262_change_book(codec, 0); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | *---------------------------------------------------------------------------- | ||
334 | * Function : minidsp_get_burst | ||
335 | * Purpose : Format one I2C burst for transfer from mini dsp program array. | ||
336 | * This function will parse the program array and get next burst | ||
337 | * data for doing an I2C bulk transfer. | ||
338 | *---------------------------------------------------------------------------- | ||
339 | */ | ||
340 | static void | ||
341 | minidsp_get_burst(reg_value *program_ptr, | ||
342 | int program_size, | ||
343 | minidsp_parser_data *parse_data) | ||
344 | { | ||
345 | int index = parse_data->current_loc; | ||
346 | int burst_write_count = 0; | ||
347 | |||
348 | /*DBG("GET_BURST: start\n");*/ | ||
349 | /* check if first location is page register, and populate page addr */ | ||
350 | if (program_ptr[index].reg_off == 0) { | ||
351 | if ((index < (program_size - 1)) && | ||
352 | (program_ptr[index+1].reg_off == 127)) { | ||
353 | parse_data->book_change = 1; | ||
354 | parse_data->book_no = program_ptr[index+1].reg_val; | ||
355 | index += 2; | ||
356 | goto finish_out; | ||
357 | |||
358 | } | ||
359 | parse_data->page_num = program_ptr[index].reg_val; | ||
360 | parse_data->burst_array[burst_write_count++] = | ||
361 | program_ptr[index].reg_off; | ||
362 | parse_data->burst_array[burst_write_count++] = | ||
363 | program_ptr[index].reg_val; | ||
364 | index++; | ||
365 | goto finish_out; | ||
366 | } | ||
367 | |||
368 | parse_data->burst_array[burst_write_count++] = | ||
369 | program_ptr[index].reg_off; | ||
370 | parse_data->burst_array[burst_write_count++] = | ||
371 | program_ptr[index].reg_val; | ||
372 | index++; | ||
373 | |||
374 | for (; index < program_size; index++) { | ||
375 | if (program_ptr[index].reg_off != | ||
376 | (program_ptr[index - 1].reg_off + 1)) | ||
377 | break; | ||
378 | else | ||
379 | parse_data->burst_array[burst_write_count++] = | ||
380 | program_ptr[index].reg_val; | ||
381 | |||
382 | } | ||
383 | finish_out: | ||
384 | parse_data->burst_size = burst_write_count; | ||
385 | if (index == program_size) | ||
386 | /* parsing completed */ | ||
387 | parse_data->current_loc = MINIDSP_PARSING_END; | ||
388 | else | ||
389 | parse_data->current_loc = index; | ||
390 | /*DBG("GET_BURST: end\n");*/ | ||
391 | } | ||
392 | /* | ||
393 | *---------------------------------------------------------------------------- | ||
394 | * Function : minidsp_i2c_multibyte_transfer | ||
395 | * Purpose : Function used to perform multi-byte I2C Writes. Used to configure | ||
396 | * the miniDSP Pages. | ||
397 | *---------------------------------------------------------------------------- | ||
398 | */ | ||
399 | #if 1 | ||
400 | int | ||
401 | minidsp_i2c_multibyte_transfer(struct snd_soc_codec *codec, | ||
402 | reg_value *program_ptr, | ||
403 | int program_size) | ||
404 | { | ||
405 | struct i2c_client *client = codec->control_data; | ||
406 | |||
407 | minidsp_parser_data parse_data; | ||
408 | int count = 0; | ||
409 | |||
410 | #ifdef DEBUG_MINIDSP_LOADING | ||
411 | int i = 0, j = 0; | ||
412 | #endif | ||
413 | /* point the current location to start of program array */ | ||
414 | parse_data.current_loc = 0; | ||
415 | parse_data.page_num = 0; | ||
416 | parse_data.book_change = 0; | ||
417 | parse_data.book_no = 0; | ||
418 | |||
419 | DBG(KERN_INFO "size is : %d", program_size); | ||
420 | do { | ||
421 | do { | ||
422 | /* Get first burst data */ | ||
423 | minidsp_get_burst(program_ptr, program_size, | ||
424 | &parse_data); | ||
425 | if (parse_data.book_change == 1) | ||
426 | break; | ||
427 | dsp_parse_data[count] = parse_data; | ||
428 | |||
429 | i2c_transaction[count].addr = client->addr; | ||
430 | i2c_transaction[count].flags = | ||
431 | client->flags & I2C_M_TEN; | ||
432 | i2c_transaction[count].len = | ||
433 | dsp_parse_data[count].burst_size; | ||
434 | i2c_transaction[count].buf = | ||
435 | dsp_parse_data[count].burst_array; | ||
436 | |||
437 | #ifdef DEBUG_MINIDSP_LOADING | ||
438 | DBG(KERN_INFO | ||
439 | "i: %d\taddr: %d\tflags: %d\tlen: %d\tbuf:", | ||
440 | i, client->addr, client->flags & I2C_M_TEN, | ||
441 | dsp_parse_data[count].burst_size); | ||
442 | |||
443 | for (j = 0; j <= dsp_parse_data[count].burst_size; j++) | ||
444 | DBG(KERN_INFO "%x ", | ||
445 | dsp_parse_data[i].burst_array[j]); | ||
446 | |||
447 | DBG(KERN_INFO "\n\n"); | ||
448 | i++; | ||
449 | #endif | ||
450 | |||
451 | count++; | ||
452 | /* Proceed to the next burst reg_addr_incruence */ | ||
453 | } while (parse_data.current_loc != MINIDSP_PARSING_END); | ||
454 | |||
455 | if (count > 0) { | ||
456 | if (i2c_transfer(client->adapter, | ||
457 | i2c_transaction, count) != count) { | ||
458 | printk(KERN_ERR "Write burst i2c data error!\n"); | ||
459 | } | ||
460 | } | ||
461 | if (parse_data.book_change == 1) { | ||
462 | aic3262_change_book(codec, parse_data.book_no); | ||
463 | parse_data.book_change = 0; | ||
464 | } | ||
465 | } while (parse_data.current_loc != MINIDSP_PARSING_END); | ||
466 | aic3262_change_book(codec, 0); | ||
467 | return 0; | ||
468 | } | ||
469 | #else | ||
470 | int | ||
471 | minidsp_i2c_multibyte_transfer(struct snd_soc_codec *codec, | ||
472 | reg_value *program_ptr, | ||
473 | int program_size) | ||
474 | { | ||
475 | struct i2c_client *client = codec->control_data; | ||
476 | |||
477 | minidsp_parser_data parse_data; | ||
478 | int count = 1; | ||
479 | |||
480 | #ifdef DEBUG_MINIDSP_LOADING | ||
481 | int i = 0, j = 0; | ||
482 | #endif | ||
483 | /* point the current location to start of program array */ | ||
484 | parse_data.current_loc = 0; | ||
485 | parse_data.page_num = 0; | ||
486 | parse_data.book_change = 0; | ||
487 | parse_data.book_no = 0; | ||
488 | |||
489 | DBG(KERN_INFO "size is : %d", program_size); | ||
490 | |||
491 | do { | ||
492 | /* Get first burst data */ | ||
493 | minidsp_get_burst(program_ptr, program_size, | ||
494 | &parse_data); | ||
495 | |||
496 | dsp_parse_data = parse_data; | ||
497 | |||
498 | i2c_transaction.addr = client->addr; | ||
499 | i2c_transaction.flags = | ||
500 | client->flags & I2C_M_TEN; | ||
501 | i2c_transaction.len = | ||
502 | dsp_parse_data.burst_size; | ||
503 | i2c_transaction.buf = | ||
504 | dsp_parse_data.burst_array; | ||
505 | |||
506 | #ifdef DEBUG_MINIDSP_LOADING | ||
507 | DBG(KERN_INFO | ||
508 | "i: %d\taddr: %d\tflags: %d\tlen: %d\tbuf:", | ||
509 | i, client->addr, client->flags & I2C_M_TEN, | ||
510 | dsp_parse_data.burst_size); | ||
511 | |||
512 | for (j = 0; j <= dsp_parse_data.burst_size; j++) | ||
513 | printk( "%x ", | ||
514 | dsp_parse_data.burst_array[j]); | ||
515 | |||
516 | DBG(KERN_INFO "\n\n"); | ||
517 | i++; | ||
518 | #endif | ||
519 | |||
520 | if (i2c_transfer(client->adapter, | ||
521 | &i2c_transaction, count) != count) { | ||
522 | printk(KERN_ERR "Write burst i2c data error!\n"); | ||
523 | } | ||
524 | if (parse_data.book_change == 1) { | ||
525 | aic3262_change_book(codec, parse_data.book_no); | ||
526 | parse_data.book_change = 0; | ||
527 | } | ||
528 | /* Proceed to the next burst reg_addr_incruence */ | ||
529 | } while (parse_data.current_loc != MINIDSP_PARSING_END); | ||
530 | |||
531 | return 0; | ||
532 | } | ||
533 | #endif | ||
534 | /* | ||
535 | * Process_Flow Structure | ||
536 | * Structure used to maintain the mapping of each PFW like the miniDSP_A | ||
537 | * miniDSP_D array values and sizes. It also contains information about | ||
538 | * the patches required for each patch. | ||
539 | */ | ||
540 | struct process_flow{ | ||
541 | int init_size; | ||
542 | reg_value *miniDSP_init; | ||
543 | int A_size; | ||
544 | reg_value *miniDSP_A_values; | ||
545 | int D_size; | ||
546 | reg_value *miniDSP_D_values; | ||
547 | int post_size; | ||
548 | reg_value *miniDSP_post; | ||
549 | struct minidsp_config { | ||
550 | int a_patch_size; | ||
551 | reg_value *a_patch; | ||
552 | int d_patch_size; | ||
553 | reg_value *d_patch; | ||
554 | } configs[MAXCONFIG]; | ||
555 | |||
556 | } miniDSP_programs[] = { | ||
557 | { | ||
558 | ARRAY_SIZE(main44_REG_Section_init_program), main44_REG_Section_init_program, | ||
559 | ARRAY_SIZE(main44_miniDSP_A_reg_values),main44_miniDSP_A_reg_values, | ||
560 | ARRAY_SIZE(main44_miniDSP_D_reg_values),main44_miniDSP_D_reg_values, | ||
561 | ARRAY_SIZE(main44_REG_Section_post_program),main44_REG_Section_post_program, | ||
562 | { | ||
563 | |||
564 | { 0, 0, 0, 0}, | ||
565 | { 0, 0, 0, 0}, | ||
566 | { 0, 0, 0, 0}, | ||
567 | { 0, 0, 0, 0}, | ||
568 | |||
569 | |||
570 | }, | ||
571 | }, | ||
572 | { | ||
573 | ARRAY_SIZE(base_speaker_SRS_REG_init_Section_program),base_speaker_SRS_REG_init_Section_program, | ||
574 | ARRAY_SIZE(base_speaker_SRS_miniDSP_A_reg_values),base_speaker_SRS_miniDSP_A_reg_values, | ||
575 | ARRAY_SIZE(base_speaker_SRS_miniDSP_D_reg_values),base_speaker_SRS_miniDSP_D_reg_values, | ||
576 | ARRAY_SIZE(base_speaker_SRS_REG_post_Section_program),base_speaker_SRS_REG_post_Section_program, | ||
577 | |||
578 | { | ||
579 | {0, 0, ARRAY_SIZE(SRS_ON_miniDSP_D_reg_values), SRS_ON_miniDSP_D_reg_values}, | ||
580 | {0, 0, ARRAY_SIZE(SRS_OFF_miniDSP_D_reg_values),SRS_OFF_miniDSP_D_reg_values}, | ||
581 | {0, 0, 0, 0}, | ||
582 | {0, 0, 0, 0}, | ||
583 | }, | ||
584 | }, | ||
585 | #if 0 | ||
586 | {ARRAY_SIZE(spkr_srs_REG_Section_init_program),spkr_srs_REG_Section_init_program, | ||
587 | ARRAY_SIZE(spkr_srs_miniDSP_A_reg_values),spkr_srs_miniDSP_A_reg_values, | ||
588 | ARRAY_SIZE(spkr_srs_miniDSP_D_reg_values),spkr_srs_miniDSP_D_reg_values, | ||
589 | ARRAY_SIZE(spkr_srs_REG_Section_post_program),spkr_srs_REG_Section_post_program, | ||
590 | { | ||
591 | { 0, 0, 0, 0}, | ||
592 | { 0, 0, 0, 0}, | ||
593 | { 0, 0, 0, 0}, | ||
594 | { 0, 0, 0, 0}, | ||
595 | |||
596 | }, | ||
597 | }, | ||
598 | #endif | ||
599 | }; | ||
600 | |||
601 | int | ||
602 | set_minidsp_mode(struct snd_soc_codec *codec, int new_mode, int new_config) | ||
603 | { | ||
604 | |||
605 | if (codec == NULL) { | ||
606 | printk(KERN_INFO "%s codec is NULL\n",__func__); | ||
607 | } | ||
608 | struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec); | ||
609 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
610 | struct process_flow * pflows = &miniDSP_programs[new_mode]; | ||
611 | u8 reg63, reg81, pll_pow, ndac_pow, mdac_pow, nadc_pow, madc_pow; | ||
612 | |||
613 | u8 adc_status,dac_status; | ||
614 | u8 reg, val; | ||
615 | u8 shift; | ||
616 | volatile u16 counter; | ||
617 | |||
618 | int (*ptransfer)(struct snd_soc_codec *codec, | ||
619 | reg_value *program_ptr, | ||
620 | int size); | ||
621 | |||
622 | printk("%s:New Switch mode = %d New Config= %d\n", __func__, new_mode,new_config); | ||
623 | if (new_mode >= ARRAY_SIZE(miniDSP_programs)) | ||
624 | return 0; // error condition | ||
625 | if (new_config > MAXCONFIG) | ||
626 | return 0; | ||
627 | #ifndef MULTIBYTE_I2C | ||
628 | ptransfer = byte_i2c_array_transfer; | ||
629 | #else | ||
630 | ptransfer = minidsp_i2c_multibyte_transfer; | ||
631 | #endif | ||
632 | if (new_mode != aic326x->process_flow) { | ||
633 | |||
634 | printk("== From PFW %d to PFW %d==\n", aic326x->process_flow , new_mode); | ||
635 | |||
636 | /* Change to book 0 page 0 and turn off the DAC and snd_soc_dapm_disable_piADC, | ||
637 | * while turning them down, poll for the power down completion. | ||
638 | */ | ||
639 | aic3262_change_page(codec, 0); | ||
640 | aic3262_change_book(codec, 0); | ||
641 | |||
642 | #if 0 | ||
643 | reg63 = aic3262_read(codec, PASI_DAC_DP_SETUP); | ||
644 | aic3262_write(codec, PASI_DAC_DP_SETUP, (reg63 & ~0xC0));/*dac power down*/ | ||
645 | mdelay (5); | ||
646 | counter = 0; | ||
647 | reg = DAC_FLAG_R1; | ||
648 | |||
649 | dac_status = aic3262_read(codec, reg); | ||
650 | |||
651 | do { | ||
652 | dac_status = snd_soc_read(codec, reg); | ||
653 | counter++;struct snd_soc_dapm_context *dapm | ||
654 | mdelay(5); | ||
655 | } while ((counter < 200) && ((dac_status & 0x88) == 1)); | ||
656 | printk (KERN_INFO "#%s: Polled Register %d Bits set 0x%X counter %d\n", | ||
657 | __func__, reg, dac_status, counter);snd_soc_dapm_disable_pi | ||
658 | struct snd_soc_dapm_context *dapm | ||
659 | reg81= aic3262_read(codec, ADC_CHANNEL_POW); | ||
660 | aic3262_write(codec, ADC_CHANNEL_POW, (reg81 & ~0xC0));/*adc power down*/ | ||
661 | mdelay (5); | ||
662 | |||
663 | adc_status=aic3262_read(codec,ADC_FLAG_R1); | ||
664 | counter = 0; | ||
665 | reg = ADC_FLAG_R1; | ||
666 | do { | ||
667 | adc_status = snd_soc_read(codec, reg); | ||
668 | counter++; | ||
669 | mdelay(5); | ||
670 | } while ((counter < 200) && ((adc_status & 0x44) == 1)); | ||
671 | |||
672 | printk (KERN_INFO "#%s: Polled Register %d Bits set 0x%X counter %d\n", | ||
673 | __func__, reg, adc_status, counter); | ||
674 | |||
675 | dac_status = snd_soc_read(codec, DAC_FLAG_R1); | ||
676 | adc_status = snd_soc_read (codec, ADC_FLAG_R1); | ||
677 | |||
678 | printk (KERN_INFO "#%s: Initial DAC_STATUS 0x%x ADC_STATUS 0x%X\n", | ||
679 | __func__, dac_status, adc_status); | ||
680 | |||
681 | #endif | ||
682 | /* Instead of hard-coding the switching off DAC and ADC, we will use the DAPM | ||
683 | * to switch off the Playback Paths and the ADC | ||
684 | */ | ||
685 | snd_soc_dapm_disable_pin( dapm, "Headphone Jack"); | ||
686 | snd_soc_dapm_disable_pin( dapm, "EarPiece"); | ||
687 | snd_soc_dapm_disable_pin( dapm, "Int Spk"); | ||
688 | snd_soc_dapm_disable_pin( dapm, "SPK out"); | ||
689 | snd_soc_dapm_disable_pin( dapm, "Line Out"); | ||
690 | |||
691 | snd_soc_dapm_disable_pin( dapm, "Mic Jack"); | ||
692 | snd_soc_dapm_disable_pin( dapm, "Linein"); | ||
693 | snd_soc_dapm_disable_pin( dapm, "Int Mic"); | ||
694 | |||
695 | //snd_soc_dapm_disable_pin (codec, "Left DAC"); | ||
696 | //snd_soc_dapm_disable_pin (codec, "Right DAC"); | ||
697 | //snd_soc_dapm_disable_pin (codec, "Left ADC"); | ||
698 | //snd_soc_dapm_disable_pin (codec, "Right ADC"); | ||
699 | snd_soc_dapm_sync(dapm); | ||
700 | mdelay(10); | ||
701 | |||
702 | mdac_pow = aic3262_read(codec, MDAC_DIV_POW_REG); | ||
703 | aic3262_write(codec, MDAC_DIV_POW_REG, (mdac_pow & ~0x80));/*mdac power down*/ | ||
704 | mdelay(5); | ||
705 | nadc_pow = aic3262_read(codec, MADC_DIV_POW_REG); | ||
706 | aic3262_write(codec, MADC_DIV_POW_REG, (nadc_pow & ~0x80));/*madc power down*/ | ||
707 | mdelay(5); | ||
708 | pll_pow = aic3262_read(codec, PLL_PR_POW_REG); | ||
709 | aic3262_write(codec, PLL_PR_POW_REG, (pll_pow & ~0x80));/*pll power down*/ | ||
710 | mdelay(5); | ||
711 | ndac_pow = aic3262_read(codec, NDAC_DIV_POW_REG); | ||
712 | aic3262_write(codec, NDAC_DIV_POW_REG, (ndac_pow & ~0x80)); /*ndac power down*/ | ||
713 | mdelay(5); | ||
714 | |||
715 | dac_status = snd_soc_read(codec, DAC_FLAG_R1); | ||
716 | adc_status = snd_soc_read (codec, ADC_FLAG_R1); | ||
717 | |||
718 | printk (KERN_INFO "#%s: Before Switching DAC_STATUS 0x%x ADC_STATUS 0x%X\n", | ||
719 | __func__, dac_status, adc_status); | ||
720 | |||
721 | mdelay (10); | ||
722 | ptransfer(codec, pflows->miniDSP_init, pflows->init_size); | ||
723 | ptransfer(codec, pflows->miniDSP_A_values, pflows->A_size); | ||
724 | ptransfer(codec, pflows->miniDSP_D_values, pflows->D_size); | ||
725 | ptransfer(codec, pflows->miniDSP_post, pflows->post_size); | ||
726 | |||
727 | |||
728 | aic326x->process_flow = new_mode; | ||
729 | |||
730 | aic3262_change_page(codec, 0); | ||
731 | aic3262_change_book(codec, 0); | ||
732 | #if 0 | ||
733 | |||
734 | /* After the miniDSP Programming is completed, power up the DAC and ADC | ||
735 | * and poll for its power up operation. | ||
736 | */ | ||
737 | |||
738 | aic3262_write(codec, PASI_DAC_DP_SETUP, reg63);/*reverting the old DAC values */ | ||
739 | mdelay(5); | ||
740 | |||
741 | /* Poll for DAC Power-up first */ | ||
742 | /* For DAC Power-up and Power-down event, we will poll for | ||
743 | * Book0 Page0 Register 37 | ||
744 | */ | ||
745 | reg = DAC_FLAG_R1; | ||
746 | counter = 0; | ||
747 | do { | ||
748 | dac_status = snd_soc_read(codec, reg); | ||
749 | counter++; | ||
750 | mdelay(5); | ||
751 | } while ((counter < 200) && ((dac_status & 0x88) == 0)); | ||
752 | |||
753 | printk (KERN_INFO "#%s: Polled Register %d Bits set 0x%X counter %d\n", | ||
754 | __func__, reg, dac_status, counter); | ||
755 | |||
756 | aic3262_write(codec, ADC_CHANNEL_POW, reg81);/*reverting the old ADC values*/ | ||
757 | mdelay (5); | ||
758 | /* For ADC Power-up and Power-down event, we will poll for | ||
759 | * Book0 Page0 Register 36 | ||
760 | */ | ||
761 | reg = ADC_FLAG_R1; | ||
762 | counter = 0; | ||
763 | do { | ||
764 | adc_status = snd_soc_read(codec, reg); | ||
765 | counter++; | ||
766 | mdelay(5); | ||
767 | } while ((counter < 200) && ((adc_status & 0x44) == 0)); | ||
768 | |||
769 | printk (KERN_INFO "#%s: Polled Register %d Bits set 0x%X counter %d\n", | ||
770 | __func__, reg, adc_status, counter); | ||
771 | aic3262_write(codec, PLL_PR_POW_REG, pll_pow);/*reverting the old pll values*/ | ||
772 | mdelay(10); | ||
773 | |||
774 | aic3262_write(codec, MDAC_DIV_POW_REG, mdac_pow);/*reverting the old mdac values*/ | ||
775 | mdelay(5); | ||
776 | aic3262_write(codec, MADC_DIV_POW_REG, madc_pow);/*reverting the old madc values*/ | ||
777 | mdelay(5); | ||
778 | aic3262_write(codec, NDAC_DIV_POW_REG, ndac_pow);/*reverting the old ndac values*/ | ||
779 | mdelay(5); | ||
780 | |||
781 | /*if (new_config == 0) { | ||
782 | aic326x->current_config = 0; | ||
783 | return 0; | ||
784 | } | ||
785 | aic326x->current_config = -1;*/ | ||
786 | |||
787 | //aic3262_change_book(codec, 0); | ||
788 | //aic3262_change_page(codec, 0); | ||
789 | #endif | ||
790 | } | ||
791 | |||
792 | #ifdef MULTICONFIG_SUPPORT | ||
793 | if (new_config < 0 ) | ||
794 | return 0; // No configs supported in this pfw | ||
795 | if (new_config == aic326x->current_config) | ||
796 | return 0; | ||
797 | if (pflows->configs[new_config].a_patch_size || pflows->configs[new_config].d_patch_size) | ||
798 | minidsp_multiconfig(codec, | ||
799 | pflows->configs[new_config].a_patch, pflows->configs[new_config].a_patch_size, | ||
800 | pflows->configs[new_config].d_patch, pflows->configs[new_config].d_patch_size); | ||
801 | #endif | ||
802 | |||
803 | aic326x->current_config = new_config; | ||
804 | aic3262_change_book( codec, 0); | ||
805 | |||
806 | DBG(KERN_INFO "%s: switch mode finished\n", __func__); | ||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | /* | ||
811 | * i2c_verify | ||
812 | * | ||
813 | * Function used to validate the contents written into the miniDSP | ||
814 | * pages after miniDSP Configuration. | ||
815 | */ | ||
816 | int i2c_verify(struct snd_soc_codec *codec) | ||
817 | { | ||
818 | |||
819 | DBG(KERN_INFO "#%s: Invoked.. Resetting to page 0\n", __func__); | ||
820 | |||
821 | aic3262_change_book(codec, 0); | ||
822 | DBG(KERN_INFO "#Reading reg_section_init_program\n"); | ||
823 | |||
824 | byte_i2c_array_read(codec, main44_REG_Section_init_program, | ||
825 | ARRAY_SIZE(main44_REG_Section_init_program)); | ||
826 | |||
827 | DBG(KERN_INFO "#Reading minidsp_A_reg_values\n"); | ||
828 | byte_i2c_array_read(codec, main44_miniDSP_A_reg_values, | ||
829 | (main44_miniDSP_A_reg_values_COEFF_SIZE + | ||
830 | main44_miniDSP_A_reg_values_INST_SIZE)); | ||
831 | |||
832 | DBG(KERN_INFO "#Reading minidsp_D_reg_values\n"); | ||
833 | byte_i2c_array_read(codec, main44_miniDSP_D_reg_values, | ||
834 | (main44_miniDSP_D_reg_values_COEFF_SIZE + | ||
835 | main44_miniDSP_D_reg_values_INST_SIZE)); | ||
836 | |||
837 | DBG(KERN_INFO "#Reading reg_section_post_program\n"); | ||
838 | byte_i2c_array_read(codec, main44_REG_Section_post_program, | ||
839 | ARRAY_SIZE(main44_REG_Section_post_program)); | ||
840 | |||
841 | aic3262_change_book(codec, 0); | ||
842 | |||
843 | DBG(KERN_INFO "i2c_verify completed\n"); | ||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | |||
848 | int change_codec_power_status(struct snd_soc_codec * codec, int off_restore, int power_mask) | ||
849 | { | ||
850 | int minidsp_power_mask; | ||
851 | u8 dac_status; | ||
852 | u8 adc_status; | ||
853 | |||
854 | minidsp_power_mask = 0; | ||
855 | |||
856 | aic3262_change_page (codec, 0); | ||
857 | aic3262_change_book (codec, 0); | ||
858 | |||
859 | |||
860 | switch (off_restore) { | ||
861 | |||
862 | case 0: /* Power-off the Codec */ | ||
863 | dac_status = snd_soc_read (codec, DAC_FLAG_R1); | ||
864 | |||
865 | if(dac_status & 0x88) { | ||
866 | minidsp_power_mask |= 0x1; | ||
867 | snd_soc_update_bits(codec, PASI_DAC_DP_SETUP, 0xC0, 0x0); | ||
868 | |||
869 | poll_dac(codec, 0x0, 0x0); | ||
870 | poll_dac(codec, 0x1, 0x0); | ||
871 | } | ||
872 | |||
873 | adc_status = snd_soc_read (codec, ADC_FLAG_R1); | ||
874 | |||
875 | if(adc_status & 0x44) { | ||
876 | minidsp_power_mask |= 0x2; | ||
877 | snd_soc_update_bits(codec, ADC_CHANNEL_POW, 0xC0, 0x0); | ||
878 | |||
879 | poll_adc(codec, 0x0, 0x0); | ||
880 | poll_adc(codec, 0x1, 0x0); | ||
881 | } | ||
882 | break; | ||
883 | case 1: /* For Restoring Codec to Previous Power State */ | ||
884 | |||
885 | if(power_mask & 0x1) { | ||
886 | |||
887 | snd_soc_update_bits(codec, PASI_DAC_DP_SETUP, 0xC0, 0xC0); | ||
888 | |||
889 | poll_dac(codec, 0x0, 0x1); | ||
890 | poll_dac(codec, 0x1, 0x1); | ||
891 | } | ||
892 | |||
893 | if(power_mask & 0x2) { | ||
894 | |||
895 | snd_soc_update_bits(codec, ADC_CHANNEL_POW, 0xC0, 0xC0); | ||
896 | |||
897 | poll_adc(codec, 0x0, 0x1); | ||
898 | poll_adc(codec, 0x1, 0x1); | ||
899 | } | ||
900 | break; | ||
901 | default: | ||
902 | printk(KERN_ERR "#%s: Unknown Power State Requested..\n", | ||
903 | __func__); | ||
904 | } | ||
905 | |||
906 | return minidsp_power_mask; | ||
907 | |||
908 | } | ||
909 | |||
910 | /* | ||
911 | *---------------------------------------------------------------------------- | ||
912 | * Function : boot_minidsp | ||
913 | * Purpose : for laoding the default minidsp mode for the first time . | ||
914 | *---------------------------------------------------------------------------- | ||
915 | */ | ||
916 | int | ||
917 | boot_minidsp(struct snd_soc_codec *codec, int new_mode) | ||
918 | { | ||
919 | struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec); | ||
920 | struct process_flow * pflows = &miniDSP_programs[new_mode]; | ||
921 | int minidsp_stat; | ||
922 | |||
923 | int (*ptransfer)(struct snd_soc_codec *codec, | ||
924 | reg_value *program_ptr, | ||
925 | int size); | ||
926 | |||
927 | DBG("%s: switch mode start\n", __func__); | ||
928 | if (new_mode >= ARRAY_SIZE(miniDSP_programs)) | ||
929 | return 0; // error condition | ||
930 | if (new_mode == aic326x->process_flow) | ||
931 | return 0; | ||
932 | |||
933 | |||
934 | #ifndef MULTIBYTE_I2C | ||
935 | ptransfer = byte_i2c_array_transfer; | ||
936 | #else | ||
937 | ptransfer = minidsp_i2c_multibyte_transfer; | ||
938 | #endif | ||
939 | |||
940 | minidsp_stat = change_codec_power_status (codec, 0x0, 0x3); | ||
941 | |||
942 | ptransfer(codec, pflows->miniDSP_init, pflows->init_size); | ||
943 | ptransfer(codec, pflows->miniDSP_A_values, pflows->A_size); | ||
944 | ptransfer(codec, pflows->miniDSP_D_values, pflows->D_size); | ||
945 | ptransfer(codec, pflows->miniDSP_post, pflows->post_size); | ||
946 | |||
947 | aic326x->process_flow = new_mode; | ||
948 | |||
949 | change_codec_power_status(codec, 1, minidsp_stat); | ||
950 | |||
951 | aic3262_change_page( codec,0); | ||
952 | aic3262_change_book( codec,0); | ||
953 | |||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | /* | ||
958 | *---------------------------------------------------------------------------- | ||
959 | * Function : aic3262_minidsp_program | ||
960 | * Purpose : Program mini dsp for AIC3262 codec chip. This routine is | ||
961 | * called from the aic3262 codec driver, if mini dsp programming | ||
962 | * is enabled. | ||
963 | *---------------------------------------------------------------------------- | ||
964 | */ | ||
965 | int aic3262_minidsp_program(struct snd_soc_codec *codec) | ||
966 | { | ||
967 | struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec); | ||
968 | DBG(KERN_INFO "#AIC3262: programming mini dsp\n"); | ||
969 | |||
970 | #if defined(PROGRAM_MINI_DSP_first) | ||
971 | #ifdef DEBUG | ||
972 | DBG("#Verifying book 0\n"); | ||
973 | i2c_verify_book0(codec); | ||
974 | #endif | ||
975 | aic3262_change_book(codec, 0); | ||
976 | boot_minidsp(codec, 1); | ||
977 | aic326x->process_flow = 0; | ||
978 | aic3262_change_book(codec, 0); | ||
979 | #ifdef DEBUG | ||
980 | DBG("#verifying book 0\n"); | ||
981 | i2c_verify_book0(codec); | ||
982 | #endif | ||
983 | #endif | ||
984 | #if defined(PROGRAM_MINI_DSP_second) | ||
985 | #ifdef DEBUG | ||
986 | DBG("#Verifying book 0\n"); | ||
987 | aic3262_change_book(codec, 0); | ||
988 | #endif | ||
989 | boot_minidsp(codec, 0); | ||
990 | aic326x->process_flow = 1; | ||
991 | #ifdef DEBUG | ||
992 | DBG("#verifying book 0\n"); | ||
993 | aic3262_change_book(codec, 0); | ||
994 | #endif | ||
995 | #endif | ||
996 | return 0; | ||
997 | } | ||
998 | /* | ||
999 | *---------------------------------------------------------------------------- | ||
1000 | * Function : m_control_info | ||
1001 | * Purpose : This function is to initialize data for new control required to | ||
1002 | * program the AIC3262 registers. | ||
1003 | * | ||
1004 | *---------------------------------------------------------------------------- | ||
1005 | */ | ||
1006 | static int m_control_info(struct snd_kcontrol *kcontrol, | ||
1007 | struct snd_ctl_elem_info *uinfo) | ||
1008 | { | ||
1009 | uinfo->count = 1; | ||
1010 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1011 | uinfo->value.integer.min = 0; | ||
1012 | uinfo->value.integer.max = 1; | ||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | /* | ||
1017 | *---------------------------------------------------------------------------- | ||
1018 | * Function : m_control_get | ||
1019 | * Purpose : This function is to read data of new control for | ||
1020 | * program the AIC3262 registers. | ||
1021 | * | ||
1022 | *---------------------------------------------------------------------------- | ||
1023 | */ | ||
1024 | static int m_control_get(struct snd_kcontrol *kcontrol, | ||
1025 | struct snd_ctl_elem_value *ucontrol) | ||
1026 | { | ||
1027 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1028 | struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); | ||
1029 | u32 val; | ||
1030 | u8 val1; | ||
1031 | |||
1032 | if (!strcmp(kcontrol->id.name, "Minidsp mode")) { | ||
1033 | val = aic3262->process_flow; | ||
1034 | ucontrol->value.integer.value[0] = val; | ||
1035 | DBG(KERN_INFO "control get : mode=%d\n", aic3262->process_flow); | ||
1036 | } | ||
1037 | if (!strcmp(kcontrol->id.name, "DAC Adaptive mode Enable")) { | ||
1038 | aic3262_change_book(codec, 80); | ||
1039 | val1 = i2c_smbus_read_byte_data(codec->control_data, 1); | ||
1040 | ucontrol->value.integer.value[0] = ((val1>>1)&0x01); | ||
1041 | DBG(KERN_INFO "control get : mode=%d\n", aic3262->process_flow); | ||
1042 | aic3262_change_book(codec,0); | ||
1043 | } | ||
1044 | if (!strcmp(kcontrol->id.name, "ADC Adaptive mode Enable")) { | ||
1045 | aic3262_change_book(codec, 40); | ||
1046 | val1 = i2c_smbus_read_byte_data(codec->control_data, 1); | ||
1047 | ucontrol->value.integer.value[0] = ((val1>>1)&0x01); | ||
1048 | DBG(KERN_INFO "control get : mode=%d\n", dmode); | ||
1049 | aic3262_change_book(codec,0); | ||
1050 | } | ||
1051 | |||
1052 | return 0; | ||
1053 | } | ||
1054 | |||
1055 | /* | ||
1056 | *---------------------------------------------------------------------------- | ||
1057 | * Function : m_new_control_put | ||
1058 | * Purpose : new_control_put is called to pass data from user/application to | ||
1059 | * the driver. | ||
1060 | * | ||
1061 | *---------------------------------------------------------------------------- | ||
1062 | */ | ||
1063 | static int m_control_put(struct snd_kcontrol *kcontrol, | ||
1064 | struct snd_ctl_elem_value *ucontrol) | ||
1065 | { | ||
1066 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1067 | struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); | ||
1068 | |||
1069 | u32 val; | ||
1070 | u8 val1; | ||
1071 | int mode = aic3262->process_flow; | ||
1072 | |||
1073 | DBG("n_control_put\n"); | ||
1074 | val = ucontrol->value.integer.value[0]; | ||
1075 | if (!strcmp(kcontrol->id.name, "Minidsp mode")) { | ||
1076 | DBG(KERN_INFO "\nMini dsp put\n mode = %d, val=%d\n", | ||
1077 | aic3262->process_flow, val); | ||
1078 | if (val != mode) { | ||
1079 | if (aic3262->mute_codec == 1) { | ||
1080 | i2c_verify_book0(codec); | ||
1081 | aic3262_change_book(codec, 0); | ||
1082 | boot_minidsp(codec, val); | ||
1083 | |||
1084 | aic3262_change_book(codec, 0); | ||
1085 | i2c_verify_book0(codec); | ||
1086 | /* update_kcontrols(codec, val);*/ | ||
1087 | } else { | ||
1088 | printk(KERN_ERR | ||
1089 | " Cant Switch Processflows, Playback in progress"); | ||
1090 | } | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | if (!strcmp(kcontrol->id.name, "DAC Adaptive mode Enable")) { | ||
1095 | DBG(KERN_INFO "\nMini dsp put\n mode = %d, val=%d\n", | ||
1096 | aic3262->process_flow, val); | ||
1097 | if (val != amode) { | ||
1098 | aic3262_change_book(codec, 80); | ||
1099 | val1 = i2c_smbus_read_byte_data(codec->control_data, 1); | ||
1100 | aic3262_write(codec, 1, (val1&0xfb)|(val<<1)); | ||
1101 | aic3262_change_book(codec,0); | ||
1102 | } | ||
1103 | amode = val; | ||
1104 | } | ||
1105 | |||
1106 | if (!strcmp(kcontrol->id.name, "ADC Adaptive mode Enable")) { | ||
1107 | DBG(KERN_INFO "\nMini dsp put\n mode = %d, val=%d\n", | ||
1108 | aic3262->process_flow, val); | ||
1109 | if (val != dmode) { | ||
1110 | aic3262_change_book(codec, 40); | ||
1111 | val1 = i2c_smbus_read_byte_data(codec->control_data, 1); | ||
1112 | aic3262_write(codec, 1, (val1&0xfb)|(val<<1)); | ||
1113 | aic3262_change_book(codec,0); | ||
1114 | } | ||
1115 | dmode = val; | ||
1116 | } | ||
1117 | |||
1118 | if (!strcmp(kcontrol->id.name, "Dump Regs Book0")) | ||
1119 | i2c_verify_book0(codec); | ||
1120 | |||
1121 | #if 0 | ||
1122 | if (!strcmp(kcontrol->id.name, "Verify minidsp program")) { | ||
1123 | |||
1124 | if (mode == 0) { | ||
1125 | DBG("Current mod=%d\nVerifying minidsp_D_regs", mode); | ||
1126 | byte_i2c_array_read(codec, main44_miniDSP_D_reg_values, | ||
1127 | (main44_miniDSP_D_reg_values_COEFF_SIZE + | ||
1128 | main44_miniDSP_D_reg_values_INST_SIZE)); | ||
1129 | } else { | ||
1130 | byte_i2c_array_read(codec, | ||
1131 | Second_Rate_miniDSP_A_reg_values, | ||
1132 | (Second_Rate_miniDSP_A_reg_values_COEFF_SIZE + | ||
1133 | Second_Rate_miniDSP_A_reg_values_INST_SIZE)); | ||
1134 | byte_i2c_array_read(codec, | ||
1135 | Second_Rate_miniDSP_D_reg_values, | ||
1136 | (Second_Rate_miniDSP_D_reg_values_COEFF_SIZE + | ||
1137 | Second_Rate_miniDSP_D_reg_values_INST_SIZE)); | ||
1138 | } | ||
1139 | } | ||
1140 | #endif | ||
1141 | DBG("\nmode = %d\n", mode); | ||
1142 | return mode; | ||
1143 | } | ||
1144 | |||
1145 | /************************** MUX CONTROL section *****************************/ | ||
1146 | /* | ||
1147 | *---------------------------------------------------------------------------- | ||
1148 | * Function : __new_control_info_minidsp_mux | ||
1149 | * Purpose : info routine for mini dsp mux control amixer kcontrols | ||
1150 | *---------------------------------------------------------------------------- | ||
1151 | */ | ||
1152 | static int __new_control_info_minidsp_mux(struct snd_kcontrol *kcontrol, | ||
1153 | struct snd_ctl_elem_info *uinfo) | ||
1154 | { | ||
1155 | int index,index2; | ||
1156 | int ret_val = -1; | ||
1157 | |||
1158 | |||
1159 | for (index = 0; index < ARRAY_SIZE(main44_MUX_controls); index++) { | ||
1160 | if (strstr(kcontrol->id.name, main44_MUX_control_names[index])) | ||
1161 | break; | ||
1162 | } | ||
1163 | if (index < ARRAY_SIZE(main44_MUX_controls)) | ||
1164 | { | ||
1165 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1166 | uinfo->count = 1; | ||
1167 | uinfo->value.integer.min = MIN_MUX_CTRL; | ||
1168 | uinfo->value.integer.max = MAX_MUX_CTRL; | ||
1169 | ret_val = 0; | ||
1170 | } | ||
1171 | |||
1172 | #if 1 | ||
1173 | else{ | ||
1174 | printk(" The second rate kcontrol id name is====== %s\n",kcontrol->id.name); | ||
1175 | |||
1176 | |||
1177 | for (index2 = 0; index < ARRAY_SIZE(base_speaker_SRS_MUX_controls); index2++) { | ||
1178 | if (strstr(kcontrol->id.name, base_speaker_SRS_MUX_control_names[index2])) | ||
1179 | break; | ||
1180 | } | ||
1181 | if (index < ARRAY_SIZE(base_speaker_SRS_MUX_controls)) | ||
1182 | { | ||
1183 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1184 | uinfo->count = 1; | ||
1185 | uinfo->value.integer.min = MIN_MUX_CTRL; | ||
1186 | uinfo->value.integer.max = MAX_MUX_CTRL; | ||
1187 | ret_val = 0; | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | #endif | ||
1192 | |||
1193 | return ret_val; | ||
1194 | } | ||
1195 | |||
1196 | /* | ||
1197 | *---------------------------------------------------------------------------- | ||
1198 | * Function : __new_control_get_minidsp_mux | ||
1199 | * | ||
1200 | * Purpose : get routine for mux control amixer kcontrols, | ||
1201 | * read current register values to user. | ||
1202 | * Used for for mini dsp 'MUX control' amixer controls. | ||
1203 | *---------------------------------------------------------------------------- | ||
1204 | */ | ||
1205 | static int __new_control_get_minidsp_mux(struct snd_kcontrol *kcontrol, | ||
1206 | struct snd_ctl_elem_value *ucontrol) | ||
1207 | { | ||
1208 | |||
1209 | ucontrol->value.integer.value[0] = kcontrol->private_value; | ||
1210 | return 0; | ||
1211 | } | ||
1212 | |||
1213 | /* | ||
1214 | *---------------------------------------------------------------------------- | ||
1215 | * Function : __new_control_put_minidsp_mux | ||
1216 | * | ||
1217 | * Purpose : put routine for amixer kcontrols, write user values to registers | ||
1218 | * values. Used for for mini dsp 'MUX control' amixer controls. | ||
1219 | *---------------------------------------------------------------------------- | ||
1220 | */ | ||
1221 | static int __new_control_put_minidsp_mux(struct snd_kcontrol *kcontrol, | ||
1222 | struct snd_ctl_elem_value *ucontrol) | ||
1223 | { | ||
1224 | u8 data[MUX_CTRL_REG_SIZE + 1]; | ||
1225 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1226 | int index = 1; | ||
1227 | int user_value = ucontrol->value.integer.value[0]; | ||
1228 | struct i2c_client *i2c; | ||
1229 | u8 value[2], swap_reg_pre, swap_reg_post; | ||
1230 | u8 page; | ||
1231 | int ret_val = -1, array_size; | ||
1232 | control *array; | ||
1233 | char **array_names; | ||
1234 | char *control_name, *control_name1, *control_name2; | ||
1235 | struct aic3262_priv *aic326x = snd_soc_codec_get_drvdata(codec); | ||
1236 | i2c = codec->control_data; | ||
1237 | |||
1238 | |||
1239 | |||
1240 | if (aic326x->process_flow == 0) { | ||
1241 | DBG("#the current process flow is %d", aic326x->process_flow); | ||
1242 | array = main44_MUX_controls; | ||
1243 | array_size = ARRAY_SIZE(main44_MUX_controls); | ||
1244 | array_names = main44_MUX_control_names; | ||
1245 | control_name = "Stereo_Mux_TwoToOne_1"; | ||
1246 | control_name1 = "Mono_Mux_1_1"; | ||
1247 | } | ||
1248 | |||
1249 | #if 0 | ||
1250 | |||
1251 | /* Configure only for process flow 1 controls */ | ||
1252 | if (strcmp(kcontrol->id.name, control_name) && | ||
1253 | strcmp(kcontrol->id.name, control_name1)) | ||
1254 | return 0; | ||
1255 | } else { | ||
1256 | array = Second_Rate_MUX_controls; | ||
1257 | array_size = ARRAY_SIZE(Second_Rate_MUX_controls); | ||
1258 | array_names = Second_Rate_MUX_control_names; | ||
1259 | control_name = "Stereo_Mux_TwoToOne_1_Second"; | ||
1260 | control_name1 = "Mono_Mux_1_Second"; | ||
1261 | control_name2 = "Mono_Mux_4_Second"; | ||
1262 | |||
1263 | /* Configure only for process flow 2 controls */ | ||
1264 | if (strcmp(kcontrol->id.name, control_name1) && | ||
1265 | strcmp(kcontrol->id.name, control_name2)) | ||
1266 | return 0; | ||
1267 | } | ||
1268 | |||
1269 | #endif | ||
1270 | |||
1271 | page = array[index].control_page; | ||
1272 | |||
1273 | DBG("#user value = 0x%x\n", user_value); | ||
1274 | for (index = 0; index < array_size; index++) { | ||
1275 | if (strstr(kcontrol->id.name, array_names[index])) | ||
1276 | break; | ||
1277 | } | ||
1278 | if (index < array_size) { | ||
1279 | DBG(KERN_INFO "#Index %d Changing to Page %d\n", index, | ||
1280 | array[index].control_page); | ||
1281 | |||
1282 | aic3262_change_book(codec, | ||
1283 | array[index].control_book); | ||
1284 | aic3262_change_page(codec, | ||
1285 | array[index].control_page); | ||
1286 | |||
1287 | if (!strcmp(array_names[index], control_name)) { | ||
1288 | if (user_value > 0) { | ||
1289 | data[1] = 0x00; | ||
1290 | data[2] = 0x00; | ||
1291 | data[3] = 0x00; | ||
1292 | } else { | ||
1293 | data[1] = 0xFF; | ||
1294 | data[2] = 0xFf; | ||
1295 | data[3] = 0xFF; | ||
1296 | } | ||
1297 | } else { | ||
1298 | if (user_value > 0) { | ||
1299 | data[1] = | ||
1300 | (u8) ((user_value >> 16) & | ||
1301 | AIC3262_8BITS_MASK); | ||
1302 | data[2] = | ||
1303 | (u8) ((user_value >> 8) & | ||
1304 | AIC3262_8BITS_MASK); | ||
1305 | data[3] = | ||
1306 | (u8)((user_value) & AIC3262_8BITS_MASK); | ||
1307 | } | ||
1308 | } | ||
1309 | /* start register address */ | ||
1310 | data[0] = array[index].control_base; | ||
1311 | |||
1312 | DBG(KERN_INFO | ||
1313 | "#Writing %d %d %d \r\n", data[0], data[1], data[2]); | ||
1314 | |||
1315 | ret_val = i2c_master_send(i2c, data, MUX_CTRL_REG_SIZE + 1); | ||
1316 | |||
1317 | if (ret_val != MUX_CTRL_REG_SIZE + 1) | ||
1318 | printk(KERN_ERR "i2c_master_send transfer failed\n"); | ||
1319 | else { | ||
1320 | /* store the current level */ | ||
1321 | kcontrol->private_value = user_value; | ||
1322 | ret_val = 0; | ||
1323 | /* Enable adaptive filtering for ADC/DAC */ | ||
1324 | } | ||
1325 | |||
1326 | /* Perform a BUFFER SWAP Command. Check if we are currently not | ||
1327 | * in Page 8, if so, swap to Page 8 first | ||
1328 | */ | ||
1329 | |||
1330 | value[0] = 1; | ||
1331 | |||
1332 | if (i2c_master_send(i2c, value, 1) != 1) | ||
1333 | printk(KERN_ERR "Can not write register address\n"); | ||
1334 | |||
1335 | /* Read the Value of the Page 8 Register 1 which controls the | ||
1336 | Adaptive Switching Mode */ | ||
1337 | if (i2c_master_recv(i2c, value, 1) != 1) | ||
1338 | printk(KERN_ERR "Can not read codec registers\n"); | ||
1339 | |||
1340 | swap_reg_pre = value[0]; | ||
1341 | /* Write the Register bit updates */ | ||
1342 | value[1] = value[0] | 1; | ||
1343 | value[0] = 1; | ||
1344 | |||
1345 | if (i2c_master_send(i2c, value, 2) != 2) | ||
1346 | printk(KERN_ERR "Can not write register address\n"); | ||
1347 | |||
1348 | value[0] = 1; | ||
1349 | /* verify buffer swap */ | ||
1350 | if (i2c_master_send(i2c, value, 1) != 1) | ||
1351 | printk(KERN_ERR "Can not write register address\n"); | ||
1352 | |||
1353 | /* Read the Value of the Page 8 Register 1 which controls the | ||
1354 | Adaptive Switching Mode */ | ||
1355 | if (i2c_master_recv(i2c, &swap_reg_post, 1) != 1) | ||
1356 | printk(KERN_ERR "Can not read codec registers\n"); | ||
1357 | |||
1358 | if ((swap_reg_pre == 4 && swap_reg_post == 6) | ||
1359 | || (swap_reg_pre == 6 && swap_reg_post == 4)) | ||
1360 | DBG("Buffer swap success\n"); | ||
1361 | else | ||
1362 | printk(KERN_ERR | ||
1363 | "Buffer swap...FAILED\nswap_reg_pre=%x, \ | ||
1364 | swap_reg_post=%x\n", swap_reg_pre, swap_reg_post); | ||
1365 | |||
1366 | } | ||
1367 | /* update the new buffer value in the old, just swapped out buffer */ | ||
1368 | aic3262_change_book(codec, array[index].control_book); | ||
1369 | aic3262_change_page(codec, array[index].control_page); | ||
1370 | ret_val = i2c_master_send(i2c, data, MUX_CTRL_REG_SIZE + 1); | ||
1371 | ret_val = 0; | ||
1372 | |||
1373 | aic3262_change_book(codec, 0); | ||
1374 | return ret_val; | ||
1375 | } | ||
1376 | |||
1377 | /* | ||
1378 | *---------------------------------------------------------------------------- | ||
1379 | * Function : minidsp_mux_ctrl_mixer_controls | ||
1380 | * | ||
1381 | * Purpose : Add amixer kcontrols for mini dsp mux controls, | ||
1382 | *---------------------------------------------------------------------------- | ||
1383 | */ | ||
1384 | static int minidsp_mux_ctrl_mixer_controls(struct snd_soc_codec *codec, | ||
1385 | int size, control *cntl, | ||
1386 | char **name) | ||
1387 | { | ||
1388 | int i, err; | ||
1389 | int val1; | ||
1390 | |||
1391 | printk("%d mixer controls for mini dsp MUX\n", size); | ||
1392 | if (size) { | ||
1393 | for (i = 0; i < size; i++) { | ||
1394 | |||
1395 | snd_mux_controls[i].name = name[i]; | ||
1396 | snd_mux_controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1397 | snd_mux_controls[i].access = | ||
1398 | SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1399 | snd_mux_controls[i].info = | ||
1400 | __new_control_info_minidsp_mux; | ||
1401 | snd_mux_controls[i].get = __new_control_get_minidsp_mux; | ||
1402 | snd_mux_controls[i].put = __new_control_put_minidsp_mux; | ||
1403 | /* | ||
1404 | * TBD: read volume reg and update the index number | ||
1405 | */ | ||
1406 | aic3262_change_book(codec, cntl[i].control_book); | ||
1407 | aic3262_change_page(codec, cntl[i].control_page); | ||
1408 | val1 = i2c_smbus_read_byte_data(codec->control_data, | ||
1409 | cntl[i].control_base); | ||
1410 | DBG(KERN_INFO "Control data %x\n", val1); | ||
1411 | /* | ||
1412 | if( val1 >= 0 ) | ||
1413 | snd_mux_controls[i].private_value = val1; | ||
1414 | else | ||
1415 | snd_mux_controls[i].private_value = 0; | ||
1416 | */ | ||
1417 | DBG(KERN_INFO | ||
1418 | "the value of amixer control mux=%d", val1); | ||
1419 | if (val1 >= 0 && val1 != 255) | ||
1420 | snd_mux_controls[i].private_value = val1; | ||
1421 | else | ||
1422 | snd_mux_controls[i].private_value = 0; | ||
1423 | |||
1424 | snd_mux_controls[i].count = 0; | ||
1425 | |||
1426 | err = snd_ctl_add(codec->card->snd_card, | ||
1427 | snd_ctl_new1(&snd_mux_controls[i], | ||
1428 | codec)); | ||
1429 | if (err < 0) | ||
1430 | printk(KERN_ERR | ||
1431 | "%s:Invalid control %s\n", __FILE__, | ||
1432 | snd_mux_controls[i].name); | ||
1433 | } | ||
1434 | } | ||
1435 | return 0; | ||
1436 | } | ||
1437 | |||
1438 | /*------------------------- Volume Controls -----------------------*/ | ||
1439 | static int volume_lite_table[] = { | ||
1440 | |||
1441 | 0x00000D, 0x00000E, 0x00000E, 0x00000F, | ||
1442 | 0x000010, 0x000011, 0x000012, 0x000013, | ||
1443 | 0x000015, 0x000016, 0x000017, 0x000018, | ||
1444 | 0x00001A, 0x00001C, 0x00001D, 0x00001F, | ||
1445 | 0x000021, 0x000023, 0x000025, 0x000027, | ||
1446 | 0x000029, 0x00002C, 0x00002F, 0x000031, | ||
1447 | 0x000034, 0x000037, 0x00003B, 0x00003E, | ||
1448 | 0x000042, 0x000046, 0x00004A, 0x00004F, | ||
1449 | 0x000053, 0x000058, 0x00005D, 0x000063, | ||
1450 | 0x000069, 0x00006F, 0x000076, 0x00007D, | ||
1451 | 0x000084, 0x00008C, 0x000094, 0x00009D, | ||
1452 | 0x0000A6, 0x0000B0, 0x0000BB, 0x0000C6, | ||
1453 | 0x0000D2, 0x0000DE, 0x0000EB, 0x0000F9, | ||
1454 | 0x000108, 0x000118, 0x000128, 0x00013A, | ||
1455 | 0x00014D, 0x000160, 0x000175, 0x00018B, | ||
1456 | 0x0001A3, 0x0001BC, 0x0001D6, 0x0001F2, | ||
1457 | 0x000210, 0x00022F, 0x000250, 0x000273, | ||
1458 | 0x000298, 0x0002C0, 0x0002E9, 0x000316, | ||
1459 | 0x000344, 0x000376, 0x0003AA, 0x0003E2, | ||
1460 | 0x00041D, 0x00045B, 0x00049E, 0x0004E4, | ||
1461 | 0x00052E, 0x00057C, 0x0005D0, 0x000628, | ||
1462 | 0x000685, 0x0006E8, 0x000751, 0x0007C0, | ||
1463 | 0x000836, 0x0008B2, 0x000936, 0x0009C2, | ||
1464 | 0x000A56, 0x000AF3, 0x000B99, 0x000C49, | ||
1465 | 0x000D03, 0x000DC9, 0x000E9A, 0x000F77, | ||
1466 | 0x001062, 0x00115A, 0x001262, 0x001378, | ||
1467 | 0x0014A0, 0x0015D9, 0x001724, 0x001883, | ||
1468 | 0x0019F7, 0x001B81, 0x001D22, 0x001EDC, | ||
1469 | 0x0020B0, 0x0022A0, 0x0024AD, 0x0026DA, | ||
1470 | 0x002927, 0x002B97, 0x002E2D, 0x0030E9, | ||
1471 | 0x0033CF, 0x0036E1, 0x003A21, 0x003D93, | ||
1472 | 0x004139, 0x004517, 0x00492F, 0x004D85, | ||
1473 | 0x00521D, 0x0056FA, 0x005C22, 0x006197, | ||
1474 | 0x006760, 0x006D80, 0x0073FD, 0x007ADC, | ||
1475 | 0x008224, 0x0089DA, 0x009205, 0x009AAC, | ||
1476 | 0x00A3D7, 0x00B7D4, 0x00AD8C, 0x00C2B9, | ||
1477 | 0x00CE43, 0x00DA7B, 0x00E76E, 0x00F524, | ||
1478 | 0x0103AB, 0x01130E, 0x01235A, 0x01349D, | ||
1479 | 0x0146E7, 0x015A46, 0x016ECA, 0x018486, | ||
1480 | 0x019B8C, 0x01B3EE, 0x01CDC3, 0x01E920, | ||
1481 | 0x02061B, 0x0224CE, 0x024553, 0x0267C5, | ||
1482 | 0x028C42, 0x02B2E8, 0x02DBD8, 0x030736, | ||
1483 | 0x033525, 0x0365CD, 0x039957, 0x03CFEE, | ||
1484 | 0x0409C2, 0x044703, 0x0487E5, 0x04CCA0, | ||
1485 | 0x05156D, 0x05628A, 0x05B439, 0x060ABF, | ||
1486 | 0x066666, 0x06C77B, 0x072E50, 0x079B3D, | ||
1487 | 0x080E9F, 0x0888D7, 0x090A4D, 0x09936E, | ||
1488 | 0x0A24B0, 0x0ABE8D, 0x0B6188, 0x0C0E2B, | ||
1489 | 0x0CC509, 0x0D86BD, 0x0E53EB, 0x0F2D42, | ||
1490 | 0x101379, 0x110754, 0x1209A3, 0x131B40, | ||
1491 | 0x143D13, 0x157012, 0x16B543, 0x180DB8, | ||
1492 | 0x197A96, 0x1AFD13, 0x1C9676, 0x1E481C, | ||
1493 | 0x201373, 0x21FA02, 0x23FD66, 0x261F54, | ||
1494 | 0x28619A, 0x2AC625, 0x2D4EFB, 0x2FFE44, | ||
1495 | 0x32D646, 0x35D96B, 0x390A41, 0x3C6B7E, | ||
1496 | 0x400000, 0x43CAD0, 0x47CF26, 0x4C106B, | ||
1497 | 0x50923B, 0x55586A, 0x5A6703, 0x5FC253, | ||
1498 | 0x656EE3, 0x6B7186, 0x71CF54, 0x788DB4, | ||
1499 | 0x7FB260, | ||
1500 | }; | ||
1501 | |||
1502 | static struct snd_kcontrol_new snd_vol_controls[MAX_VOLUME_CONTROLS]; | ||
1503 | /* | ||
1504 | *---------------------------------------------------------------------------- | ||
1505 | * Function : __new_control_info_main44_minidsp_volume | ||
1506 | * Purpose : info routine for volumeLite amixer kcontrols | ||
1507 | *---------------------------------------------------------------------------- | ||
1508 | */ | ||
1509 | |||
1510 | static int | ||
1511 | __new_control_info_minidsp_volume(struct snd_kcontrol *kcontrol, | ||
1512 | struct snd_ctl_elem_info *uinfo) | ||
1513 | { | ||
1514 | int index, index8; | ||
1515 | int ret_val = -1; | ||
1516 | |||
1517 | for (index = 0; index < ARRAY_SIZE(main44_VOLUME_controls); index++) { | ||
1518 | if (strstr | ||
1519 | (kcontrol->id.name, main44_VOLUME_control_names[index])) | ||
1520 | break; | ||
1521 | } | ||
1522 | |||
1523 | for (index8 = 0; index8 < ARRAY_SIZE(base_speaker_SRS_VOLUME_controls); | ||
1524 | index8++) { | ||
1525 | if (strstr | ||
1526 | (kcontrol->id.name, | ||
1527 | base_speaker_SRS_VOLUME_control_names[index])) | ||
1528 | break; | ||
1529 | } | ||
1530 | |||
1531 | if ((index < ARRAY_SIZE(main44_VOLUME_controls)) | ||
1532 | |||
1533 | || (index8 < ARRAY_SIZE(base_speaker_SRS_VOLUME_controls))) { | ||
1534 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1535 | uinfo->count = 1; | ||
1536 | uinfo->value.integer.min = MIN_VOLUME; | ||
1537 | uinfo->value.integer.max = MAX_VOLUME; | ||
1538 | ret_val = 0; | ||
1539 | } | ||
1540 | return ret_val; | ||
1541 | } | ||
1542 | |||
1543 | /* | ||
1544 | *---------------------------------------------------------------------------- | ||
1545 | * Function : __new_control_get_main44_minidsp_vol | ||
1546 | * Purpose : get routine for amixer kcontrols, read current register | ||
1547 | * values. Used for for mini dsp 'VolumeLite' amixer controls. | ||
1548 | *---------------------------------------------------------------------------- | ||
1549 | */ | ||
1550 | static int | ||
1551 | __new_control_get_minidsp_volume(struct snd_kcontrol *kcontrol, | ||
1552 | struct snd_ctl_elem_value *ucontrol) | ||
1553 | { | ||
1554 | ucontrol->value.integer.value[0] = kcontrol->private_value; | ||
1555 | return 0; | ||
1556 | } | ||
1557 | |||
1558 | /* | ||
1559 | *---------------------------------------------------------------------------- | ||
1560 | * Function : __new_control_put_main44_minidsp_volume | ||
1561 | * Purpose : put routine for amixer kcontrols, write user values to registers | ||
1562 | * values. Used for for mini dsp 'VolumeLite' amixer controls. | ||
1563 | *---------------------------------------------------------------------------- | ||
1564 | */ | ||
1565 | static int | ||
1566 | __new_control_put_minidsp_volume(struct snd_kcontrol *kcontrol, | ||
1567 | struct snd_ctl_elem_value *ucontrol) | ||
1568 | { | ||
1569 | u8 data[4]; | ||
1570 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1571 | int user_value = ucontrol->value.integer.value[0]; | ||
1572 | struct i2c_client *i2c = codec->control_data; | ||
1573 | int ret_val = -1; | ||
1574 | int coeff; | ||
1575 | u8 value[2], swap_reg_pre, swap_reg_post; | ||
1576 | struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec); | ||
1577 | |||
1578 | control *volume_controls = NULL; | ||
1579 | printk(KERN_INFO "user value = 0x%x\n", user_value); | ||
1580 | |||
1581 | if (aic3262->process_flow == 0) | ||
1582 | volume_controls = main44_VOLUME_controls; | ||
1583 | |||
1584 | else | ||
1585 | volume_controls = base_speaker_SRS_VOLUME_controls; | ||
1586 | |||
1587 | |||
1588 | aic3262_change_book(codec, volume_controls->control_book); | ||
1589 | aic3262_change_page(codec, volume_controls->control_page); | ||
1590 | |||
1591 | coeff = volume_lite_table[user_value << 1]; | ||
1592 | |||
1593 | data[1] = (u8) ((coeff >> 16) & AIC3262_8BITS_MASK); | ||
1594 | data[2] = (u8) ((coeff >> 8) & AIC3262_8BITS_MASK); | ||
1595 | data[3] = (u8) ((coeff) & AIC3262_8BITS_MASK); | ||
1596 | |||
1597 | /* Start register address */ | ||
1598 | data[0] = volume_controls->control_base; | ||
1599 | ret_val = i2c_master_send(i2c, data, VOLUME_REG_SIZE + 1); | ||
1600 | if (ret_val != VOLUME_REG_SIZE + 1) | ||
1601 | printk(KERN_ERR "i2c_master_send transfer failed\n"); | ||
1602 | else { | ||
1603 | /* store the current level */ | ||
1604 | kcontrol->private_value = user_value; | ||
1605 | ret_val = 0; | ||
1606 | } | ||
1607 | /* Initiate buffer swap */ | ||
1608 | value[0] = 1; | ||
1609 | |||
1610 | if (i2c_master_send(i2c, value, 1) != 1) | ||
1611 | printk(KERN_ERR "Can not write register address\n"); | ||
1612 | |||
1613 | /* Read the Value of the Page 8 Register 1 which controls the | ||
1614 | Adaptive Switching Mode */ | ||
1615 | if (i2c_master_recv(i2c, value, 1) != 1) | ||
1616 | printk(KERN_ERR "Can not read codec registers\n"); | ||
1617 | |||
1618 | swap_reg_pre = value[0]; | ||
1619 | /* Write the Register bit updates */ | ||
1620 | value[1] = value[0] | 1; | ||
1621 | value[0] = 1; | ||
1622 | if (i2c_master_send(i2c, value, 2) != 2) | ||
1623 | printk(KERN_ERR "Can not write register address\n"); | ||
1624 | |||
1625 | value[0] = 1; | ||
1626 | /* verify buffer swap */ | ||
1627 | if (i2c_master_send(i2c, value, 1) != 1) | ||
1628 | printk(KERN_ERR "Can not write register address\n"); | ||
1629 | |||
1630 | /* Read the Value of the Page 8 Register 1 which controls the | ||
1631 | Adaptive Switching Mode */ | ||
1632 | if (i2c_master_recv(i2c, &swap_reg_post, 1) != 1) | ||
1633 | printk(KERN_ERR "Can not read codec registers\n"); | ||
1634 | |||
1635 | if ((swap_reg_pre == 4 && swap_reg_post == 6) | ||
1636 | || (swap_reg_pre == 6 && swap_reg_post == 4)) | ||
1637 | DBG("Buffer swap success\n"); | ||
1638 | else | ||
1639 | DBG("Buffer swap...FAILED\nswap_reg_pre=%x, swap_reg_post=%x\n", | ||
1640 | swap_reg_pre, swap_reg_post); | ||
1641 | |||
1642 | /* update the new buffer value in the old, just swapped out buffer */ | ||
1643 | aic3262_change_book(codec, volume_controls->control_book); | ||
1644 | aic3262_change_page(codec, volume_controls->control_page); | ||
1645 | i2c_master_send(i2c, data, MUX_CTRL_REG_SIZE + 1); | ||
1646 | |||
1647 | aic3262_change_book(codec, 0); | ||
1648 | |||
1649 | return 0; | ||
1650 | } | ||
1651 | |||
1652 | /* | ||
1653 | *---------------------------------------------------------------------------- | ||
1654 | * Function : minidsp_volume_main44_mixer_controls | ||
1655 | * Purpose : Add amixer kcontrols for mini dsp volume Lite controls, | ||
1656 | *---------------------------------------------------------------------------- | ||
1657 | */ | ||
1658 | static int minidsp_volume_mixer_controls(struct snd_soc_codec *codec) | ||
1659 | { | ||
1660 | int i, err, no_volume_controls; | ||
1661 | static char volume_control_name[MAX_VOLUME_CONTROLS][40]; | ||
1662 | |||
1663 | /* ADD first process volume controls */ | ||
1664 | no_volume_controls = ARRAY_SIZE(main44_VOLUME_controls); | ||
1665 | |||
1666 | printk(KERN_INFO " %d mixer controls for mini dsp 'volumeLite'\n", | ||
1667 | no_volume_controls); | ||
1668 | |||
1669 | if (no_volume_controls) { | ||
1670 | |||
1671 | for (i = 0; i < no_volume_controls; i++) { | ||
1672 | strcpy(volume_control_name[i], | ||
1673 | main44_VOLUME_control_names[i]); | ||
1674 | strcat(volume_control_name[i], VOLUME_KCONTROL_NAME); | ||
1675 | |||
1676 | printk(KERN_ERR "Volume controls: %s\n", | ||
1677 | volume_control_name[i]); | ||
1678 | |||
1679 | snd_vol_controls[i].name = volume_control_name[i]; | ||
1680 | snd_vol_controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1681 | snd_vol_controls[i].access = | ||
1682 | SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1683 | snd_vol_controls[i].info = | ||
1684 | __new_control_info_minidsp_volume; | ||
1685 | snd_vol_controls[i].get = | ||
1686 | __new_control_get_minidsp_volume; | ||
1687 | snd_vol_controls[i].put = | ||
1688 | __new_control_put_minidsp_volume; | ||
1689 | /* | ||
1690 | * TBD: read volume reg and update the index number | ||
1691 | */ | ||
1692 | snd_vol_controls[i].private_value = 0; | ||
1693 | snd_vol_controls[i].count = 0; | ||
1694 | |||
1695 | err = snd_ctl_add(codec->card->snd_card, | ||
1696 | snd_ctl_new1(&snd_vol_controls[i], | ||
1697 | codec)); | ||
1698 | if (err < 0) { | ||
1699 | printk(KERN_ERR | ||
1700 | "%s:Invalid control %s\n", __FILE__, | ||
1701 | snd_vol_controls[i].name); | ||
1702 | } | ||
1703 | } | ||
1704 | } | ||
1705 | |||
1706 | |||
1707 | /* ADD second process volume controls */ | ||
1708 | no_volume_controls = ARRAY_SIZE(base_speaker_SRS_VOLUME_controls); | ||
1709 | |||
1710 | printk(KERN_ERR " %d mixer controls for mini dsp 'volumeLite'\n", | ||
1711 | no_volume_controls); | ||
1712 | |||
1713 | if (no_volume_controls) { | ||
1714 | |||
1715 | for (i = 0; i < no_volume_controls; i++) { | ||
1716 | strcpy(volume_control_name[i], | ||
1717 | base_speaker_SRS_VOLUME_control_names[i]); | ||
1718 | strcat(volume_control_name[i], VOLUME_KCONTROL_NAME); | ||
1719 | |||
1720 | printk(KERN_ERR "Volume controls: %s\n", | ||
1721 | volume_control_name[i]); | ||
1722 | |||
1723 | snd_vol_controls[i].name = volume_control_name[i]; | ||
1724 | snd_vol_controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1725 | snd_vol_controls[i].access = | ||
1726 | SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
1727 | snd_vol_controls[i].info = | ||
1728 | __new_control_info_minidsp_volume; | ||
1729 | snd_vol_controls[i].get = | ||
1730 | __new_control_get_minidsp_volume; | ||
1731 | snd_vol_controls[i].put = | ||
1732 | __new_control_put_minidsp_volume; | ||
1733 | /* | ||
1734 | * TBD: read volume reg and update the index number | ||
1735 | */ | ||
1736 | snd_vol_controls[i].private_value = 0; | ||
1737 | snd_vol_controls[i].count = 0; | ||
1738 | |||
1739 | err = snd_ctl_add(codec->card->snd_card, | ||
1740 | snd_ctl_new1(&snd_vol_controls[i], | ||
1741 | codec)); | ||
1742 | if (err < 0) { | ||
1743 | printk(KERN_ERR | ||
1744 | "%s:Invalid control %s\n", __FILE__, | ||
1745 | snd_vol_controls[i].name); | ||
1746 | } | ||
1747 | } | ||
1748 | } | ||
1749 | |||
1750 | return 0; | ||
1751 | } | ||
1752 | |||
1753 | /* | ||
1754 | *-------------------------------------------------------------------------- | ||
1755 | * Function : aic3262_add_minidsp_controls | ||
1756 | * Purpose : Configures the AMIXER Control Interfaces that can be exercised by | ||
1757 | * the user at run-time. Utilizes the the snd_adaptive_controls[] | ||
1758 | * array to specify two run-time controls. | ||
1759 | *--------------------------------------------------------------------------- | ||
1760 | */ | ||
1761 | int aic3262_add_minidsp_controls(struct snd_soc_codec *codec) | ||
1762 | { | ||
1763 | #ifdef ADD_MINI_DSP_CONTROLS | ||
1764 | int i, err, no_mux_controls,no_mux_controls1; | ||
1765 | /* add mode k control */ | ||
1766 | for (i = 0; i < ARRAY_SIZE(aic3262_minidsp_controls); i++) { | ||
1767 | err = snd_ctl_add(codec->card->snd_card, | ||
1768 | snd_ctl_new1(&aic3262_minidsp_controls[i], codec)); | ||
1769 | if (err < 0) { | ||
1770 | printk(KERN_ERR "Invalid control\n"); | ||
1771 | return err; | ||
1772 | } | ||
1773 | } | ||
1774 | |||
1775 | |||
1776 | /* add mux controls */ | ||
1777 | no_mux_controls = ARRAY_SIZE(main44_MUX_controls); | ||
1778 | minidsp_mux_ctrl_mixer_controls(codec, no_mux_controls, | ||
1779 | main44_MUX_controls, main44_MUX_control_names); | ||
1780 | |||
1781 | |||
1782 | no_mux_controls1 = ARRAY_SIZE(base_speaker_SRS_MUX_controls); | ||
1783 | minidsp_mux_ctrl_mixer_controls(codec, no_mux_controls1, | ||
1784 | base_speaker_SRS_MUX_controls, base_speaker_SRS_MUX_control_names); | ||
1785 | |||
1786 | |||
1787 | /* add volume controls*/ | ||
1788 | minidsp_volume_mixer_controls(codec); | ||
1789 | #endif /* ADD_MINI_DSP_CONTROLS */ | ||
1790 | return 0; | ||
1791 | } | ||
1792 | |||
1793 | MODULE_DESCRIPTION("ASoC TLV320AIC3262 miniDSP driver"); | ||
1794 | MODULE_AUTHOR("Y Preetam Sashank Reddy <preetam@mistralsolutions.com>"); | ||
1795 | MODULE_LICENSE("GPL"); | ||
1796 | #endif /* End of CONFIG_MINI_DSP */ | ||