tizen 2.4 release
[kernel/u-boot-tm1.git] / drivers / sound / dai / vbc_r2p0.c
1 /*
2  * sound/soc/sprd/dai/vbc/vbc.c
3  *
4  * SPRD SoC CPU-DAI -- SpreadTrum SOC DAI with EQ&ALC and some loop.
5  *
6  * Copyright (C) 2012 SpreadTrum Ltd.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17 #define pr_fmt(fmt) "[audio: vbc ] " fmt
18
19 #include <common.h>
20 #include <errno.h>
21 #include <asm/atomic.h>
22 #include <ubi_uboot.h>
23
24 #include "vbc_r2p0.h"
25 #include "../sound_common.h"
26
27 #ifdef CONFIG_SPRD_AUDIO_DEBUG
28 #define vbc_dbg pr_info
29 #else
30 #define vbc_dbg(...)
31 #endif
32
33 #define FUN_REG(f) ((unsigned short)(-((f) + 1)))
34
35 #define DEFINE_SPINLOCK(...)
36 #define DEFINE_MUTEX(...)
37
38 #define VBC_DG_VAL_MAX (0x7F)
39
40 struct vbc_fw_header {
41         char magic[VBC_EQ_FIRMWARE_MAGIC_LEN];
42         u32 profile_version;
43         u32 num_profile;
44 };
45
46 struct vbc_eq_profile {
47         char magic[VBC_EQ_FIRMWARE_MAGIC_LEN];
48         char name[VBC_EQ_PROFILE_NAME_MAX];
49         /* TODO */
50         u32 effect_paras[VBC_EFFECT_PARAS_LEN];
51 };
52
53 static const u32 vbc_eq_profile_default[VBC_EFFECT_PARAS_LEN] = {
54 /* TODO the default register value */
55         0x00000000,             /*  DAPATCHCTL      */
56         0x00001818,             /*  DADGCTL         */
57         0x0000007F,             /*  DAHPCTL         */
58         0x00000000,             /*  DAALCCTL0       */
59         0x00000000,             /*  DAALCCTL1       */
60         0x00000000,             /*  DAALCCTL2       */
61         0x00000000,             /*  DAALCCTL3       */
62         0x00000000,             /*  DAALCCTL4       */
63         0x00000000,             /*  DAALCCTL5       */
64         0x00000000,             /*  DAALCCTL6       */
65         0x00000000,             /*  DAALCCTL7       */
66         0x00000000,             /*  DAALCCTL8       */
67         0x00000000,             /*  DAALCCTL9       */
68         0x00000000,             /*  DAALCCTL10      */
69         0x00000183,             /*  STCTL0          */
70         0x00000183,             /*  STCTL1          */
71         0x00000000,             /*  ADPATCHCTL      */
72         0x00001818,             /*  ADDG01CTL         */
73         0x00001818,             /*  ADDG23CTL         */
74         0x00000000,             /*  ADHPCTL         */
75         0x00000000,             /*  ADCSRCCTL         */
76         0x00000000,             /*  DACSRCCTL         */
77         0x00000000,             /*  MIXERCTL         */
78         0x00000000,             /*  VBNGCVTHD        */
79         0x00000000,             /*  VBNGCTTHD          */
80         0x00000000,             /*  VBNGCTL         */
81         0x00000000,             /*  HPCOEF0_H         */
82 };
83
84 struct vbc_equ {
85         struct device *dev;
86         int is_active;
87         int is_loaded;
88         int is_loading;
89         int now_profile;
90         struct vbc_fw_header hdr;
91         struct vbc_eq_profile *data;
92         void (*vbc_eq_apply) (void *data);
93 };
94
95 typedef int (*vbc_dma_set) (int enable);
96 typedef int (*vbc_dg_set) (int enable, int dg);
97 DEFINE_MUTEX(vbc_mutex);
98 struct vbc_priv {
99         vbc_dma_set dma_set[2];
100
101         int (*arch_enable) (int chan);
102         int (*arch_disable) (int chan);
103         int is_open;
104         int is_active;
105         int used_chan_count;
106         int dg_switch[2];
107         int dg_val[2];
108         vbc_dg_set dg_set[2];
109 };
110
111 DEFINE_MUTEX(load_mutex);
112 static struct vbc_equ vbc_eq_setting = { 0 };
113
114 static void vbc_eq_try_apply(void);
115 static struct vbc_priv vbc[3];
116
117 DEFINE_SPINLOCK(vbc_lock);
118 /* local register setting */
119 static int vbc_reg_write(int reg, int val, int mask)
120 {
121         int tmp, ret;
122         spin_lock(&vbc_lock);
123         tmp = __raw_readl(reg);
124         ret = tmp;
125         tmp &= ~(mask);
126         tmp |= val & mask;
127         __raw_writel(tmp, reg);
128         spin_unlock(&vbc_lock);
129         return ret & (mask);
130 }
131
132 static inline int vbc_reg_read(int reg)
133 {
134         int tmp;
135         tmp = __raw_readl(reg);
136         return tmp;
137 }
138
139 static int vbc_set_buffer_size(int ad_buffer_size, int da_buffer_size,
140                                int ad23_buffer_size)
141 {
142         int val = vbc_reg_read(VBBUFFSIZE);
143         WARN_ON(ad_buffer_size > VBC_FIFO_FRAME_NUM);
144         WARN_ON(da_buffer_size > VBC_FIFO_FRAME_NUM);
145         WARN_ON(ad23_buffer_size > VBC_FIFO_FRAME_NUM);
146         if ((ad_buffer_size > 0)
147             && (ad_buffer_size <= VBC_FIFO_FRAME_NUM)) {
148                 val &= ~(VBADBUFFERSIZE_MASK);
149                 val |= (((ad_buffer_size - 1) << VBADBUFFERSIZE_SHIFT)
150                         & VBADBUFFERSIZE_MASK);
151         }
152         if ((da_buffer_size > 0)
153             && (da_buffer_size <= VBC_FIFO_FRAME_NUM)) {
154                 val &= ~(VBDABUFFERSIZE_MASK);
155                 val |= (((da_buffer_size - 1) << VBDABUFFERSIZE_SHIFT)
156                         & VBDABUFFERSIZE_MASK);
157         }
158         vbc_reg_write(VBBUFFSIZE, val,
159                       (VBDABUFFERSIZE_MASK | VBADBUFFERSIZE_MASK));
160         if ((ad23_buffer_size > 0)
161             && (ad23_buffer_size <= VBC_FIFO_FRAME_NUM)) {
162                 val &= ~(VBAD23BUFFERSIZE_MASK);
163                 val |= (((ad23_buffer_size - 1) << VBAD23BUFFERSIZE_SHIFT)
164                         & VBAD23BUFFERSIZE_MASK);
165         }
166         vbc_reg_write(VBBUFFAD23, val, VBAD23BUFFERSIZE_MASK);
167         return 0;
168 }
169
170 static inline int vbc_sw_write_buffer(int enable)
171 {
172         /* Software access ping-pong buffer enable when VBENABE bit low */
173         vbc_reg_write(VBDABUFFDTA, ((enable ? 1 : 0) << RAMSW_EN),
174                       (1 << RAMSW_EN));
175         return 0;
176 }
177
178 static inline int vbc_da_enable(int enable, int chan)
179 {
180         vbc_reg_write(VBCHNEN, ((enable ? 1 : 0) << (VBDACHEN_SHIFT + chan)),
181                       (1 << (VBDACHEN_SHIFT + chan)));
182         return 0;
183 }
184
185 static inline int vbc_ad_enable(int enable, int chan)
186 {
187         vbc_reg_write(VBCHNEN, ((enable ? 1 : 0) << (VBADCHEN_SHIFT + chan)),
188                       (1 << (VBADCHEN_SHIFT + chan)));
189         return 0;
190 }
191
192 static inline int vbc_ad23_enable(int enable, int chan)
193 {
194         vbc_reg_write(VBCHNEN, ((enable ? 1 : 0) << (VBAD23CHEN_SHIFT + chan)),
195                       (1 << (VBAD23CHEN_SHIFT + chan)));
196         return 0;
197 }
198
199 static inline int vbc_enable_set(int enable)
200 {
201         vbc_reg_write(VBADBUFFDTA, (0 << VBIIS_LRCK), (1 << VBIIS_LRCK));
202         vbc_reg_write(VBDABUFFDTA, ((enable ? 1 : 0) << VBENABLE),
203                       (1 << VBENABLE));
204         return 0;
205 }
206
207 static inline int vbc_ad0_dma_set(int enable)
208 {
209         vbc_reg_write(VBDABUFFDTA, ((enable ? 1 : 0) << VBAD0DMA_EN),
210                       (1 << VBAD0DMA_EN));
211         return 0;
212 }
213
214 static inline int vbc_ad1_dma_set(int enable)
215 {
216         vbc_reg_write(VBDABUFFDTA, ((enable ? 1 : 0) << VBAD1DMA_EN),
217                       (1 << VBAD1DMA_EN));
218         return 0;
219 }
220
221 static inline int vbc_ad2_dma_set(int enable)
222 {
223         vbc_reg_write(VBADDMA, ((enable ? 1 : 0) << VBAD2DMA_EN),
224                       (1 << VBAD2DMA_EN));
225         return 0;
226 }
227
228 static inline int vbc_ad3_dma_set(int enable)
229 {
230         vbc_reg_write(VBADDMA, ((enable ? 1 : 0) << VBAD3DMA_EN),
231                       (1 << VBAD3DMA_EN));
232         return 0;
233 }
234
235 static inline int vbc_da0_dma_set(int enable)
236 {
237         vbc_reg_write(VBDABUFFDTA, ((enable ? 1 : 0) << VBDA0DMA_EN),
238                       (1 << VBDA0DMA_EN));
239         return 0;
240 }
241
242 static inline int vbc_da1_dma_set(int enable)
243 {
244         vbc_reg_write(VBDABUFFDTA, ((enable ? 1 : 0) << VBDA1DMA_EN),
245                       (1 << VBDA1DMA_EN));
246         return 0;
247 }
248
249 static void vbc_da_buffer_clear(int id)
250 {
251         int i;
252         vbc_reg_write(VBDABUFFDTA, ((id ? 1 : 0) << RAMSW_NUMB),
253                       (1 << RAMSW_NUMB));
254         for (i = 0; i < VBC_FIFO_FRAME_NUM; i++) {
255                 __raw_writel(0, VBDA0);
256                 __raw_writel(0, VBDA1);
257         }
258 }
259
260 static void vbc_da_buffer_clear_all(void)
261 {
262         int i;
263         int ret;
264         int save_enable = 0;
265         ret = arch_audio_vbc_enable();
266         if (ret < 0) {
267                 pr_err("Failed to enable VBC\n");
268         }
269         save_enable |= (ret << 2);
270         for (i = 0; i < 2; i++) {
271                 ret = vbc_da_enable(1, i);
272                 if (ret < 0) {
273                         pr_err("Failed to enable VBC DA%d\n", i);
274                 }
275                 save_enable |= (ret << i);
276         }
277         vbc_sw_write_buffer(true);
278         vbc_set_buffer_size(0, VBC_FIFO_FRAME_NUM, 0);
279         vbc_da_buffer_clear(1); /* clear data buffer 1 */
280         vbc_da_buffer_clear(0); /* clear data buffer 0 */
281         vbc_sw_write_buffer(false);
282         for (i = 0; i < 2; i++, save_enable >>= 1) {
283                 if (save_enable & 0x1) {
284                         vbc_da_enable(0, i);
285                 }
286         }
287         save_enable >>= 1;
288         if (save_enable & 0x1) {
289                 arch_audio_vbc_disable();
290         }
291 }
292
293 static inline int vbc_str_2_index(int stream);
294
295 static int vbc_da_arch_enable(int chan)
296 {
297         int ret;
298         ret = vbc_da_enable(1, chan);
299         if (ret < 0) {
300                 pr_err("VBC da enable error:%i\n", ret);
301                 return ret;
302         } else {
303                 arch_audio_vbc_enable();
304                 vbc[vbc_str_2_index(SNDRV_PCM_STREAM_PLAYBACK)].is_active = 1;
305         }
306         return ret;
307 }
308
309 static int vbc_da_arch_disable(int chan)
310 {
311         int ret;
312         ret = vbc_da_enable(0, chan);
313         if (ret < 0) {
314                 pr_err("VBC da disable error:%i\n", ret);
315                 return ret;
316         } else {
317                 vbc[vbc_str_2_index(SNDRV_PCM_STREAM_PLAYBACK)].is_active = 0;
318         }
319         return ret;
320 }
321
322 static int vbc_ad_arch_enable(int chan)
323 {
324         int ret;
325         ret = vbc_ad_enable(1, chan);
326         if (ret < 0) {
327                 pr_err("VBC ad enable error:%i\n", ret);
328                 return ret;
329         } else {
330                 arch_audio_vbc_enable();
331                 vbc[vbc_str_2_index(SNDRV_PCM_STREAM_CAPTURE)].is_active = 1;
332         }
333         return ret;
334 }
335
336 static int vbc_ad_arch_disable(int chan)
337 {
338         int ret;
339         ret = vbc_ad_enable(0, chan);
340         if (ret < 0) {
341                 pr_err("VBC ad disable error:%i\n", ret);
342                 return ret;
343         } else {
344                 vbc[vbc_str_2_index(SNDRV_PCM_STREAM_CAPTURE)].is_active = 0;
345         }
346         return ret;
347 }
348
349 static int vbc_ad23_arch_enable(int chan)
350 {
351         int ret;
352         ret = vbc_ad23_enable(1, chan);
353         if (ret < 0) {
354                 pr_err("VBC ad enable error:%i\n", ret);
355                 return ret;
356         } else {
357                 arch_audio_vbc_enable();
358                 vbc[vbc_str_2_index(SNDRV_PCM_STREAM_CAPTURE) + 1].is_active =
359                     1;
360         }
361         return ret;
362 }
363
364 static int vbc_ad23_arch_disable(int chan)
365 {
366         int ret;
367         ret = vbc_ad23_enable(0, chan);
368         if (ret < 0) {
369                 pr_err("VBC ad23 disable error:%i\n", ret);
370                 return ret;
371         } else {
372                 vbc[vbc_str_2_index(SNDRV_PCM_STREAM_CAPTURE) + 1].is_active =
373                     0;
374         }
375         return ret;
376 }
377
378 static inline int vbc_da0_dg_set(int enable, int dg)
379 {
380         if (enable) {
381                 vbc_reg_write(DADGCTL, 0x80 | (0xFF & dg), 0xFF);
382         } else {
383                 vbc_reg_write(DADGCTL, 0, 0x80);
384         }
385         return 0;
386 }
387
388 static inline int vbc_da1_dg_set(int enable, int dg)
389 {
390         if (enable) {
391                 vbc_reg_write(DADGCTL, (0x80 | (0xFF & dg)) << 8, 0xFF00);
392         } else {
393                 vbc_reg_write(DADGCTL, 0, 0x8000);
394         }
395         return 0;
396 }
397
398 static inline int vbc_ad0_dg_set(int enable, int dg)
399 {
400         if (enable) {
401                 vbc_reg_write(ADDG01CTL, 0x80 | (0xFF & dg), 0xFF);
402         } else {
403                 vbc_reg_write(ADDG01CTL, 0, 0x80);
404         }
405         return 0;
406 }
407
408 static inline int vbc_ad1_dg_set(int enable, int dg)
409 {
410         if (enable) {
411                 vbc_reg_write(ADDG01CTL, (0x80 | (0xFF & dg)) << 8, 0xFF00);
412         } else {
413                 vbc_reg_write(ADDG01CTL, 0, 0x8000);
414         }
415         return 0;
416 }
417
418 static inline int vbc_ad2_dg_set(int enable, int dg)
419 {
420         if (enable) {
421                 vbc_reg_write(ADDG23CTL, 0x80 | (0xFF & dg), 0xFF);
422         } else {
423                 vbc_reg_write(ADDG23CTL, 0, 0x80);
424         }
425         return 0;
426 }
427
428 static inline int vbc_ad3_dg_set(int enable, int dg)
429 {
430         if (enable) {
431                 vbc_reg_write(ADDG23CTL, (0x80 | (0xFF & dg)) << 8, 0xFF00);
432         } else {
433                 vbc_reg_write(ADDG23CTL, 0, 0x8000);
434         }
435         return 0;
436 }
437
438 static int vbc_try_dg_set(int vbc_idx, int id)
439 {
440         int dg = vbc[vbc_idx].dg_val[id];
441         if (vbc[vbc_idx].dg_switch[id]) {
442                 vbc[vbc_idx].dg_set[id] (1, dg);
443         } else {
444                 vbc[vbc_idx].dg_set[id] (0, dg);
445         }
446         return 0;
447 }
448
449 int vbc_adc_sel_iis(int port)
450 {
451         vbc_reg_write(VBIISSEL, port << VBIISSEL_AD01_PORT_SHIFT,
452                       VBIISSEL_AD01_PORT_MASK);
453         return 0;
454 }
455
456 int vbc_adc23_sel_iis(int port)
457 {
458         vbc_reg_write(VBIISSEL, port << VBIISSEL_AD23_PORT_SHIFT,
459                       VBIISSEL_AD23_PORT_MASK);
460         return 0;
461 }
462
463 int vbc_dac0_fm_mixer(int mode)
464 {
465         vbc_reg_write(DAPATCHCTL, mode << VBDAPATH_DA0_ADDFM_SHIFT,
466                       VBDAPATH_DA0_ADDFM_MASK);
467         return 0;
468 }
469
470 int vbc_dac1_fm_mixer(int mode)
471 {
472         vbc_reg_write(DAPATCHCTL, mode << VBDAPATH_DA1_ADDFM_SHIFT,
473                       VBDAPATH_DA1_ADDFM_MASK);
474         return 0;
475 }
476
477 static int vbc_dac_src_enable(int enable)
478 {
479         int i;
480         int mask =
481             (1 << VBDACSRC_F1F2F3_BP) | (1 << VBDACSRC_F1_SEL) | (1 <<
482                                                                   VBDACSRC_F0_BP)
483             | (1 << VBDACSRC_F0_SEL) | (1 << VBDACSRC_EN);
484         if (enable) {
485                 //src_clr
486                 vbc_reg_write(DACSRCCTL, (1 << VBDACSRC_CLR),
487                               (1 << VBDACSRC_CLR));
488                 for (i = 0; i < 10; i++) ;
489                 vbc_reg_write(DACSRCCTL, 0, (1 << VBDACSRC_CLR));
490
491                 //src_set and enable
492                 vbc_reg_write(DACSRCCTL, 0x31, mask);
493         } else {
494                 vbc_reg_write(DACSRCCTL, 0, 0x7F);
495         }
496         return 0;
497 }
498
499 static int vbc_st0_enable(int enable)
500 {
501         vbc_reg_write(STCTL0, (enable ? (1 << 12) : 0), 1 << 12);
502         return 0;
503 }
504
505 static int vbc_st1_enable(int enable)
506 {
507         vbc_reg_write(STCTL0, (enable ? (1 << 12) : 0), 1 << 12);
508         return 0;
509 }
510
511 static void digtal_fm_input_enable(int enable)
512 {
513         /*we suppose that  digital fm input from vbc ad01 */
514         if (enable) {
515                 vbc_adc_sel_iis(1);     /*digital fm ==> vbc */
516         } else {
517                 vbc_adc_sel_iis(0);     /*codec ==> vbc */
518         }
519
520         /*ST enable */
521         vbc_st0_enable(enable);
522         vbc_st1_enable(enable);
523
524         /*SRC set */
525         vbc_dac_src_enable(enable);     /*todo:maybe we need to reserve SRC value */
526
527         /*todo:  set fm input pin */
528 }
529
530 static struct vbc_priv vbc[3] = {
531         {                       /*PlayBack */
532          .dma_set = {vbc_da0_dma_set, vbc_da1_dma_set},
533          .arch_enable = vbc_da_arch_enable,
534          .arch_disable = vbc_da_arch_disable,
535          .is_active = 0,
536          .dg_switch = {0, 0},
537          .dg_val = {0x18, 0x18},
538          .dg_set = {vbc_da0_dg_set, vbc_da1_dg_set},
539          },
540         {                       /*Capture for ad01 */
541          .dma_set = {vbc_ad0_dma_set, vbc_ad1_dma_set},
542          .arch_enable = vbc_ad_arch_enable,
543          .arch_disable = vbc_ad_arch_disable,
544          .is_active = 0,
545          .dg_switch = {0, 0},
546          .dg_val = {0x18, 0x18},
547          .dg_set = {vbc_ad0_dg_set, vbc_ad1_dg_set},
548          },
549         {                       /*Capture for ad23 */
550          .dma_set = {vbc_ad2_dma_set, vbc_ad3_dma_set},
551          .arch_enable = vbc_ad23_arch_enable,
552          .arch_disable = vbc_ad23_arch_disable,
553          .is_active = 0,
554          .dg_switch = {0, 0},
555          .dg_val = {0x18, 0x18},
556          .dg_set = {vbc_ad2_dg_set, vbc_ad3_dg_set},
557          },
558 };
559
560 /* NOTE:
561    this index need use for the [struct vbc_priv] vbc[2] index
562    default MUST return 0.
563  */
564 static inline int vbc_str_2_index(int stream)
565 {
566         if (stream == SNDRV_PCM_STREAM_CAPTURE) {
567                 return 1;
568         }
569
570         return 0;
571 }
572
573 static inline void vbc_reg_enable(void)
574 {
575         arch_audio_vbc_reg_enable();
576 }
577
578 int vbc_startup(int stream)
579 {
580         int vbc_idx;
581
582         vbc_dbg("Entering %s\n", __func__);
583         vbc_idx = vbc_str_2_index(stream);
584
585         if (vbc[vbc_idx].is_open || vbc[vbc_idx].is_active) {
586                 pr_err("vbc is actived:%d\n", stream);
587         }
588
589         mutex_lock(&vbc_mutex);
590         vbc[vbc_idx].is_open = 1;
591         mutex_unlock(&vbc_mutex);
592
593         vbc_reg_enable();
594
595         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
596                 vbc_da_buffer_clear_all();
597                 vbc_set_buffer_size(0, VBC_FIFO_FRAME_NUM, 0);
598                 vbc_eq_try_apply();
599         } else if (vbc_idx == 1) {
600                 vbc_set_buffer_size(VBC_FIFO_FRAME_NUM, 0, 0);
601         } else {
602                 vbc_set_buffer_size(0, 0, VBC_FIFO_FRAME_NUM);
603         }
604
605         vbc_try_dg_set(vbc_idx, VBC_LEFT);
606         vbc_try_dg_set(vbc_idx, VBC_RIGHT);
607
608         vbc[vbc_idx].used_chan_count = 2;
609
610         WARN_ON(!vbc[vbc_idx].arch_enable);
611         WARN_ON(!vbc[vbc_idx].arch_disable);
612         WARN_ON(!vbc[vbc_idx].dma_set[0]);
613         WARN_ON(!vbc[vbc_idx].dma_set[1]);
614
615         vbc_dbg("Leaving %s\n", __func__);
616         return 0;
617 }
618
619 static inline int vbc_can_close(void)
620 {
621         return !(vbc[vbc_str_2_index(SNDRV_PCM_STREAM_PLAYBACK)].is_open
622                  || vbc[vbc_str_2_index(SNDRV_PCM_STREAM_CAPTURE)].is_open
623                  ||
624                  vbc[(vbc_str_2_index(SNDRV_PCM_STREAM_CAPTURE) + 1)].is_open);
625 }
626
627 void vbc_shutdown(int stream)
628 {
629         int vbc_idx;
630         int i;
631
632         vbc_dbg("Entering %s\n", __func__);
633
634         /* vbc da close MUST clear da buffer */
635         if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
636                 vbc_da_buffer_clear_all();
637         }
638
639         vbc_idx = vbc_str_2_index(stream);
640
641         for (i = 0; i < 2; i++) {
642                 vbc[vbc_idx].arch_disable(i);
643                 vbc[vbc_idx].dma_set[i] (0);
644         }
645
646         mutex_lock(&vbc_mutex);
647         vbc[vbc_idx].is_open = 0;
648         if (vbc_can_close()) {
649                 vbc_enable_set(0);
650                 arch_audio_vbc_reset();
651                 arch_audio_vbc_disable();
652                 arch_audio_vbc_reg_disable();
653                 pr_info("close the VBC\n");
654         }
655         mutex_unlock(&vbc_mutex);
656
657         vbc_dbg("Leaving %s\n", __func__);
658 }
659
660 int vbc_trigger(int stream, int enable)
661 {
662         int vbc_idx;
663         int ret = 0;
664         int i;
665
666 #if 0
667         vbc_dbg("Entering %s\n", __func__);
668 #endif
669
670         vbc_idx = vbc_str_2_index(stream);
671
672         if (enable) {
673                 for (i = 0; i < vbc[vbc_idx].used_chan_count; i++) {
674                         vbc[vbc_idx].arch_enable(i);
675                         vbc[vbc_idx].dma_set[i] (1);
676                 }
677                 vbc_enable_set(1);
678         } else {
679                 for (i = 0; i < vbc[vbc_idx].used_chan_count; i++) {
680                         vbc[vbc_idx].arch_disable(i);
681                         vbc[vbc_idx].dma_set[i] (0);
682                 }
683
684                 if (vbc_can_close()) {
685                         vbc_enable_set(0);
686                         arch_audio_vbc_disable();
687                 }
688         }
689
690 #if 0
691         vbc_dbg("Leaving %s\n", __func__);
692 #endif
693         return ret;
694 }
695
696 static int vbc_eq_reg_offset(u32 reg)
697 {
698         int i = 0;
699         if ((reg >= DAPATCHCTL) && (reg <= MIXERCTL)) {
700                 i = (reg - DAPATCHCTL) >> 2;
701         } else if ((reg >= VBNGCVTHD) && (reg <= VBNGCTL)) {
702                 i = ((reg - VBNGCVTHD) >> 2) + ((MIXERCTL - DAPATCHCTL) >> 2) +
703                     1;
704         } else if ((reg >= HPCOEF0_H) && (reg <= HPCOEF71_L)) {
705                 i = ((reg - HPCOEF0_H) >> 2) + ((VBNGCTL - VBNGCVTHD) >> 2) +
706                     ((MIXERCTL - DAPATCHCTL) >> 2) + 2;
707         }
708         BUG_ON(i >= VBC_EFFECT_PARAS_LEN);
709         return i;
710 }
711
712 static inline void vbc_eq_reg_set(u32 reg, void *data)
713 {
714         u32 *effect_paras = data;
715         vbc_dbg("reg(0x%x) = (0x%x)\n", reg,
716                 effect_paras[vbc_eq_reg_offset(reg)]);
717         __raw_writel(effect_paras[vbc_eq_reg_offset(reg)], reg);
718 }
719
720 static inline void vbc_eq_reg_set_range(u32 reg_start, u32 reg_end, void *data)
721 {
722         u32 reg_addr;
723         for (reg_addr = reg_start; reg_addr <= reg_end; reg_addr += 4) {
724                 vbc_eq_reg_set(reg_addr, data);
725         }
726 }
727
728 static void vbc_eq_reg_apply(void *data)
729 {
730         vbc_eq_reg_set_range(DAALCCTL0, DAALCCTL10, data);
731         vbc_eq_reg_set_range(HPCOEF0_H, HPCOEF71_L, data);
732
733         vbc_eq_reg_set(DAHPCTL, data);
734         vbc_eq_reg_set(DAPATCHCTL, data);
735
736         vbc_eq_reg_set(STCTL0, data);
737         vbc_eq_reg_set(STCTL1, data);
738
739         vbc_eq_reg_set(ADPATCHCTL, data);
740         vbc_eq_reg_set_range(ADHPCTL, VBNGCTL, data);
741 }
742
743 static void vbc_eq_profile_apply(void *data)
744 {
745         vbc_eq_reg_apply(data);
746 }
747
748 static void vbc_eq_profile_close(void)
749 {
750         vbc_eq_profile_apply(&vbc_eq_profile_default);
751 }
752
753 static void vbc_eq_try_apply(void)
754 {
755         u32 *data;
756         vbc_dbg("Entering %s 0x%x\n", __func__,
757                 (int)vbc_eq_setting.vbc_eq_apply);
758         if (vbc_eq_setting.vbc_eq_apply) {
759                 mutex_lock(&load_mutex);
760                 if (vbc_eq_setting.is_loaded) {
761                         struct vbc_eq_profile *now =
762                             &vbc_eq_setting.data[vbc_eq_setting.now_profile];
763                         data = now->effect_paras;
764                         pr_info("vbc eq apply '%s'\n", now->name);
765                         vbc_eq_setting.vbc_eq_apply(data);
766                 }
767                 mutex_unlock(&load_mutex);
768         }
769         vbc_dbg("Leaving %s\n", __func__);
770 }
771
772 static int vbc_eq_profile_get(void)
773 {
774         return vbc_eq_setting.now_profile;
775 }
776
777 static int vbc_eq_profile_put(int select)
778 {
779         int ret = 0;
780
781         pr_info("vbc eq select %d max %d\n", select,
782                 vbc_eq_setting.hdr.num_profile);
783
784         ret = select;
785         if (ret == vbc_eq_setting.now_profile) {
786                 return ret;
787         }
788         if (ret < vbc_eq_setting.hdr.num_profile) {
789                 vbc_eq_setting.now_profile = ret;
790         }
791
792         vbc_eq_try_apply();
793
794         vbc_dbg("Leaving %s\n", __func__);
795         return ret;
796 }
797
798 static int vbc_switch_get(void)
799 {
800         int ret;
801         ret = arch_audio_vbc_switch(AUDIO_NO_CHANGE);
802         if (ret >= 0)
803                 return ((ret ==
804                       AUDIO_TO_CP0_DSP_CTRL) ? 0 : ((ret ==
805                                                      AUDIO_TO_CP1_DSP_CTRL) ? 1
806                                                     : 2));
807
808         return ret;
809 }
810
811 static int vbc_switch_put(int is_arm)
812 {
813         int ret;
814         pr_info("VBC switch to %s\n", is_arm ? "ARM" : "DSP");
815
816         ret = is_arm;
817         ret = arch_audio_vbc_switch(ret == 0 ?
818                                     AUDIO_TO_CP0_DSP_CTRL : ((ret == 1) ?
819                                                              AUDIO_TO_CP1_DSP_CTRL
820                                                              :
821                                                              AUDIO_TO_AP_ARM_CTRL));
822
823         vbc_dbg("Leaving %s\n", __func__);
824         return ret;
825 }
826
827 static int vbc_eq_switch_get(void)
828 {
829         return vbc_eq_setting.is_active;
830 }
831
832 static int vbc_eq_switch_put(int is_active)
833 {
834         int ret;
835         pr_info("VBC eq switch %s\n", is_active ? "ON" : "OFF");
836
837         ret = is_active;
838         if (ret == vbc_eq_setting.is_active) {
839                 return ret;
840         }
841         if ((ret == 0) || (ret == 1)) {
842                 vbc_eq_setting.is_active = ret;
843                 if (vbc_eq_setting.is_active) {
844                         vbc_eq_setting.vbc_eq_apply = vbc_eq_profile_apply;
845                         vbc_eq_try_apply();
846                 } else {
847                         vbc_eq_setting.vbc_eq_apply = 0;
848                         vbc_eq_profile_close();
849                 }
850         }
851
852         vbc_dbg("Leaving %s\n", __func__);
853         return ret;
854 }
855
856 static int vbc_dg_get(int stream, int id)
857 {
858         int vbc_idx = vbc_str_2_index(stream);
859         return vbc[vbc_idx].dg_val[id];
860 }
861
862 static int vbc_dg_put(int stream, int id, int dg)
863 {
864         int ret = 0;
865         int vbc_idx = vbc_str_2_index(stream);
866
867         pr_info("VBC %s%s DG set 0x%02x\n",
868                 (vbc_idx == 2) ? "ADC23" : (vbc_idx == 1 ? "ADC" : "DAC"),
869                 id == VBC_LEFT ? "L" : "R",     dg);
870
871         ret = dg;
872         if (ret == vbc[vbc_idx].dg_val[id]) {
873                 return ret;
874         }
875         if (ret <= VBC_DG_VAL_MAX) {
876                 vbc[vbc_idx].dg_val[id] = ret;
877         }
878
879         vbc_try_dg_set(vbc_idx, id);
880
881         vbc_dbg("Leaving %s\n", __func__);
882         return ret;
883 }
884
885 static int vbc_dg_switch_get(int stream, int id)
886 {
887         int vbc_idx = vbc_str_2_index(stream);
888         return vbc[vbc_idx].dg_switch[id];
889 }
890
891 static int vbc_dg_switch_put(int stream, int id, int enable)
892 {
893         int ret = 0;
894         int vbc_idx = vbc_str_2_index(stream);
895
896         pr_info("VBC %s%s DG switch %s\n",
897                 (vbc_idx == 2) ? "ADC23" : (vbc_idx == 1 ? "ADC" : "DAC"),
898                 id == VBC_LEFT ? "L" : "R",
899                 enable ? "ON" : "OFF");
900
901         ret = enable;
902         if (ret == vbc[vbc_idx].dg_switch[id]) {
903                 return ret;
904         }
905
906         vbc[vbc_idx].dg_switch[id] = ret;
907
908         vbc_try_dg_set(vbc_idx, id);
909
910         vbc_dbg("Leaving %s\n", __func__);
911         return ret;
912 }
913
914 int vbc_init(void)
915 {
916         arch_audio_vbc_switch(AUDIO_TO_AP_ARM_CTRL);
917         return 0;
918 }
919
920 void vbc_exit(void)
921 {
922 }
923
924 MODULE_DESCRIPTION("SPRD ASoC VBC CUP-DAI driver");
925 MODULE_AUTHOR("Zhenfang Wang <zhenfang.wang@spreadtrum.com>");
926 MODULE_LICENSE("GPL");