aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/plat-mxc/Makefile4
-rw-r--r--arch/arm/plat-mxc/ssi-fiq-ksym.c20
-rw-r--r--arch/arm/plat-mxc/ssi-fiq.S134
-rw-r--r--arch/sh/include/asm/siu.h26
-rw-r--r--include/sound/soc-dai.h2
-rw-r--r--include/sound/soc-dapm.h32
-rw-r--r--include/sound/soc.h22
-rw-r--r--include/sound/tlv320dac33-plat.h1
-rw-r--r--include/sound/tpa6130a2-plat.h6
-rw-r--r--include/sound/wm8904.h57
-rw-r--r--include/sound/wm8955.h26
-rw-r--r--sound/soc/codecs/Kconfig12
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/ad1836.c32
-rw-r--r--sound/soc/codecs/ad1836.h1
-rw-r--r--sound/soc/codecs/ad1938.c64
-rw-r--r--sound/soc/codecs/ak4104.c4
-rw-r--r--sound/soc/codecs/cs4270.c81
-rw-r--r--sound/soc/codecs/da7210.c589
-rw-r--r--sound/soc/codecs/da7210.h24
-rw-r--r--sound/soc/codecs/tlv320aic3x.c75
-rw-r--r--sound/soc/codecs/tlv320dac33.c306
-rw-r--r--sound/soc/codecs/tpa6130a2.c115
-rw-r--r--sound/soc/codecs/twl4030.c2
-rw-r--r--sound/soc/codecs/twl4030.h2
-rw-r--r--sound/soc/codecs/wm8727.c66
-rw-r--r--sound/soc/codecs/wm8731.c3
-rw-r--r--sound/soc/codecs/wm8753.c8
-rw-r--r--sound/soc/codecs/wm8776.c2
-rw-r--r--sound/soc/codecs/wm8904.c2556
-rw-r--r--sound/soc/codecs/wm8904.h1681
-rw-r--r--sound/soc/codecs/wm8955.c1151
-rw-r--r--sound/soc/codecs/wm8955.h489
-rw-r--r--sound/soc/codecs/wm8961.c3
-rw-r--r--sound/soc/codecs/wm8990.c8
-rw-r--r--sound/soc/codecs/wm8993.c67
-rw-r--r--sound/soc/codecs/wm_hubs.c6
-rw-r--r--sound/soc/davinci/davinci-mcasp.c18
-rw-r--r--sound/soc/davinci/davinci-mcasp.h1
-rw-r--r--sound/soc/davinci/davinci-pcm.c2
-rw-r--r--sound/soc/imx/Kconfig20
-rw-r--r--sound/soc/imx/Makefile12
-rw-r--r--sound/soc/imx/imx-pcm-dma-mx2.c313
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c277
-rw-r--r--sound/soc/imx/imx-ssi.c758
-rw-r--r--sound/soc/imx/imx-ssi.h237
-rw-r--r--sound/soc/imx/mx1_mx2-pcm.c488
-rw-r--r--sound/soc/imx/mx1_mx2-pcm.h26
-rw-r--r--sound/soc/imx/mx27vis_wm8974.c318
-rw-r--r--sound/soc/imx/mxc-ssi.c860
-rw-r--r--sound/soc/imx/mxc-ssi.h238
-rw-r--r--sound/soc/pxa/raumfeld.c61
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c120
-rw-r--r--sound/soc/sh/Kconfig14
-rw-r--r--sound/soc/sh/Makefile4
-rw-r--r--sound/soc/sh/fsi-da7210.c83
-rw-r--r--sound/soc/sh/fsi.c164
-rw-r--r--sound/soc/sh/siu.h193
-rw-r--r--sound/soc/sh/siu_dai.c847
-rw-r--r--sound/soc/sh/siu_pcm.c616
-rw-r--r--sound/soc/soc-cache.c2
-rw-r--r--sound/soc/soc-core.c11
-rw-r--r--sound/soc/soc-dapm.c142
63 files changed, 11078 insertions, 2434 deletions
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
index 996cbac6932..6cee38df58b 100644
--- a/arch/arm/plat-mxc/Makefile
+++ b/arch/arm/plat-mxc/Makefile
@@ -13,3 +13,7 @@ obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
13obj-$(CONFIG_MXC_ULPI) += ulpi.o 13obj-$(CONFIG_MXC_ULPI) += ulpi.o
14obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o 14obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
15obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o 15obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
16ifdef CONFIG_SND_IMX_SOC
17obj-y += ssi-fiq.o
18obj-y += ssi-fiq-ksym.o
19endif
diff --git a/arch/arm/plat-mxc/ssi-fiq-ksym.c b/arch/arm/plat-mxc/ssi-fiq-ksym.c
new file mode 100644
index 00000000000..b5fad454da7
--- /dev/null
+++ b/arch/arm/plat-mxc/ssi-fiq-ksym.c
@@ -0,0 +1,20 @@
1/*
2 * Exported ksyms for the SSI FIQ handler
3 *
4 * Copyright (C) 2009, Sascha Hauer <s.hauer@pengutronix.de>
5 *
6 * This program 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
11#include <linux/module.h>
12
13#include <mach/ssi.h>
14
15EXPORT_SYMBOL(imx_ssi_fiq_tx_buffer);
16EXPORT_SYMBOL(imx_ssi_fiq_rx_buffer);
17EXPORT_SYMBOL(imx_ssi_fiq_start);
18EXPORT_SYMBOL(imx_ssi_fiq_end);
19EXPORT_SYMBOL(imx_ssi_fiq_base);
20
diff --git a/arch/arm/plat-mxc/ssi-fiq.S b/arch/arm/plat-mxc/ssi-fiq.S
new file mode 100644
index 00000000000..4ddce565b35
--- /dev/null
+++ b/arch/arm/plat-mxc/ssi-fiq.S
@@ -0,0 +1,134 @@
1/*
2 * Copyright (C) 2009 Sascha Hauer <s.hauer@pengutronix.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/linkage.h>
10#include <asm/assembler.h>
11
12/*
13 * r8 = bit 0-15: tx offset, bit 16-31: tx buffer size
14 * r9 = bit 0-15: rx offset, bit 16-31: rx buffer size
15 */
16
17#define SSI_STX0 0x00
18#define SSI_SRX0 0x08
19#define SSI_SISR 0x14
20#define SSI_SIER 0x18
21#define SSI_SACNT 0x38
22
23#define SSI_SACNT_AC97EN (1 << 0)
24
25#define SSI_SIER_TFE0_EN (1 << 0)
26#define SSI_SISR_TFE0 (1 << 0)
27#define SSI_SISR_RFF0 (1 << 2)
28#define SSI_SIER_RFF0_EN (1 << 2)
29
30 .text
31 .global imx_ssi_fiq_start
32 .global imx_ssi_fiq_end
33 .global imx_ssi_fiq_base
34 .global imx_ssi_fiq_rx_buffer
35 .global imx_ssi_fiq_tx_buffer
36
37imx_ssi_fiq_start:
38 ldr r12, imx_ssi_fiq_base
39
40 /* TX */
41 ldr r11, imx_ssi_fiq_tx_buffer
42
43 /* shall we send? */
44 ldr r13, [r12, #SSI_SIER]
45 tst r13, #SSI_SIER_TFE0_EN
46 beq 1f
47
48 /* TX FIFO empty? */
49 ldr r13, [r12, #SSI_SISR]
50 tst r13, #SSI_SISR_TFE0
51 beq 1f
52
53 mov r10, #0x10000
54 sub r10, #1
55 and r10, r10, r8 /* r10: current buffer offset */
56
57 add r11, r11, r10
58
59 ldrh r13, [r11]
60 strh r13, [r12, #SSI_STX0]
61
62 ldrh r13, [r11, #2]
63 strh r13, [r12, #SSI_STX0]
64
65 ldrh r13, [r11, #4]
66 strh r13, [r12, #SSI_STX0]
67
68 ldrh r13, [r11, #6]
69 strh r13, [r12, #SSI_STX0]
70
71 add r10, #8
72 lsr r13, r8, #16 /* r13: buffer size */
73 cmp r10, r13
74 lslgt r8, r13, #16
75 addle r8, #8
761:
77 /* RX */
78
79 /* shall we receive? */
80 ldr r13, [r12, #SSI_SIER]
81 tst r13, #SSI_SIER_RFF0_EN
82 beq 1f
83
84 /* RX FIFO full? */
85 ldr r13, [r12, #SSI_SISR]
86 tst r13, #SSI_SISR_RFF0
87 beq 1f
88
89 ldr r11, imx_ssi_fiq_rx_buffer
90
91 mov r10, #0x10000
92 sub r10, #1
93 and r10, r10, r9 /* r10: current buffer offset */
94
95 add r11, r11, r10
96
97 ldr r13, [r12, #SSI_SACNT]
98 tst r13, #SSI_SACNT_AC97EN
99
100 ldr r13, [r12, #SSI_SRX0]
101 strh r13, [r11]
102
103 ldr r13, [r12, #SSI_SRX0]
104 strh r13, [r11, #2]
105
106 /* dummy read to skip slot 12 */
107 ldrne r13, [r12, #SSI_SRX0]
108
109 ldr r13, [r12, #SSI_SRX0]
110 strh r13, [r11, #4]
111
112 ldr r13, [r12, #SSI_SRX0]
113 strh r13, [r11, #6]
114
115 /* dummy read to skip slot 12 */
116 ldrne r13, [r12, #SSI_SRX0]
117
118 add r10, #8
119 lsr r13, r9, #16 /* r13: buffer size */
120 cmp r10, r13
121 lslgt r9, r13, #16
122 addle r9, #8
123
1241:
125 @ return from FIQ
126 subs pc, lr, #4
127imx_ssi_fiq_base:
128 .word 0x0
129imx_ssi_fiq_rx_buffer:
130 .word 0x0
131imx_ssi_fiq_tx_buffer:
132 .word 0x0
133imx_ssi_fiq_end:
134
diff --git a/arch/sh/include/asm/siu.h b/arch/sh/include/asm/siu.h
new file mode 100644
index 00000000000..57565a3b551
--- /dev/null
+++ b/arch/sh/include/asm/siu.h
@@ -0,0 +1,26 @@
1/*
2 * platform header for the SIU ASoC driver
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 *
6 * This program 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
11#ifndef ASM_SIU_H
12#define ASM_SIU_H
13
14#include <asm/dma-sh.h>
15
16struct device;
17
18struct siu_platform {
19 struct device *dma_dev;
20 enum sh_dmae_slave_chan_id dma_slave_tx_a;
21 enum sh_dmae_slave_chan_id dma_slave_rx_a;
22 enum sh_dmae_slave_chan_id dma_slave_tx_b;
23 enum sh_dmae_slave_chan_id dma_slave_rx_b;
24};
25
26#endif /* ASM_SIU_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index ca24e7f7a3f..061f16d4c87 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -16,6 +16,8 @@
16 16
17#include <linux/list.h> 17#include <linux/list.h>
18 18
19#include <sound/soc.h>
20
19struct snd_pcm_substream; 21struct snd_pcm_substream;
20 22
21/* 23/*
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index c5c95e1da65..c0922a03422 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -95,6 +95,21 @@
95 .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \ 95 .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
96 .num_kcontrols = 1} 96 .num_kcontrols = 1}
97 97
98/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
99#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
100 wcontrols) \
101{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
102 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
103#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
104 wcontrols)\
105{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
106 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
107#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
108 wcontrols)\
109{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
110 .shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
111 .num_kcontrols = ARRAY_SIZE(wcontrols)}
112
98/* path domain with event - event handler must return 0 for success */ 113/* path domain with event - event handler must return 0 for success */
99#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ 114#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
100 wncontrols, wevent, wflags) \ 115 wncontrols, wevent, wflags) \
@@ -126,6 +141,23 @@
126 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \ 141 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
127 .event = wevent, .event_flags = wflags} 142 .event = wevent, .event_flags = wflags}
128 143
144/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
145#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
146 wevent, wflags) \
147{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
148 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
149 .event = wevent, .event_flags = wflags}
150#define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
151 wevent, wflags) \
152{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
153 .invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
154 .event = wevent, .event_flags = wflags}
155#define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
156 wcontrols, wevent, wflags) \
157{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
158 .invert = winvert, .kcontrols = wcontrols, \
159 .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
160
129/* events that are pre and post DAPM */ 161/* events that are pre and post DAPM */
130#define SND_SOC_DAPM_PRE(wname, wevent) \ 162#define SND_SOC_DAPM_PRE(wname, wevent) \
131{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \ 163{ .id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 0d7718f9280..4bbeb9f83ec 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -169,6 +169,23 @@
169 .private_value = (unsigned long)&xenum } 169 .private_value = (unsigned long)&xenum }
170 170
171/* 171/*
172 * Simplified versions of above macros, declaring a struct and calculating
173 * ARRAY_SIZE internally
174 */
175#define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \
176 struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \
177 ARRAY_SIZE(xtexts), xtexts)
178#define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \
179 SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts)
180#define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \
181 struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts)
182#define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \
183 struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \
184 ARRAY_SIZE(xtexts), xtexts, xvalues)
185#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
186 SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
187
188/*
172 * Bias levels 189 * Bias levels
173 * 190 *
174 * @ON: Bias is fully on for audio playback and capture operations. 191 * @ON: Bias is fully on for audio playback and capture operations.
@@ -253,6 +270,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
253/* codec register bit access */ 270/* codec register bit access */
254int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, 271int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
255 unsigned int mask, unsigned int value); 272 unsigned int mask, unsigned int value);
273int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
274 unsigned short reg, unsigned int mask,
275 unsigned int value);
256int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, 276int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
257 unsigned int mask, unsigned int value); 277 unsigned int mask, unsigned int value);
258 278
@@ -402,6 +422,8 @@ struct snd_soc_codec {
402 short reg_cache_size; 422 short reg_cache_size;
403 short reg_cache_step; 423 short reg_cache_step;
404 424
425 unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
426
405 /* dapm */ 427 /* dapm */
406 u32 pop_time; 428 u32 pop_time;
407 struct list_head dapm_widgets; 429 struct list_head dapm_widgets;
diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h
index 5858d06a7ff..ac0665264bd 100644
--- a/include/sound/tlv320dac33-plat.h
+++ b/include/sound/tlv320dac33-plat.h
@@ -15,6 +15,7 @@
15 15
16struct tlv320dac33_platform_data { 16struct tlv320dac33_platform_data {
17 int power_gpio; 17 int power_gpio;
18 u8 burst_bclkdiv;
18}; 19};
19 20
20#endif /* __TLV320DAC33_PLAT_H */ 21#endif /* __TLV320DAC33_PLAT_H */
diff --git a/include/sound/tpa6130a2-plat.h b/include/sound/tpa6130a2-plat.h
index e8c901e749d..e29fde6b5cb 100644
--- a/include/sound/tpa6130a2-plat.h
+++ b/include/sound/tpa6130a2-plat.h
@@ -23,7 +23,13 @@
23#ifndef TPA6130A2_PLAT_H 23#ifndef TPA6130A2_PLAT_H
24#define TPA6130A2_PLAT_H 24#define TPA6130A2_PLAT_H
25 25
26enum tpa_model {
27 TPA6130A2,
28 TPA6140A2,
29};
30
26struct tpa6130a2_platform_data { 31struct tpa6130a2_platform_data {
32 enum tpa_model id;
27 int power_gpio; 33 int power_gpio;
28}; 34};
29 35
diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h
new file mode 100644
index 00000000000..d66575a601b
--- /dev/null
+++ b/include/sound/wm8904.h
@@ -0,0 +1,57 @@
1/*
2 * Platform data for WM8904
3 *
4 * Copyright 2009 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#ifndef __MFD_WM8994_PDATA_H__
16#define __MFD_WM8994_PDATA_H__
17
18#define WM8904_DRC_REGS 4
19#define WM8904_EQ_REGS 25
20
21/**
22 * DRC configurations are specified with a label and a set of register
23 * values to write (the enable bits will be ignored). At runtime an
24 * enumerated control will be presented for each DRC block allowing
25 * the user to choose the configration to use.
26 *
27 * Configurations may be generated by hand or by using the DRC control
28 * panel provided by the WISCE - see http://www.wolfsonmicro.com/wisce/
29 * for details.
30 */
31struct wm8904_drc_cfg {
32 const char *name;
33 u16 regs[WM8904_DRC_REGS];
34};
35
36/**
37 * ReTune Mobile configurations are specified with a label, sample
38 * rate and set of values to write (the enable bits will be ignored).
39 *
40 * Configurations are expected to be generated using the ReTune Mobile
41 * control panel in WISCE - see http://www.wolfsonmicro.com/wisce/
42 */
43struct wm8904_retune_mobile_cfg {
44 const char *name;
45 unsigned int rate;
46 u16 regs[WM8904_EQ_REGS];
47};
48
49struct wm8904_pdata {
50 int num_drc_cfgs;
51 struct wm8904_drc_cfg *drc_cfgs;
52
53 int num_retune_mobile_cfgs;
54 struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
55};
56
57#endif
diff --git a/include/sound/wm8955.h b/include/sound/wm8955.h
new file mode 100644
index 00000000000..5074ef499f4
--- /dev/null
+++ b/include/sound/wm8955.h
@@ -0,0 +1,26 @@
1/*
2 * Platform data for WM8955
3 *
4 * Copyright 2009 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#ifndef __WM8955_PDATA_H__
16#define __WM8955_PDATA_H__
17
18struct wm8955_pdata {
19 /* Configure LOUT2/ROUT2 to drive a speaker */
20 unsigned int out2_speaker:1;
21
22 /* Configure MONOIN+/- in differential mode */
23 unsigned int monoin_diff:1;
24};
25
26#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 52b005f8fed..62ff26a08a2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -23,6 +23,7 @@ config SND_SOC_ALL_CODECS
23 select SND_SOC_AK4671 if I2C 23 select SND_SOC_AK4671 if I2C
24 select SND_SOC_CS4270 if I2C 24 select SND_SOC_CS4270 if I2C
25 select SND_SOC_MAX9877 if I2C 25 select SND_SOC_MAX9877 if I2C
26 select SND_SOC_DA7210 if I2C
26 select SND_SOC_PCM3008 27 select SND_SOC_PCM3008
27 select SND_SOC_SPDIF 28 select SND_SOC_SPDIF
28 select SND_SOC_SSM2602 if I2C 29 select SND_SOC_SSM2602 if I2C
@@ -49,7 +50,9 @@ config SND_SOC_ALL_CODECS
49 select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI 50 select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
50 select SND_SOC_WM8900 if I2C 51 select SND_SOC_WM8900 if I2C
51 select SND_SOC_WM8903 if I2C 52 select SND_SOC_WM8903 if I2C
53 select SND_SOC_WM8904 if I2C
52 select SND_SOC_WM8940 if I2C 54 select SND_SOC_WM8940 if I2C
55 select SND_SOC_WM8955 if I2C
53 select SND_SOC_WM8960 if I2C 56 select SND_SOC_WM8960 if I2C
54 select SND_SOC_WM8961 if I2C 57 select SND_SOC_WM8961 if I2C
55 select SND_SOC_WM8971 if I2C 58 select SND_SOC_WM8971 if I2C
@@ -112,6 +115,9 @@ config SND_SOC_AK4671
112config SND_SOC_CS4270 115config SND_SOC_CS4270
113 tristate 116 tristate
114 117
118config SND_SOC_DA7210
119 tristate
120
115# Cirrus Logic CS4270 Codec VD = 3.3V Errata 121# Cirrus Logic CS4270 Codec VD = 3.3V Errata
116# Select if you are affected by the errata where the part will not function 122# Select if you are affected by the errata where the part will not function
117# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will 123# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will
@@ -203,9 +209,15 @@ config SND_SOC_WM8900
203config SND_SOC_WM8903 209config SND_SOC_WM8903
204 tristate 210 tristate
205 211
212config SND_SOC_WM8904
213 tristate
214
206config SND_SOC_WM8940 215config SND_SOC_WM8940
207 tristate 216 tristate
208 217
218config SND_SOC_WM8955
219 tristate
220
209config SND_SOC_WM8960 221config SND_SOC_WM8960
210 tristate 222 tristate
211 223
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index dbaecb133ac..ea9835412e6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -10,6 +10,7 @@ snd-soc-ak4642-objs := ak4642.o
10snd-soc-ak4671-objs := ak4671.o 10snd-soc-ak4671-objs := ak4671.o
11snd-soc-cs4270-objs := cs4270.o 11snd-soc-cs4270-objs := cs4270.o
12snd-soc-cx20442-objs := cx20442.o 12snd-soc-cx20442-objs := cx20442.o
13snd-soc-da7210-objs := da7210.o
13snd-soc-l3-objs := l3.o 14snd-soc-l3-objs := l3.o
14snd-soc-pcm3008-objs := pcm3008.o 15snd-soc-pcm3008-objs := pcm3008.o
15snd-soc-spdif-objs := spdif_transciever.o 16snd-soc-spdif-objs := spdif_transciever.o
@@ -36,7 +37,9 @@ snd-soc-wm8753-objs := wm8753.o
36snd-soc-wm8776-objs := wm8776.o 37snd-soc-wm8776-objs := wm8776.o
37snd-soc-wm8900-objs := wm8900.o 38snd-soc-wm8900-objs := wm8900.o
38snd-soc-wm8903-objs := wm8903.o 39snd-soc-wm8903-objs := wm8903.o
40snd-soc-wm8904-objs := wm8904.o
39snd-soc-wm8940-objs := wm8940.o 41snd-soc-wm8940-objs := wm8940.o
42snd-soc-wm8955-objs := wm8955.o
40snd-soc-wm8960-objs := wm8960.o 43snd-soc-wm8960-objs := wm8960.o
41snd-soc-wm8961-objs := wm8961.o 44snd-soc-wm8961-objs := wm8961.o
42snd-soc-wm8971-objs := wm8971.o 45snd-soc-wm8971-objs := wm8971.o
@@ -66,6 +69,7 @@ obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
66obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o 69obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
67obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 70obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
68obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o 71obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
72obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
69obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 73obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
70obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 74obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
71obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o 75obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
@@ -92,11 +96,13 @@ obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
92obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o 96obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
93obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o 97obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
94obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o 98obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
95obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o 99obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o
96obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
97obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o 100obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
101obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o
98obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o 102obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
99obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o 103obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
104obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
105obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
100obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o 106obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
101obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o 107obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
102obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o 108obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 2c18e3d1b71..83add2f3afb 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -223,6 +223,36 @@ static unsigned int ad1836_read_reg_cache(struct snd_soc_codec *codec,
223 return reg_cache[reg]; 223 return reg_cache[reg];
224} 224}
225 225
226#ifdef CONFIG_PM
227static int ad1836_soc_suspend(struct platform_device *pdev,
228 pm_message_t state)
229{
230 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
231 struct snd_soc_codec *codec = socdev->card->codec;
232
233 /* reset clock control mode */
234 u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2);
235 adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
236
237 return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
238}
239
240static int ad1836_soc_resume(struct platform_device *pdev)
241{
242 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
243 struct snd_soc_codec *codec = socdev->card->codec;
244
245 /* restore clock control mode */
246 u16 adc_ctrl2 = codec->read(codec, AD1836_ADC_CTRL2);
247 adc_ctrl2 |= AD1836_ADC_AUX;
248
249 return codec->write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
250}
251#else
252#define ad1836_soc_suspend NULL
253#define ad1836_soc_resume NULL
254#endif
255
226static int __devinit ad1836_spi_probe(struct spi_device *spi) 256static int __devinit ad1836_spi_probe(struct spi_device *spi)
227{ 257{
228 struct snd_soc_codec *codec; 258 struct snd_soc_codec *codec;
@@ -404,6 +434,8 @@ static int ad1836_remove(struct platform_device *pdev)
404struct snd_soc_codec_device soc_codec_dev_ad1836 = { 434struct snd_soc_codec_device soc_codec_dev_ad1836 = {
405 .probe = ad1836_probe, 435 .probe = ad1836_probe,
406 .remove = ad1836_remove, 436 .remove = ad1836_remove,
437 .suspend = ad1836_soc_suspend,
438 .resume = ad1836_soc_resume,
407}; 439};
408EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); 440EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
409 441
diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h
index 7660ee6973c..e9d90d3951c 100644
--- a/sound/soc/codecs/ad1836.h
+++ b/sound/soc/codecs/ad1836.h
@@ -54,6 +54,7 @@
54#define AD1836_ADC_SERFMT_MASK (7 << 6) 54#define AD1836_ADC_SERFMT_MASK (7 << 6)
55#define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) 55#define AD1836_ADC_SERFMT_PCK256 (0x4 << 6)
56#define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) 56#define AD1836_ADC_SERFMT_PCK128 (0x5 << 6)
57#define AD1836_ADC_AUX (0x6 << 6)
57 58
58#define AD1836_ADC_CTRL3 14 59#define AD1836_ADC_CTRL3 14
59 60
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c
index 5d489186c05..47d9ac0ec9d 100644
--- a/sound/soc/codecs/ad1938.c
+++ b/sound/soc/codecs/ad1938.c
@@ -97,6 +97,7 @@ static const struct snd_kcontrol_new ad1938_snd_controls[] = {
97static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = { 97static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
98 SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1), 98 SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),
99 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), 99 SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
100 SND_SOC_DAPM_SUPPLY("PLL_PWR", AD1938_PLL_CLK_CTRL0, 0, 1, NULL, 0),
100 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0), 101 SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),
101 SND_SOC_DAPM_OUTPUT("DAC1OUT"), 102 SND_SOC_DAPM_OUTPUT("DAC1OUT"),
102 SND_SOC_DAPM_OUTPUT("DAC2OUT"), 103 SND_SOC_DAPM_OUTPUT("DAC2OUT"),
@@ -107,6 +108,8 @@ static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
107}; 108};
108 109
109static const struct snd_soc_dapm_route audio_paths[] = { 110static const struct snd_soc_dapm_route audio_paths[] = {
111 { "DAC", NULL, "PLL_PWR" },
112 { "ADC", NULL, "PLL_PWR" },
110 { "DAC", NULL, "ADC_PWR" }, 113 { "DAC", NULL, "ADC_PWR" },
111 { "ADC", NULL, "ADC_PWR" }, 114 { "ADC", NULL, "ADC_PWR" },
112 { "DAC1OUT", "DAC1 Switch", "DAC" }, 115 { "DAC1OUT", "DAC1 Switch", "DAC" },
@@ -134,18 +137,8 @@ static int ad1938_mute(struct snd_soc_dai *dai, int mute)
134 return 0; 137 return 0;
135} 138}
136 139
137static inline int ad1938_pll_powerctrl(struct snd_soc_codec *codec, int cmd)
138{
139 int reg = codec->read(codec, AD1938_PLL_CLK_CTRL0);
140 reg = (cmd > 0) ? reg & (~AD1938_PLL_POWERDOWN) : reg |
141 AD1938_PLL_POWERDOWN;
142 codec->write(codec, AD1938_PLL_CLK_CTRL0, reg);
143
144 return 0;
145}
146
147static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 140static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
148 unsigned int mask, int slots, int width) 141 unsigned int rx_mask, int slots, int width)
149{ 142{
150 struct snd_soc_codec *codec = dai->codec; 143 struct snd_soc_codec *codec = dai->codec;
151 int dac_reg = codec->read(codec, AD1938_DAC_CTRL1); 144 int dac_reg = codec->read(codec, AD1938_DAC_CTRL1);
@@ -306,24 +299,6 @@ static int ad1938_hw_params(struct snd_pcm_substream *substream,
306 return 0; 299 return 0;
307} 300}
308 301
309static int ad1938_set_bias_level(struct snd_soc_codec *codec,
310 enum snd_soc_bias_level level)
311{
312 switch (level) {
313 case SND_SOC_BIAS_ON:
314 ad1938_pll_powerctrl(codec, 1);
315 break;
316 case SND_SOC_BIAS_PREPARE:
317 break;
318 case SND_SOC_BIAS_STANDBY:
319 case SND_SOC_BIAS_OFF:
320 ad1938_pll_powerctrl(codec, 0);
321 break;
322 }
323 codec->bias_level = level;
324 return 0;
325}
326
327/* 302/*
328 * interface to read/write ad1938 register 303 * interface to read/write ad1938 register
329 */ 304 */
@@ -514,7 +489,6 @@ static int ad1938_register(struct ad1938_priv *ad1938)
514 codec->num_dai = 1; 489 codec->num_dai = 1;
515 codec->write = ad1938_write_reg; 490 codec->write = ad1938_write_reg;
516 codec->read = ad1938_read_reg_cache; 491 codec->read = ad1938_read_reg_cache;
517 codec->set_bias_level = ad1938_set_bias_level;
518 INIT_LIST_HEAD(&codec->dapm_widgets); 492 INIT_LIST_HEAD(&codec->dapm_widgets);
519 INIT_LIST_HEAD(&codec->dapm_paths); 493 INIT_LIST_HEAD(&codec->dapm_paths);
520 494
@@ -559,7 +533,6 @@ static int ad1938_register(struct ad1938_priv *ad1938)
559 533
560static void ad1938_unregister(struct ad1938_priv *ad1938) 534static void ad1938_unregister(struct ad1938_priv *ad1938)
561{ 535{
562 ad1938_set_bias_level(&ad1938->codec, SND_SOC_BIAS_OFF);
563 snd_soc_unregister_dai(&ad1938_dai); 536 snd_soc_unregister_dai(&ad1938_dai);
564 snd_soc_unregister_codec(&ad1938->codec); 537 snd_soc_unregister_codec(&ad1938->codec);
565 kfree(ad1938); 538 kfree(ad1938);
@@ -593,7 +566,6 @@ static int ad1938_probe(struct platform_device *pdev)
593 ARRAY_SIZE(ad1938_dapm_widgets)); 566 ARRAY_SIZE(ad1938_dapm_widgets));
594 snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); 567 snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
595 568
596 ad1938_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
597 569
598pcm_err: 570pcm_err:
599 return ret; 571 return ret;
@@ -610,37 +582,9 @@ static int ad1938_remove(struct platform_device *pdev)
610 return 0; 582 return 0;
611} 583}
612 584
613#ifdef CONFIG_PM
614static int ad1938_suspend(struct platform_device *pdev,
615 pm_message_t state)
616{
617 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
618 struct snd_soc_codec *codec = socdev->card->codec;
619
620 ad1938_set_bias_level(codec, SND_SOC_BIAS_OFF);
621 return 0;
622}
623
624static int ad1938_resume(struct platform_device *pdev)
625{
626 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
627 struct snd_soc_codec *codec = socdev->card->codec;
628
629 if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
630 ad1938_set_bias_level(codec, SND_SOC_BIAS_ON);
631
632 return 0;
633}
634#else
635#define ad1938_suspend NULL
636#define ad1938_resume NULL
637#endif
638
639struct snd_soc_codec_device soc_codec_dev_ad1938 = { 585struct snd_soc_codec_device soc_codec_dev_ad1938 = {
640 .probe = ad1938_probe, 586 .probe = ad1938_probe,
641 .remove = ad1938_remove, 587 .remove = ad1938_remove,
642 .suspend = ad1938_suspend,
643 .resume = ad1938_resume,
644}; 588};
645EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938); 589EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938);
646 590
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 3a14c6fc4f5..b9ef7e45891 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -185,9 +185,7 @@ struct snd_soc_dai ak4104_dai = {
185 .stream_name = "Playback", 185 .stream_name = "Playback",
186 .channels_min = 2, 186 .channels_min = 2,
187 .channels_max = 2, 187 .channels_max = 2,
188 .rates = SNDRV_PCM_RATE_44100 | 188 .rates = SNDRV_PCM_RATE_8000_192000,
189 SNDRV_PCM_RATE_48000 |
190 SNDRV_PCM_RATE_32000,
191 .formats = SNDRV_PCM_FMTBIT_S16_LE | 189 .formats = SNDRV_PCM_FMTBIT_S16_LE |
192 SNDRV_PCM_FMTBIT_S24_3LE | 190 SNDRV_PCM_FMTBIT_S24_3LE |
193 SNDRV_PCM_FMTBIT_S24_LE 191 SNDRV_PCM_FMTBIT_S24_LE
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index ffe122d1cd7..593bfc7a698 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -28,6 +28,7 @@
28#include <sound/initval.h> 28#include <sound/initval.h>
29#include <linux/i2c.h> 29#include <linux/i2c.h>
30#include <linux/delay.h> 30#include <linux/delay.h>
31#include <linux/regulator/consumer.h>
31 32
32#include "cs4270.h" 33#include "cs4270.h"
33 34
@@ -106,6 +107,10 @@
106#define CS4270_MUTE_DAC_A 0x01 107#define CS4270_MUTE_DAC_A 0x01
107#define CS4270_MUTE_DAC_B 0x02 108#define CS4270_MUTE_DAC_B 0x02
108 109
110static const char *supply_names[] = {
111 "va", "vd", "vlc"
112};
113
109/* Private data for the CS4270 */ 114/* Private data for the CS4270 */
110struct cs4270_private { 115struct cs4270_private {
111 struct snd_soc_codec codec; 116 struct snd_soc_codec codec;
@@ -114,6 +119,9 @@ struct cs4270_private {
114 unsigned int mode; /* The mode (I2S or left-justified) */ 119 unsigned int mode; /* The mode (I2S or left-justified) */
115 unsigned int slave_mode; 120 unsigned int slave_mode;
116 unsigned int manual_mute; 121 unsigned int manual_mute;
122
123 /* power domain regulators */
124 struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
117}; 125};
118 126
119/** 127/**
@@ -192,6 +200,11 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
192 * This function must be called by the machine driver's 'startup' function, 200 * This function must be called by the machine driver's 'startup' function,
193 * otherwise the list of supported sample rates will not be available in 201 * otherwise the list of supported sample rates will not be available in
194 * time for ALSA. 202 * time for ALSA.
203 *
204 * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause
205 * theoretically possible sample rates to be enabled. Call it again with a
206 * proper value set one the external clock is set (most probably you would do
207 * that from a machine's driver 'hw_param' hook.
195 */ 208 */
196static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai, 209static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
197 int clk_id, unsigned int freq, int dir) 210 int clk_id, unsigned int freq, int dir)
@@ -205,20 +218,27 @@ static int cs4270_set_dai_sysclk(struct snd_soc_dai *codec_dai,
205 218
206 cs4270->mclk = freq; 219 cs4270->mclk = freq;
207 220
208 for (i = 0; i < NUM_MCLK_RATIOS; i++) { 221 if (cs4270->mclk) {
209 unsigned int rate = freq / cs4270_mode_ratios[i].ratio; 222 for (i = 0; i < NUM_MCLK_RATIOS; i++) {
210 rates |= snd_pcm_rate_to_rate_bit(rate); 223 unsigned int rate = freq / cs4270_mode_ratios[i].ratio;
211 if (rate < rate_min) 224 rates |= snd_pcm_rate_to_rate_bit(rate);
212 rate_min = rate; 225 if (rate < rate_min)
213 if (rate > rate_max) 226 rate_min = rate;
214 rate_max = rate; 227 if (rate > rate_max)
215 } 228 rate_max = rate;
216 /* FIXME: soc should support a rate list */ 229 }
217 rates &= ~SNDRV_PCM_RATE_KNOT; 230 /* FIXME: soc should support a rate list */
231 rates &= ~SNDRV_PCM_RATE_KNOT;
218 232
219 if (!rates) { 233 if (!rates) {
220 dev_err(codec->dev, "could not find a valid sample rate\n"); 234 dev_err(codec->dev, "could not find a valid sample rate\n");
221 return -EINVAL; 235 return -EINVAL;
236 }
237 } else {
238 /* enable all possible rates */
239 rates = SNDRV_PCM_RATE_8000_192000;
240 rate_min = 8000;
241 rate_max = 192000;
222 } 242 }
223 243
224 codec_dai->playback.rates = rates; 244 codec_dai->playback.rates = rates;
@@ -579,7 +599,8 @@ static int cs4270_probe(struct platform_device *pdev)
579{ 599{
580 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 600 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
581 struct snd_soc_codec *codec = cs4270_codec; 601 struct snd_soc_codec *codec = cs4270_codec;
582 int ret; 602 struct cs4270_private *cs4270 = codec->private_data;
603 int i, ret;
583 604
584 /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */ 605 /* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
585 socdev->card->codec = codec; 606 socdev->card->codec = codec;
@@ -599,6 +620,15 @@ static int cs4270_probe(struct platform_device *pdev)
599 goto error_free_pcms; 620 goto error_free_pcms;
600 } 621 }
601 622
623 /* get the power supply regulators */
624 for (i = 0; i < ARRAY_SIZE(supply_names); i++)
625 cs4270->supplies[i].supply = supply_names[i];
626
627 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies),
628 cs4270->supplies);
629 if (ret < 0)
630 goto error_free_pcms;
631
602 return 0; 632 return 0;
603 633
604error_free_pcms: 634error_free_pcms:
@@ -616,8 +646,11 @@ error_free_pcms:
616static int cs4270_remove(struct platform_device *pdev) 646static int cs4270_remove(struct platform_device *pdev)
617{ 647{
618 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 648 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
649 struct snd_soc_codec *codec = cs4270_codec;
650 struct cs4270_private *cs4270 = codec->private_data;
619 651
620 snd_soc_free_pcms(socdev); 652 snd_soc_free_pcms(socdev);
653 regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
621 654
622 return 0; 655 return 0;
623}; 656};
@@ -799,17 +832,33 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
799static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg) 832static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
800{ 833{
801 struct snd_soc_codec *codec = cs4270_codec; 834 struct snd_soc_codec *codec = cs4270_codec;
802 int reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL; 835 struct cs4270_private *cs4270 = codec->private_data;
836 int reg, ret;
803 837
804 return snd_soc_write(codec, CS4270_PWRCTL, reg); 838 reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
839 if (reg < 0)
840 return reg;
841
842 ret = snd_soc_write(codec, CS4270_PWRCTL, reg);
843 if (ret < 0)
844 return ret;
845
846 regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies),
847 cs4270->supplies);
848
849 return 0;
805} 850}
806 851
807static int cs4270_soc_resume(struct platform_device *pdev) 852static int cs4270_soc_resume(struct platform_device *pdev)
808{ 853{
809 struct snd_soc_codec *codec = cs4270_codec; 854 struct snd_soc_codec *codec = cs4270_codec;
855 struct cs4270_private *cs4270 = codec->private_data;
810 struct i2c_client *i2c_client = codec->control_data; 856 struct i2c_client *i2c_client = codec->control_data;
811 int reg; 857 int reg;
812 858
859 regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
860 cs4270->supplies);
861
813 /* In case the device was put to hard reset during sleep, we need to 862 /* In case the device was put to hard reset during sleep, we need to
814 * wait 500ns here before any I2C communication. */ 863 * wait 500ns here before any I2C communication. */
815 ndelay(500); 864 ndelay(500);
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
new file mode 100644
index 00000000000..cf2975a7294
--- /dev/null
+++ b/sound/soc/codecs/da7210.c
@@ -0,0 +1,589 @@
1/*
2 * DA7210 ALSA Soc codec driver
3 *
4 * Copyright (c) 2009 Dialog Semiconductor
5 * Written by David Chen <Dajun.chen@diasemi.com>
6 *
7 * Copyright (C) 2009 Renesas Solutions Corp.
8 * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
9 *
10 * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/delay.h>
23#include <linux/pm.h>
24#include <linux/i2c.h>
25#include <linux/platform_device.h>
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include <sound/pcm_params.h>
29#include <sound/soc.h>
30#include <sound/soc-dapm.h>
31#include <sound/tlv.h>
32#include <sound/initval.h>
33#include <asm/div64.h>
34
35#include "da7210.h"
36
37/* DA7210 register space */
38#define DA7210_STATUS 0x02
39#define DA7210_STARTUP1 0x03
40#define DA7210_MIC_L 0x07
41#define DA7210_MIC_R 0x08
42#define DA7210_INMIX_L 0x0D
43#define DA7210_INMIX_R 0x0E
44#define DA7210_ADC_HPF 0x0F
45#define DA7210_ADC 0x10
46#define DA7210_DAC_HPF 0x14
47#define DA7210_DAC_L 0x15
48#define DA7210_DAC_R 0x16
49#define DA7210_DAC_SEL 0x17
50#define DA7210_OUTMIX_L 0x1C
51#define DA7210_OUTMIX_R 0x1D
52#define DA7210_HP_L_VOL 0x21
53#define DA7210_HP_R_VOL 0x22
54#define DA7210_HP_CFG 0x23
55#define DA7210_DAI_SRC_SEL 0x25
56#define DA7210_DAI_CFG1 0x26
57#define DA7210_DAI_CFG3 0x28
58#define DA7210_PLL_DIV3 0x2B
59#define DA7210_PLL 0x2C
60
61/* STARTUP1 bit fields */
62#define DA7210_SC_MST_EN (1 << 0)
63
64/* MIC_L bit fields */
65#define DA7210_MICBIAS_EN (1 << 6)
66#define DA7210_MIC_L_EN (1 << 7)
67
68/* MIC_R bit fields */
69#define DA7210_MIC_R_EN (1 << 7)
70
71/* INMIX_L bit fields */
72#define DA7210_IN_L_EN (1 << 7)
73
74/* INMIX_R bit fields */
75#define DA7210_IN_R_EN (1 << 7)
76
77/* ADC_HPF bit fields */
78#define DA7210_ADC_VOICE_EN (1 << 7)
79
80/* ADC bit fields */
81#define DA7210_ADC_L_EN (1 << 3)
82#define DA7210_ADC_R_EN (1 << 7)
83
84/* DAC_HPF fields */
85#define DA7210_DAC_VOICE_EN (1 << 7)
86
87/* DAC_SEL bit fields */
88#define DA7210_DAC_L_SRC_DAI_L (4 << 0)
89#define DA7210_DAC_L_EN (1 << 3)
90#define DA7210_DAC_R_SRC_DAI_R (5 << 4)
91#define DA7210_DAC_R_EN (1 << 7)
92
93/* OUTMIX_L bit fields */
94#define DA7210_OUT_L_EN (1 << 7)
95
96/* OUTMIX_R bit fields */
97#define DA7210_OUT_R_EN (1 << 7)
98
99/* HP_CFG bit fields */
100#define DA7210_HP_2CAP_MODE (1 << 1)
101#define DA7210_HP_SENSE_EN (1 << 2)
102#define DA7210_HP_L_EN (1 << 3)
103#define DA7210_HP_MODE (1 << 6)
104#define DA7210_HP_R_EN (1 << 7)
105
106/* DAI_SRC_SEL bit fields */
107#define DA7210_DAI_OUT_L_SRC (6 << 0)
108#define DA7210_DAI_OUT_R_SRC (7 << 4)
109
110/* DAI_CFG1 bit fields */
111#define DA7210_DAI_WORD_S16_LE (0 << 0)
112#define DA7210_DAI_WORD_S24_LE (2 << 0)
113#define DA7210_DAI_FLEN_64BIT (1 << 2)
114#define DA7210_DAI_MODE_MASTER (1 << 7)
115
116/* DAI_CFG3 bit fields */
117#define DA7210_DAI_FORMAT_I2SMODE (0 << 0)
118#define DA7210_DAI_OE (1 << 3)
119#define DA7210_DAI_EN (1 << 7)
120
121/*PLL_DIV3 bit fields */
122#define DA7210_MCLK_RANGE_10_20_MHZ (1 << 4)
123#define DA7210_PLL_BYP (1 << 6)
124
125/* PLL bit fields */
126#define DA7210_PLL_FS_48000 (11 << 0)
127
128#define DA7210_VERSION "0.0.1"
129
130/* Codec private data */
131struct da7210_priv {
132 struct snd_soc_codec codec;
133};
134
135static struct snd_soc_codec *da7210_codec;
136
137/*
138 * Register cache
139 */
140static const u8 da7210_reg[] = {
141 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R0 - R7 */
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, /* R8 - RF */
143 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x54, /* R10 - R17 */
144 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R18 - R1F */
145 0x00, 0x00, 0x00, 0x02, 0x00, 0x76, 0x00, 0x00, /* R20 - R27 */
146 0x04, 0x00, 0x00, 0x30, 0x2A, 0x00, 0x40, 0x00, /* R28 - R2F */
147 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, /* R30 - R37 */
148 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, /* R38 - R3F */
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R40 - R4F */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R48 - R4F */
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R50 - R57 */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R58 - R5F */
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R60 - R67 */
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R68 - R6F */
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* R70 - R77 */
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x54, 0x00, /* R78 - R7F */
157 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, /* R80 - R87 */
158 0x00, /* R88 */
159};
160
161/*
162 * Read da7210 register cache
163 */
164static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg)
165{
166 u8 *cache = codec->reg_cache;
167 BUG_ON(reg > ARRAY_SIZE(da7210_reg));
168 return cache[reg];
169}
170
171/*
172 * Write to the da7210 register space
173 */
174static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value)
175{
176 u8 *cache = codec->reg_cache;
177 u8 data[2];
178
179 BUG_ON(codec->volatile_register);
180
181 data[0] = reg & 0xff;
182 data[1] = value & 0xff;
183
184 if (reg >= codec->reg_cache_size)
185 return -EIO;
186
187 if (2 != codec->hw_write(codec->control_data, data, 2))
188 return -EIO;
189
190 cache[reg] = value;
191 return 0;
192}
193
194/*
195 * Read from the da7210 register space.
196 */
197static inline u32 da7210_read(struct snd_soc_codec *codec, u32 reg)
198{
199 if (DA7210_STATUS == reg)
200 return i2c_smbus_read_byte_data(codec->control_data, reg);
201
202 return da7210_read_reg_cache(codec, reg);
203}
204
205static int da7210_startup(struct snd_pcm_substream *substream,
206 struct snd_soc_dai *dai)
207{
208 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
209 struct snd_soc_codec *codec = dai->codec;
210
211 if (is_play) {
212 /* PlayBack Volume 40 */
213 snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40);
214 snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40);
215
216 /* Enable Out */
217 snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
218 snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
219
220 } else {
221 /* Volume 7 */
222 snd_soc_update_bits(codec, DA7210_MIC_L, 0x7, 0x7);
223 snd_soc_update_bits(codec, DA7210_MIC_R, 0x7, 0x7);
224
225 /* Enable Mic */
226 snd_soc_update_bits(codec, DA7210_INMIX_L, 0x1F, 0x1);
227 snd_soc_update_bits(codec, DA7210_INMIX_R, 0x1F, 0x1);
228 }
229
230 return 0;
231}
232
233/*
234 * Set PCM DAI word length.
235 */
236static int da7210_hw_params(struct snd_pcm_substream *substream,
237 struct snd_pcm_hw_params *params,
238 struct snd_soc_dai *dai)
239{
240 struct snd_soc_pcm_runtime *rtd = substream->private_data;
241 struct snd_soc_device *socdev = rtd->socdev;
242 struct snd_soc_codec *codec = socdev->card->codec;
243 u32 dai_cfg1;
244 u32 reg, mask;
245
246 /* set DAI source to Left and Right ADC */
247 da7210_write(codec, DA7210_DAI_SRC_SEL,
248 DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC);
249
250 /* Enable DAI */
251 da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
252
253 dai_cfg1 = 0xFC & da7210_read(codec, DA7210_DAI_CFG1);
254
255 switch (params_format(params)) {
256 case SNDRV_PCM_FORMAT_S16_LE:
257 dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
258 break;
259 case SNDRV_PCM_FORMAT_S24_LE:
260 dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
261 break;
262 default:
263 return -EINVAL;
264 }
265
266 da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
267
268 /* FIXME
269 *
270 * It support 48K only now
271 */
272 switch (params_rate(params)) {
273 case 48000:
274 if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
275 reg = DA7210_DAC_HPF;
276 mask = DA7210_DAC_VOICE_EN;
277 } else {
278 reg = DA7210_ADC_HPF;
279 mask = DA7210_ADC_VOICE_EN;
280 }
281 break;
282 default:
283 return -EINVAL;
284 }
285
286 snd_soc_update_bits(codec, reg, mask, 0);
287
288 return 0;
289}
290
291/*
292 * Set DAI mode and Format
293 */
294static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
295{
296 struct snd_soc_codec *codec = codec_dai->codec;
297 u32 dai_cfg1;
298 u32 dai_cfg3;
299
300 dai_cfg1 = 0x7f & da7210_read(codec, DA7210_DAI_CFG1);
301 dai_cfg3 = 0xfc & da7210_read(codec, DA7210_DAI_CFG3);
302
303 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
304 case SND_SOC_DAIFMT_CBM_CFM:
305 dai_cfg1 |= DA7210_DAI_MODE_MASTER;
306 break;
307 default:
308 return -EINVAL;
309 }
310
311 /* FIXME
312 *
313 * It support I2S only now
314 */
315 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
316 case SND_SOC_DAIFMT_I2S:
317 dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE;
318 break;
319 default:
320 return -EINVAL;
321 }
322
323 /* FIXME
324 *
325 * It support 64bit data transmission only now
326 */
327 dai_cfg1 |= DA7210_DAI_FLEN_64BIT;
328
329 da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
330 da7210_write(codec, DA7210_DAI_CFG3, dai_cfg3);
331
332 return 0;
333}
334
335#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
336
337/* DAI operations */
338static struct snd_soc_dai_ops da7210_dai_ops = {
339 .startup = da7210_startup,
340 .hw_params = da7210_hw_params,
341 .set_fmt = da7210_set_dai_fmt,
342};
343
344struct snd_soc_dai da7210_dai = {
345 .name = "DA7210 IIS",
346 .id = 0,
347 /* playback capabilities */
348 .playback = {
349 .stream_name = "Playback",
350 .channels_min = 1,
351 .channels_max = 2,
352 .rates = SNDRV_PCM_RATE_8000_96000,
353 .formats = DA7210_FORMATS,
354 },
355 /* capture capabilities */
356 .capture = {
357 .stream_name = "Capture",
358 .channels_min = 1,
359 .channels_max = 2,
360 .rates = SNDRV_PCM_RATE_8000_96000,
361 .formats = DA7210_FORMATS,
362 },
363 .ops = &da7210_dai_ops,
364};
365EXPORT_SYMBOL_GPL(da7210_dai);
366
367/*
368 * Initialize the DA7210 driver
369 * register the mixer and dsp interfaces with the kernel
370 */
371static int da7210_init(struct da7210_priv *da7210)
372{
373 struct snd_soc_codec *codec = &da7210->codec;
374 int ret = 0;
375
376 if (da7210_codec) {
377 dev_err(codec->dev, "Another da7210 is registered\n");
378 return -EINVAL;
379 }
380
381 mutex_init(&codec->mutex);
382 INIT_LIST_HEAD(&codec->dapm_widgets);
383 INIT_LIST_HEAD(&codec->dapm_paths);
384
385 codec->private_data = da7210;
386 codec->name = "DA7210";
387 codec->owner = THIS_MODULE;
388 codec->read = da7210_read;
389 codec->write = da7210_write;
390 codec->dai = &da7210_dai;
391 codec->num_dai = 1;
392 codec->hw_write = (hw_write_t)i2c_master_send;
393 codec->reg_cache_size = ARRAY_SIZE(da7210_reg);
394 codec->reg_cache = kmemdup(da7210_reg,
395 sizeof(da7210_reg), GFP_KERNEL);
396
397 if (!codec->reg_cache)
398 return -ENOMEM;
399
400 da7210_dai.dev = codec->dev;
401 da7210_codec = codec;
402
403 ret = snd_soc_register_codec(codec);
404 if (ret) {
405 dev_err(codec->dev, "Failed to register CODEC: %d\n", ret);
406 goto init_err;
407 }
408
409 ret = snd_soc_register_dai(&da7210_dai);
410 if (ret) {
411 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
412 goto init_err;
413 }
414
415 /* FIXME
416 *
417 * This driver use fixed value here
418 */
419
420 /*
421 * ADC settings
422 */
423
424 /* Enable Left & Right MIC PGA and Mic Bias */
425 da7210_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
426 da7210_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN);
427
428 /* Enable Left and Right input PGA */
429 da7210_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN);
430 da7210_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN);
431
432 /* Enable Left and Right ADC */
433 da7210_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
434
435 /*
436 * DAC settings
437 */
438
439 /* Enable Left and Right DAC */
440 da7210_write(codec, DA7210_DAC_SEL,
441 DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN |
442 DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN);
443
444 /* Enable Left and Right out PGA */
445 da7210_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
446 da7210_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
447
448 /* Enable Left and Right HeadPhone PGA */
449 da7210_write(codec, DA7210_HP_CFG,
450 DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN |
451 DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN);
452
453 /* Diable PLL and bypass it */
454 da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
455
456 /* Bypass PLL and set MCLK freq rang to 10-20MHz */
457 da7210_write(codec, DA7210_PLL_DIV3,
458 DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
459
460 /* Activate all enabled subsystem */
461 da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
462
463 return ret;
464
465init_err:
466 kfree(codec->reg_cache);
467 codec->reg_cache = NULL;
468
469 return ret;
470
471}
472
473#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
474static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
475 const struct i2c_device_id *id)
476{
477 struct da7210_priv *da7210;
478 struct snd_soc_codec *codec;
479 int ret;
480
481 da7210 = kzalloc(sizeof(struct da7210_priv), GFP_KERNEL);
482 if (!da7210)
483 return -ENOMEM;
484
485 codec = &da7210->codec;
486 codec->dev = &i2c->dev;
487
488 i2c_set_clientdata(i2c, da7210);
489 codec->control_data = i2c;
490
491 ret = da7210_init(da7210);
492 if (ret < 0)
493 pr_err("Failed to initialise da7210 audio codec\n");
494
495 return ret;
496}
497
498static int __devexit da7210_i2c_remove(struct i2c_client *client)
499{
500 struct da7210_priv *da7210 = i2c_get_clientdata(client);
501
502 snd_soc_unregister_dai(&da7210_dai);
503 kfree(da7210->codec.reg_cache);
504 kfree(da7210);
505 da7210_codec = NULL;
506
507 return 0;
508}
509
510static const struct i2c_device_id da7210_i2c_id[] = {
511 { "da7210", 0 },
512 { }
513};
514MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
515
516/* I2C codec control layer */
517static struct i2c_driver da7210_i2c_driver = {
518 .driver = {
519 .name = "DA7210 I2C Codec",
520 .owner = THIS_MODULE,
521 },
522 .probe = da7210_i2c_probe,
523 .remove = __devexit_p(da7210_i2c_remove),
524 .id_table = da7210_i2c_id,
525};
526#endif
527
528static int da7210_probe(struct platform_device *pdev)
529{
530 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
531 struct snd_soc_codec *codec;
532 int ret;
533
534 if (!da7210_codec) {
535 dev_err(&pdev->dev, "Codec device not registered\n");
536 return -ENODEV;
537 }
538
539 socdev->card->codec = da7210_codec;
540 codec = da7210_codec;
541
542 /* Register pcms */
543 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
544 if (ret < 0)
545 goto pcm_err;
546
547 dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
548
549pcm_err:
550 return ret;
551}
552
553static int da7210_remove(struct platform_device *pdev)
554{
555 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
556
557 snd_soc_free_pcms(socdev);
558 snd_soc_dapm_free(socdev);
559
560 return 0;
561}
562
563struct snd_soc_codec_device soc_codec_dev_da7210 = {
564 .probe = da7210_probe,
565 .remove = da7210_remove,
566};
567EXPORT_SYMBOL_GPL(soc_codec_dev_da7210);
568
569static int __init da7210_modinit(void)
570{
571 int ret = 0;
572#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
573 ret = i2c_add_driver(&da7210_i2c_driver);
574#endif
575 return ret;
576}
577module_init(da7210_modinit);
578
579static void __exit da7210_exit(void)
580{
581#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
582 i2c_del_driver(&da7210_i2c_driver);
583#endif
584}
585module_exit(da7210_exit);
586
587MODULE_DESCRIPTION("ASoC DA7210 driver");
588MODULE_AUTHOR("David Chen, Kuninori Morimoto");
589MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/da7210.h b/sound/soc/codecs/da7210.h
new file mode 100644
index 00000000000..390d621eb74
--- /dev/null
+++ b/sound/soc/codecs/da7210.h
@@ -0,0 +1,24 @@
1/*
2 * da7210.h -- audio driver for da7210
3 *
4 * Copyright (c) 2009 Dialog Semiconductor
5 * Written by David Chen <Dajun.chen@diasemi.com>
6 *
7 * Copyright (C) 2009 Renesas Solutions Corp.
8 * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#ifndef _DA7210_H
18#define _DA7210_H
19
20extern struct snd_soc_dai da7210_dai;
21extern struct snd_soc_codec_device soc_codec_dev_da7210;
22
23#endif
24
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 2b4dc2b0b01..e4b946a19ea 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -765,9 +765,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
765 struct snd_soc_codec *codec = socdev->card->codec; 765 struct snd_soc_codec *codec = socdev->card->codec;
766 struct aic3x_priv *aic3x = codec->private_data; 766 struct aic3x_priv *aic3x = codec->private_data;
767 int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; 767 int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
768 u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; 768 u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
769 u16 pll_d = 1; 769 u16 d, pll_d = 1;
770 u8 reg; 770 u8 reg;
771 int clk;
771 772
772 /* select data word length */ 773 /* select data word length */
773 data = 774 data =
@@ -833,48 +834,70 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
833 if (bypass_pll) 834 if (bypass_pll)
834 return 0; 835 return 0;
835 836
836 /* Use PLL 837 /* Use PLL, compute apropriate setup for j, d, r and p, the closest
837 * find an apropriate setup for j, d, r and p by iterating over 838 * one wins the game. Try with d==0 first, next with d!=0.
838 * p and r - j and d are calculated for each fraction. 839 * Constraints for j are according to the datasheet.
839 * Up to 128 values are probed, the closest one wins the game.
840 * The sysclk is divided by 1000 to prevent integer overflows. 840 * The sysclk is divided by 1000 to prevent integer overflows.
841 */ 841 */
842
842 codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); 843 codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000);
843 844
844 for (r = 1; r <= 16; r++) 845 for (r = 1; r <= 16; r++)
845 for (p = 1; p <= 8; p++) { 846 for (p = 1; p <= 8; p++) {
846 int clk, tmp = (codec_clk * pll_r * 10) / pll_p; 847 for (j = 4; j <= 55; j++) {
847 u8 j = tmp / 10000; 848 /* This is actually 1000*((j+(d/10000))*r)/p
848 u16 d = tmp % 10000; 849 * The term had to be converted to get
850 * rid of the division by 10000; d = 0 here
851 */
852 int tmp_clk = (1000 * j * r) / p;
853
854 /* Check whether this values get closer than
855 * the best ones we had before
856 */
857 if (abs(codec_clk - tmp_clk) <
858 abs(codec_clk - last_clk)) {
859 pll_j = j; pll_d = 0;
860 pll_r = r; pll_p = p;
861 last_clk = tmp_clk;
862 }
863
864 /* Early exit for exact matches */
865 if (tmp_clk == codec_clk)
866 goto found;
867 }
868 }
849 869
850 if (j > 63) 870 /* try with d != 0 */
851 continue; 871 for (p = 1; p <= 8; p++) {
872 j = codec_clk * p / 1000;
852 873
853 if (d != 0 && aic3x->sysclk < 10000000) 874 if (j < 4 || j > 11)
854 continue; 875 continue;
855 876
856 /* This is actually 1000 * ((j + (d/10000)) * r) / p 877 /* do not use codec_clk here since we'd loose precision */
857 * The term had to be converted to get rid of the 878 d = ((2048 * p * fsref) - j * aic3x->sysclk)
858 * division by 10000 */ 879 * 100 / (aic3x->sysclk/100);
859 clk = ((10000 * j * r) + (d * r)) / (10 * p);
860 880
861 /* check whether this values get closer than the best 881 clk = (10000 * j + d) / (10 * p);
862 * ones we had before */
863 if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
864 pll_j = j; pll_d = d; pll_r = r; pll_p = p;
865 last_clk = clk;
866 }
867 882
868 /* Early exit for exact matches */ 883 /* check whether this values get closer than the best
869 if (clk == codec_clk) 884 * ones we had before */
870 break; 885 if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
886 pll_j = j; pll_d = d; pll_r = 1; pll_p = p;
887 last_clk = clk;
871 } 888 }
872 889
890 /* Early exit for exact matches */
891 if (clk == codec_clk)
892 goto found;
893 }
894
873 if (last_clk == 0) { 895 if (last_clk == 0) {
874 printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); 896 printk(KERN_ERR "%s(): unable to setup PLL\n", __func__);
875 return -EINVAL; 897 return -EINVAL;
876 } 898 }
877 899
900found:
878 data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); 901 data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
879 aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); 902 aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
880 aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT); 903 aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 9c8903dbe64..1b35d0cf336 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -30,6 +30,7 @@
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <linux/interrupt.h> 31#include <linux/interrupt.h>
32#include <linux/gpio.h> 32#include <linux/gpio.h>
33#include <linux/regulator/consumer.h>
33#include <sound/core.h> 34#include <sound/core.h>
34#include <sound/pcm.h> 35#include <sound/pcm.h>
35#include <sound/pcm_params.h> 36#include <sound/pcm_params.h>
@@ -58,11 +59,26 @@ enum dac33_state {
58 DAC33_FLUSH, 59 DAC33_FLUSH,
59}; 60};
60 61
62enum dac33_fifo_modes {
63 DAC33_FIFO_BYPASS = 0,
64 DAC33_FIFO_MODE1,
65 DAC33_FIFO_MODE7,
66 DAC33_FIFO_LAST_MODE,
67};
68
69#define DAC33_NUM_SUPPLIES 3
70static const char *dac33_supply_names[DAC33_NUM_SUPPLIES] = {
71 "AVDD",
72 "DVDD",
73 "IOVDD",
74};
75
61struct tlv320dac33_priv { 76struct tlv320dac33_priv {
62 struct mutex mutex; 77 struct mutex mutex;
63 struct workqueue_struct *dac33_wq; 78 struct workqueue_struct *dac33_wq;
64 struct work_struct work; 79 struct work_struct work;
65 struct snd_soc_codec codec; 80 struct snd_soc_codec codec;
81 struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
66 int power_gpio; 82 int power_gpio;
67 int chip_power; 83 int chip_power;
68 int irq; 84 int irq;
@@ -73,8 +89,9 @@ struct tlv320dac33_priv {
73 * this */ 89 * this */
74 unsigned int nsample_max; /* nsample should not be higher than 90 unsigned int nsample_max; /* nsample should not be higher than
75 * this */ 91 * this */
76 unsigned int nsample_switch; /* Use FIFO or bypass FIFO switch */ 92 enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
77 unsigned int nsample; /* burst read amount from host */ 93 unsigned int nsample; /* burst read amount from host */
94 u8 burst_bclkdiv; /* BCLK divider value in burst mode */
78 95
79 enum dac33_state state; 96 enum dac33_state state;
80}; 97};
@@ -297,28 +314,49 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
297 dac33_write(codec, DAC33_PWR_CTRL, reg); 314 dac33_write(codec, DAC33_PWR_CTRL, reg);
298} 315}
299 316
300static void dac33_hard_power(struct snd_soc_codec *codec, int power) 317static int dac33_hard_power(struct snd_soc_codec *codec, int power)
301{ 318{
302 struct tlv320dac33_priv *dac33 = codec->private_data; 319 struct tlv320dac33_priv *dac33 = codec->private_data;
320 int ret;
303 321
304 mutex_lock(&dac33->mutex); 322 mutex_lock(&dac33->mutex);
305 if (power) { 323 if (power) {
306 if (dac33->power_gpio >= 0) { 324 ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
307 gpio_set_value(dac33->power_gpio, 1); 325 dac33->supplies);
308 dac33->chip_power = 1; 326 if (ret != 0) {
309 /* Restore registers */ 327 dev_err(codec->dev,
310 dac33_restore_regs(codec); 328 "Failed to enable supplies: %d\n", ret);
329 goto exit;
311 } 330 }
331
332 if (dac33->power_gpio >= 0)
333 gpio_set_value(dac33->power_gpio, 1);
334
335 dac33->chip_power = 1;
336
337 /* Restore registers */
338 dac33_restore_regs(codec);
339
312 dac33_soft_power(codec, 1); 340 dac33_soft_power(codec, 1);
313 } else { 341 } else {
314 dac33_soft_power(codec, 0); 342 dac33_soft_power(codec, 0);
315 if (dac33->power_gpio >= 0) { 343 if (dac33->power_gpio >= 0)
316 gpio_set_value(dac33->power_gpio, 0); 344 gpio_set_value(dac33->power_gpio, 0);
317 dac33->chip_power = 0; 345
346 ret = regulator_bulk_disable(ARRAY_SIZE(dac33->supplies),
347 dac33->supplies);
348 if (ret != 0) {
349 dev_err(codec->dev,
350 "Failed to disable supplies: %d\n", ret);
351 goto exit;
318 } 352 }
353
354 dac33->chip_power = 0;
319 } 355 }
320 mutex_unlock(&dac33->mutex);
321 356
357exit:
358 mutex_unlock(&dac33->mutex);
359 return ret;
322} 360}
323 361
324static int dac33_get_nsample(struct snd_kcontrol *kcontrol, 362static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
@@ -351,39 +389,48 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
351 return ret; 389 return ret;
352} 390}
353 391
354static int dac33_get_nsample_switch(struct snd_kcontrol *kcontrol, 392static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
355 struct snd_ctl_elem_value *ucontrol) 393 struct snd_ctl_elem_value *ucontrol)
356{ 394{
357 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 395 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
358 struct tlv320dac33_priv *dac33 = codec->private_data; 396 struct tlv320dac33_priv *dac33 = codec->private_data;
359 397
360 ucontrol->value.integer.value[0] = dac33->nsample_switch; 398 ucontrol->value.integer.value[0] = dac33->fifo_mode;
361 399
362 return 0; 400 return 0;
363} 401}
364 402
365static int dac33_set_nsample_switch(struct snd_kcontrol *kcontrol, 403static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_value *ucontrol) 404 struct snd_ctl_elem_value *ucontrol)
367{ 405{
368 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 406 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
369 struct tlv320dac33_priv *dac33 = codec->private_data; 407 struct tlv320dac33_priv *dac33 = codec->private_data;
370 int ret = 0; 408 int ret = 0;
371 409
372 if (dac33->nsample_switch == ucontrol->value.integer.value[0]) 410 if (dac33->fifo_mode == ucontrol->value.integer.value[0])
373 return 0; 411 return 0;
374 /* Do not allow changes while stream is running*/ 412 /* Do not allow changes while stream is running*/
375 if (codec->active) 413 if (codec->active)
376 return -EPERM; 414 return -EPERM;
377 415
378 if (ucontrol->value.integer.value[0] < 0 || 416 if (ucontrol->value.integer.value[0] < 0 ||
379 ucontrol->value.integer.value[0] > 1) 417 ucontrol->value.integer.value[0] >= DAC33_FIFO_LAST_MODE)
380 ret = -EINVAL; 418 ret = -EINVAL;
381 else 419 else
382 dac33->nsample_switch = ucontrol->value.integer.value[0]; 420 dac33->fifo_mode = ucontrol->value.integer.value[0];
383 421
384 return ret; 422 return ret;
385} 423}
386 424
425/* Codec operation modes */
426static const char *dac33_fifo_mode_texts[] = {
427 "Bypass", "Mode 1", "Mode 7"
428};
429
430static const struct soc_enum dac33_fifo_mode_enum =
431 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts),
432 dac33_fifo_mode_texts);
433
387/* 434/*
388 * DACL/R digital volume control: 435 * DACL/R digital volume control:
389 * from 0 dB to -63.5 in 0.5 dB steps 436 * from 0 dB to -63.5 in 0.5 dB steps
@@ -406,8 +453,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
406static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { 453static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = {
407 SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, 454 SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
408 dac33_get_nsample, dac33_set_nsample), 455 dac33_get_nsample, dac33_set_nsample),
409 SOC_SINGLE_EXT("nSample Switch", 0, 0, 1, 0, 456 SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum,
410 dac33_get_nsample_switch, dac33_set_nsample_switch), 457 dac33_get_fifo_mode, dac33_set_fifo_mode),
411}; 458};
412 459
413/* Analog bypass */ 460/* Analog bypass */
@@ -469,6 +516,8 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
469static int dac33_set_bias_level(struct snd_soc_codec *codec, 516static int dac33_set_bias_level(struct snd_soc_codec *codec,
470 enum snd_soc_bias_level level) 517 enum snd_soc_bias_level level)
471{ 518{
519 int ret;
520
472 switch (level) { 521 switch (level) {
473 case SND_SOC_BIAS_ON: 522 case SND_SOC_BIAS_ON:
474 dac33_soft_power(codec, 1); 523 dac33_soft_power(codec, 1);
@@ -476,12 +525,19 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
476 case SND_SOC_BIAS_PREPARE: 525 case SND_SOC_BIAS_PREPARE:
477 break; 526 break;
478 case SND_SOC_BIAS_STANDBY: 527 case SND_SOC_BIAS_STANDBY:
479 if (codec->bias_level == SND_SOC_BIAS_OFF) 528 if (codec->bias_level == SND_SOC_BIAS_OFF) {
480 dac33_hard_power(codec, 1); 529 ret = dac33_hard_power(codec, 1);
530 if (ret != 0)
531 return ret;
532 }
533
481 dac33_soft_power(codec, 0); 534 dac33_soft_power(codec, 0);
482 break; 535 break;
483 case SND_SOC_BIAS_OFF: 536 case SND_SOC_BIAS_OFF:
484 dac33_hard_power(codec, 0); 537 ret = dac33_hard_power(codec, 0);
538 if (ret != 0)
539 return ret;
540
485 break; 541 break;
486 } 542 }
487 codec->bias_level = level; 543 codec->bias_level = level;
@@ -489,6 +545,51 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
489 return 0; 545 return 0;
490} 546}
491 547
548static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
549{
550 struct snd_soc_codec *codec;
551
552 codec = &dac33->codec;
553
554 switch (dac33->fifo_mode) {
555 case DAC33_FIFO_MODE1:
556 dac33_write16(codec, DAC33_NSAMPLE_MSB,
557 DAC33_THRREG(dac33->nsample));
558 dac33_write16(codec, DAC33_PREFILL_MSB,
559 DAC33_THRREG(dac33->alarm_threshold));
560 break;
561 case DAC33_FIFO_MODE7:
562 dac33_write16(codec, DAC33_PREFILL_MSB,
563 DAC33_THRREG(10));
564 break;
565 default:
566 dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
567 dac33->fifo_mode);
568 break;
569 }
570}
571
572static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
573{
574 struct snd_soc_codec *codec;
575
576 codec = &dac33->codec;
577
578 switch (dac33->fifo_mode) {
579 case DAC33_FIFO_MODE1:
580 dac33_write16(codec, DAC33_NSAMPLE_MSB,
581 DAC33_THRREG(dac33->nsample));
582 break;
583 case DAC33_FIFO_MODE7:
584 /* At the moment we are not using interrupts in mode7 */
585 break;
586 default:
587 dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
588 dac33->fifo_mode);
589 break;
590 }
591}
592
492static void dac33_work(struct work_struct *work) 593static void dac33_work(struct work_struct *work)
493{ 594{
494 struct snd_soc_codec *codec; 595 struct snd_soc_codec *codec;
@@ -502,14 +603,10 @@ static void dac33_work(struct work_struct *work)
502 switch (dac33->state) { 603 switch (dac33->state) {
503 case DAC33_PREFILL: 604 case DAC33_PREFILL:
504 dac33->state = DAC33_PLAYBACK; 605 dac33->state = DAC33_PLAYBACK;
505 dac33_write16(codec, DAC33_NSAMPLE_MSB, 606 dac33_prefill_handler(dac33);
506 DAC33_THRREG(dac33->nsample));
507 dac33_write16(codec, DAC33_PREFILL_MSB,
508 DAC33_THRREG(dac33->alarm_threshold));
509 break; 607 break;
510 case DAC33_PLAYBACK: 608 case DAC33_PLAYBACK:
511 dac33_write16(codec, DAC33_NSAMPLE_MSB, 609 dac33_playback_handler(dac33);
512 DAC33_THRREG(dac33->nsample));
513 break; 610 break;
514 case DAC33_IDLE: 611 case DAC33_IDLE:
515 break; 612 break;
@@ -547,7 +644,7 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
547 unsigned int pwr_ctrl; 644 unsigned int pwr_ctrl;
548 645
549 /* Stop pending workqueue */ 646 /* Stop pending workqueue */
550 if (dac33->nsample_switch) 647 if (dac33->fifo_mode)
551 cancel_work_sync(&dac33->work); 648 cancel_work_sync(&dac33->work);
552 649
553 mutex_lock(&dac33->mutex); 650 mutex_lock(&dac33->mutex);
@@ -619,7 +716,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
619 struct snd_soc_codec *codec = socdev->card->codec; 716 struct snd_soc_codec *codec = socdev->card->codec;
620 struct tlv320dac33_priv *dac33 = codec->private_data; 717 struct tlv320dac33_priv *dac33 = codec->private_data;
621 unsigned int oscset, ratioset, pwr_ctrl, reg_tmp; 718 unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
622 u8 aictrl_a, fifoctrl_a; 719 u8 aictrl_a, aictrl_b, fifoctrl_a;
623 720
624 switch (substream->runtime->rate) { 721 switch (substream->runtime->rate) {
625 case 44100: 722 case 44100:
@@ -675,7 +772,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
675 772
676 dac33_oscwait(codec); 773 dac33_oscwait(codec);
677 774
678 if (dac33->nsample_switch) { 775 if (dac33->fifo_mode) {
776 /* Generic for all FIFO modes */
679 /* 50-51 : ASRC Control registers */ 777 /* 50-51 : ASRC Control registers */
680 dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ 778 dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */
681 dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ 779 dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */
@@ -685,38 +783,101 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
685 783
686 /* Set interrupts to high active */ 784 /* Set interrupts to high active */
687 dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH); 785 dac33_write(codec, DAC33_INTP_CTRL_A, DAC33_INTPM_AHIGH);
688
689 dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
690 DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
691 dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
692 } else { 786 } else {
787 /* FIFO bypass mode */
693 /* 50-51 : ASRC Control registers */ 788 /* 50-51 : ASRC Control registers */
694 dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP); 789 dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCBYP);
695 dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */ 790 dac33_write(codec, DAC33_ASRC_CTRL_B, 0); /* ??? */
696 } 791 }
697 792
698 if (dac33->nsample_switch) 793 /* Interrupt behaviour configuration */
794 switch (dac33->fifo_mode) {
795 case DAC33_FIFO_MODE1:
796 dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
797 DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
798 dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
799 break;
800 case DAC33_FIFO_MODE7:
801 /* Disable all interrupts */
802 dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0);
803 break;
804 default:
805 /* in FIFO bypass mode, the interrupts are not used */
806 break;
807 }
808
809 aictrl_b = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
810
811 switch (dac33->fifo_mode) {
812 case DAC33_FIFO_MODE1:
813 /*
814 * For mode1:
815 * Disable the FIFO bypass (Enable the use of FIFO)
816 * Select nSample mode
817 * BCLK is only running when data is needed by DAC33
818 */
699 fifoctrl_a &= ~DAC33_FBYPAS; 819 fifoctrl_a &= ~DAC33_FBYPAS;
700 else 820 fifoctrl_a &= ~DAC33_FAUTO;
821 aictrl_b &= ~DAC33_BCLKON;
822 break;
823 case DAC33_FIFO_MODE7:
824 /*
825 * For mode1:
826 * Disable the FIFO bypass (Enable the use of FIFO)
827 * Select Threshold mode
828 * BCLK is only running when data is needed by DAC33
829 */
830 fifoctrl_a &= ~DAC33_FBYPAS;
831 fifoctrl_a |= DAC33_FAUTO;
832 aictrl_b &= ~DAC33_BCLKON;
833 break;
834 default:
835 /*
836 * For FIFO bypass mode:
837 * Enable the FIFO bypass (Disable the FIFO use)
838 * Set the BCLK as continous
839 */
701 fifoctrl_a |= DAC33_FBYPAS; 840 fifoctrl_a |= DAC33_FBYPAS;
702 dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a); 841 aictrl_b |= DAC33_BCLKON;
842 break;
843 }
703 844
845 dac33_write(codec, DAC33_FIFO_CTRL_A, fifoctrl_a);
704 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a); 846 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_A, aictrl_a);
705 reg_tmp = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B); 847 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, aictrl_b);
706 if (dac33->nsample_switch)
707 reg_tmp &= ~DAC33_BCLKON;
708 else
709 reg_tmp |= DAC33_BCLKON;
710 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg_tmp);
711 848
712 if (dac33->nsample_switch) { 849 /*
713 /* 20: BCLK divide ratio */ 850 * BCLK divide ratio
714 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 3); 851 * 0: 1.5
852 * 1: 1
853 * 2: 2
854 * ...
855 * 254: 254
856 * 255: 255
857 */
858 if (dac33->fifo_mode)
859 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C,
860 dac33->burst_bclkdiv);
861 else
862 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
715 863
864 switch (dac33->fifo_mode) {
865 case DAC33_FIFO_MODE1:
716 dac33_write16(codec, DAC33_ATHR_MSB, 866 dac33_write16(codec, DAC33_ATHR_MSB,
717 DAC33_THRREG(dac33->alarm_threshold)); 867 DAC33_THRREG(dac33->alarm_threshold));
718 } else { 868 break;
719 dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32); 869 case DAC33_FIFO_MODE7:
870 /*
871 * Configure the threshold levels, and leave 10 sample space
872 * at the bottom, and also at the top of the FIFO
873 */
874 dac33_write16(codec, DAC33_UTHR_MSB,
875 DAC33_THRREG(DAC33_BUFFER_SIZE_SAMPLES - 10));
876 dac33_write16(codec, DAC33_LTHR_MSB,
877 DAC33_THRREG(10));
878 break;
879 default:
880 break;
720 } 881 }
721 882
722 mutex_unlock(&dac33->mutex); 883 mutex_unlock(&dac33->mutex);
@@ -789,7 +950,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
789 case SNDRV_PCM_TRIGGER_START: 950 case SNDRV_PCM_TRIGGER_START:
790 case SNDRV_PCM_TRIGGER_RESUME: 951 case SNDRV_PCM_TRIGGER_RESUME:
791 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 952 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
792 if (dac33->nsample_switch) { 953 if (dac33->fifo_mode) {
793 dac33->state = DAC33_PREFILL; 954 dac33->state = DAC33_PREFILL;
794 queue_work(dac33->dac33_wq, &dac33->work); 955 queue_work(dac33->dac33_wq, &dac33->work);
795 } 956 }
@@ -797,7 +958,7 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
797 case SNDRV_PCM_TRIGGER_STOP: 958 case SNDRV_PCM_TRIGGER_STOP:
798 case SNDRV_PCM_TRIGGER_SUSPEND: 959 case SNDRV_PCM_TRIGGER_SUSPEND:
799 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 960 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
800 if (dac33->nsample_switch) { 961 if (dac33->fifo_mode) {
801 dac33->state = DAC33_FLUSH; 962 dac33->state = DAC33_FLUSH;
802 queue_work(dac33->dac33_wq, &dac33->work); 963 queue_work(dac33->dac33_wq, &dac33->work);
803 } 964 }
@@ -843,6 +1004,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
843 unsigned int fmt) 1004 unsigned int fmt)
844{ 1005{
845 struct snd_soc_codec *codec = codec_dai->codec; 1006 struct snd_soc_codec *codec = codec_dai->codec;
1007 struct tlv320dac33_priv *dac33 = codec->private_data;
846 u8 aictrl_a, aictrl_b; 1008 u8 aictrl_a, aictrl_b;
847 1009
848 aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A); 1010 aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
@@ -855,7 +1017,11 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
855 break; 1017 break;
856 case SND_SOC_DAIFMT_CBS_CFS: 1018 case SND_SOC_DAIFMT_CBS_CFS:
857 /* Codec Slave */ 1019 /* Codec Slave */
858 aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK); 1020 if (dac33->fifo_mode) {
1021 dev_err(codec->dev, "FIFO mode requires master mode\n");
1022 return -EINVAL;
1023 } else
1024 aictrl_a &= ~(DAC33_MSBCLK | DAC33_MSWCLK);
859 break; 1025 break;
860 default: 1026 default:
861 return -EINVAL; 1027 return -EINVAL;
@@ -959,6 +1125,9 @@ static int dac33_soc_probe(struct platform_device *pdev)
959 /* power on device */ 1125 /* power on device */
960 dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1126 dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
961 1127
1128 /* Bias level configuration has enabled regulator an extra time */
1129 regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
1130
962 return 0; 1131 return 0;
963 1132
964pcm_err: 1133pcm_err:
@@ -1033,13 +1202,13 @@ struct snd_soc_dai dac33_dai = {
1033}; 1202};
1034EXPORT_SYMBOL_GPL(dac33_dai); 1203EXPORT_SYMBOL_GPL(dac33_dai);
1035 1204
1036static int dac33_i2c_probe(struct i2c_client *client, 1205static int __devinit dac33_i2c_probe(struct i2c_client *client,
1037 const struct i2c_device_id *id) 1206 const struct i2c_device_id *id)
1038{ 1207{
1039 struct tlv320dac33_platform_data *pdata; 1208 struct tlv320dac33_platform_data *pdata;
1040 struct tlv320dac33_priv *dac33; 1209 struct tlv320dac33_priv *dac33;
1041 struct snd_soc_codec *codec; 1210 struct snd_soc_codec *codec;
1042 int ret = 0; 1211 int ret, i;
1043 1212
1044 if (client->dev.platform_data == NULL) { 1213 if (client->dev.platform_data == NULL) {
1045 dev_err(&client->dev, "Platform data not set\n"); 1214 dev_err(&client->dev, "Platform data not set\n");
@@ -1080,10 +1249,11 @@ static int dac33_i2c_probe(struct i2c_client *client,
1080 i2c_set_clientdata(client, dac33); 1249 i2c_set_clientdata(client, dac33);
1081 1250
1082 dac33->power_gpio = pdata->power_gpio; 1251 dac33->power_gpio = pdata->power_gpio;
1252 dac33->burst_bclkdiv = pdata->burst_bclkdiv;
1083 dac33->irq = client->irq; 1253 dac33->irq = client->irq;
1084 dac33->nsample = NSAMPLE_MAX; 1254 dac33->nsample = NSAMPLE_MAX;
1085 /* Disable FIFO use by default */ 1255 /* Disable FIFO use by default */
1086 dac33->nsample_switch = 0; 1256 dac33->fifo_mode = DAC33_FIFO_BYPASS;
1087 1257
1088 tlv320dac33_codec = codec; 1258 tlv320dac33_codec = codec;
1089 1259
@@ -1130,6 +1300,24 @@ static int dac33_i2c_probe(struct i2c_client *client,
1130 } 1300 }
1131 } 1301 }
1132 1302
1303 for (i = 0; i < ARRAY_SIZE(dac33->supplies); i++)
1304 dac33->supplies[i].supply = dac33_supply_names[i];
1305
1306 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(dac33->supplies),
1307 dac33->supplies);
1308
1309 if (ret != 0) {
1310 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
1311 goto err_get;
1312 }
1313
1314 ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
1315 dac33->supplies);
1316 if (ret != 0) {
1317 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
1318 goto err_enable;
1319 }
1320
1133 ret = snd_soc_register_codec(codec); 1321 ret = snd_soc_register_codec(codec);
1134 if (ret != 0) { 1322 if (ret != 0) {
1135 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 1323 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
@@ -1149,6 +1337,10 @@ static int dac33_i2c_probe(struct i2c_client *client,
1149 return ret; 1337 return ret;
1150 1338
1151error_codec: 1339error_codec:
1340 regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
1341err_enable:
1342 regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
1343err_get:
1152 if (dac33->irq >= 0) { 1344 if (dac33->irq >= 0) {
1153 free_irq(dac33->irq, &dac33->codec); 1345 free_irq(dac33->irq, &dac33->codec);
1154 destroy_workqueue(dac33->dac33_wq); 1346 destroy_workqueue(dac33->dac33_wq);
@@ -1165,7 +1357,7 @@ error_reg:
1165 return ret; 1357 return ret;
1166} 1358}
1167 1359
1168static int dac33_i2c_remove(struct i2c_client *client) 1360static int __devexit dac33_i2c_remove(struct i2c_client *client)
1169{ 1361{
1170 struct tlv320dac33_priv *dac33; 1362 struct tlv320dac33_priv *dac33;
1171 1363
@@ -1177,6 +1369,8 @@ static int dac33_i2c_remove(struct i2c_client *client)
1177 if (dac33->irq >= 0) 1369 if (dac33->irq >= 0)
1178 free_irq(dac33->irq, &dac33->codec); 1370 free_irq(dac33->irq, &dac33->codec);
1179 1371
1372 regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
1373
1180 destroy_workqueue(dac33->dac33_wq); 1374 destroy_workqueue(dac33->dac33_wq);
1181 snd_soc_unregister_dai(&dac33_dai); 1375 snd_soc_unregister_dai(&dac33_dai);
1182 snd_soc_unregister_codec(&dac33->codec); 1376 snd_soc_unregister_codec(&dac33->codec);
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 6b650c1aa3d..958d49c969a 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -25,6 +25,7 @@
25#include <linux/device.h> 25#include <linux/device.h>
26#include <linux/i2c.h> 26#include <linux/i2c.h>
27#include <linux/gpio.h> 27#include <linux/gpio.h>
28#include <linux/regulator/consumer.h>
28#include <sound/tpa6130a2-plat.h> 29#include <sound/tpa6130a2-plat.h>
29#include <sound/soc.h> 30#include <sound/soc.h>
30#include <sound/soc-dapm.h> 31#include <sound/soc-dapm.h>
@@ -34,10 +35,22 @@
34 35
35static struct i2c_client *tpa6130a2_client; 36static struct i2c_client *tpa6130a2_client;
36 37
38#define TPA6130A2_NUM_SUPPLIES 2
39static const char *tpa6130a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
40 "CPVSS",
41 "Vdd",
42};
43
44static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
45 "HPVdd",
46 "AVdd",
47};
48
37/* This struct is used to save the context */ 49/* This struct is used to save the context */
38struct tpa6130a2_data { 50struct tpa6130a2_data {
39 struct mutex mutex; 51 struct mutex mutex;
40 unsigned char regs[TPA6130A2_CACHEREGNUM]; 52 unsigned char regs[TPA6130A2_CACHEREGNUM];
53 struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES];
41 int power_gpio; 54 int power_gpio;
42 unsigned char power_state; 55 unsigned char power_state;
43}; 56};
@@ -106,10 +119,11 @@ static void tpa6130a2_initialize(void)
106 tpa6130a2_i2c_write(i, data->regs[i]); 119 tpa6130a2_i2c_write(i, data->regs[i]);
107} 120}
108 121
109static void tpa6130a2_power(int power) 122static int tpa6130a2_power(int power)
110{ 123{
111 struct tpa6130a2_data *data; 124 struct tpa6130a2_data *data;
112 u8 val; 125 u8 val;
126 int ret;
113 127
114 BUG_ON(tpa6130a2_client == NULL); 128 BUG_ON(tpa6130a2_client == NULL);
115 data = i2c_get_clientdata(tpa6130a2_client); 129 data = i2c_get_clientdata(tpa6130a2_client);
@@ -117,11 +131,20 @@ static void tpa6130a2_power(int power)
117 mutex_lock(&data->mutex); 131 mutex_lock(&data->mutex);
118 if (power) { 132 if (power) {
119 /* Power on */ 133 /* Power on */
120 if (data->power_gpio >= 0) { 134 if (data->power_gpio >= 0)
121 gpio_set_value(data->power_gpio, 1); 135 gpio_set_value(data->power_gpio, 1);
122 data->power_state = 1; 136
123 tpa6130a2_initialize(); 137 ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies),
138 data->supplies);
139 if (ret != 0) {
140 dev_err(&tpa6130a2_client->dev,
141 "Failed to enable supplies: %d\n", ret);
142 goto exit;
124 } 143 }
144
145 data->power_state = 1;
146 tpa6130a2_initialize();
147
125 /* Clear SWS */ 148 /* Clear SWS */
126 val = tpa6130a2_read(TPA6130A2_REG_CONTROL); 149 val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
127 val &= ~TPA6130A2_SWS; 150 val &= ~TPA6130A2_SWS;
@@ -131,13 +154,25 @@ static void tpa6130a2_power(int power)
131 val = tpa6130a2_read(TPA6130A2_REG_CONTROL); 154 val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
132 val |= TPA6130A2_SWS; 155 val |= TPA6130A2_SWS;
133 tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); 156 tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
157
134 /* Power off */ 158 /* Power off */
135 if (data->power_gpio >= 0) { 159 if (data->power_gpio >= 0)
136 gpio_set_value(data->power_gpio, 0); 160 gpio_set_value(data->power_gpio, 0);
137 data->power_state = 0; 161
162 ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies),
163 data->supplies);
164 if (ret != 0) {
165 dev_err(&tpa6130a2_client->dev,
166 "Failed to disable supplies: %d\n", ret);
167 goto exit;
138 } 168 }
169
170 data->power_state = 0;
139 } 171 }
172
173exit:
140 mutex_unlock(&data->mutex); 174 mutex_unlock(&data->mutex);
175 return ret;
141} 176}
142 177
143static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, 178static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
@@ -237,12 +272,8 @@ static const struct snd_kcontrol_new tpa6130a2_controls[] = {
237 */ 272 */
238static void tpa6130a2_channel_enable(u8 channel, int enable) 273static void tpa6130a2_channel_enable(u8 channel, int enable)
239{ 274{
240 struct tpa6130a2_data *data;
241 u8 val; 275 u8 val;
242 276
243 BUG_ON(tpa6130a2_client == NULL);
244 data = i2c_get_clientdata(tpa6130a2_client);
245
246 if (enable) { 277 if (enable) {
247 /* Enable channel */ 278 /* Enable channel */
248 /* Enable amplifier */ 279 /* Enable amplifier */
@@ -299,15 +330,17 @@ static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
299static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w, 330static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
300 struct snd_kcontrol *kcontrol, int event) 331 struct snd_kcontrol *kcontrol, int event)
301{ 332{
333 int ret = 0;
334
302 switch (event) { 335 switch (event) {
303 case SND_SOC_DAPM_POST_PMU: 336 case SND_SOC_DAPM_POST_PMU:
304 tpa6130a2_power(1); 337 ret = tpa6130a2_power(1);
305 break; 338 break;
306 case SND_SOC_DAPM_POST_PMD: 339 case SND_SOC_DAPM_POST_PMD:
307 tpa6130a2_power(0); 340 ret = tpa6130a2_power(0);
308 break; 341 break;
309 } 342 }
310 return 0; 343 return ret;
311} 344}
312 345
313static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { 346static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
@@ -346,13 +379,13 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
346} 379}
347EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); 380EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
348 381
349static int tpa6130a2_probe(struct i2c_client *client, 382static int __devinit tpa6130a2_probe(struct i2c_client *client,
350 const struct i2c_device_id *id) 383 const struct i2c_device_id *id)
351{ 384{
352 struct device *dev; 385 struct device *dev;
353 struct tpa6130a2_data *data; 386 struct tpa6130a2_data *data;
354 struct tpa6130a2_platform_data *pdata; 387 struct tpa6130a2_platform_data *pdata;
355 int ret; 388 int i, ret;
356 389
357 dev = &client->dev; 390 dev = &client->dev;
358 391
@@ -387,15 +420,38 @@ static int tpa6130a2_probe(struct i2c_client *client,
387 if (ret < 0) { 420 if (ret < 0) {
388 dev_err(dev, "Failed to request power GPIO (%d)\n", 421 dev_err(dev, "Failed to request power GPIO (%d)\n",
389 data->power_gpio); 422 data->power_gpio);
390 goto fail; 423 goto err_gpio;
391 } 424 }
392 gpio_direction_output(data->power_gpio, 0); 425 gpio_direction_output(data->power_gpio, 0);
393 } else {
394 data->power_state = 1;
395 tpa6130a2_initialize();
396 } 426 }
397 427
398 tpa6130a2_power(1); 428 switch (pdata->id) {
429 case TPA6130A2:
430 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
431 data->supplies[i].supply = tpa6130a2_supply_names[i];
432 break;
433 case TPA6140A2:
434 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
435 data->supplies[i].supply = tpa6140a2_supply_names[i];;
436 break;
437 default:
438 dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
439 pdata->id);
440 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
441 data->supplies[i].supply = tpa6130a2_supply_names[i];
442 }
443
444 ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
445 data->supplies);
446 if (ret != 0) {
447 dev_err(dev, "Failed to request supplies: %d\n", ret);
448 goto err_regulator;
449 }
450
451 ret = tpa6130a2_power(1);
452 if (ret != 0)
453 goto err_power;
454
399 455
400 /* Read version */ 456 /* Read version */
401 ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & 457 ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) &
@@ -404,10 +460,18 @@ static int tpa6130a2_probe(struct i2c_client *client,
404 dev_warn(dev, "UNTESTED version detected (%d)\n", ret); 460 dev_warn(dev, "UNTESTED version detected (%d)\n", ret);
405 461
406 /* Disable the chip */ 462 /* Disable the chip */
407 tpa6130a2_power(0); 463 ret = tpa6130a2_power(0);
464 if (ret != 0)
465 goto err_power;
408 466
409 return 0; 467 return 0;
410fail: 468
469err_power:
470 regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies);
471err_regulator:
472 if (data->power_gpio >= 0)
473 gpio_free(data->power_gpio);
474err_gpio:
411 kfree(data); 475 kfree(data);
412 i2c_set_clientdata(tpa6130a2_client, NULL); 476 i2c_set_clientdata(tpa6130a2_client, NULL);
413 tpa6130a2_client = NULL; 477 tpa6130a2_client = NULL;
@@ -415,7 +479,7 @@ fail:
415 return ret; 479 return ret;
416} 480}
417 481
418static int tpa6130a2_remove(struct i2c_client *client) 482static int __devexit tpa6130a2_remove(struct i2c_client *client)
419{ 483{
420 struct tpa6130a2_data *data = i2c_get_clientdata(client); 484 struct tpa6130a2_data *data = i2c_get_clientdata(client);
421 485
@@ -423,6 +487,9 @@ static int tpa6130a2_remove(struct i2c_client *client)
423 487
424 if (data->power_gpio >= 0) 488 if (data->power_gpio >= 0)
425 gpio_free(data->power_gpio); 489 gpio_free(data->power_gpio);
490
491 regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies);
492
426 kfree(data); 493 kfree(data);
427 tpa6130a2_client = NULL; 494 tpa6130a2_client = NULL;
428 495
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 2a27f7b5672..74f0d65f078 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -2192,7 +2192,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2192 codec->write = twl4030_write; 2192 codec->write = twl4030_write;
2193 codec->set_bias_level = twl4030_set_bias_level; 2193 codec->set_bias_level = twl4030_set_bias_level;
2194 codec->dai = twl4030_dai; 2194 codec->dai = twl4030_dai;
2195 codec->num_dai = ARRAY_SIZE(twl4030_dai), 2195 codec->num_dai = ARRAY_SIZE(twl4030_dai);
2196 codec->reg_cache_size = sizeof(twl4030_reg); 2196 codec->reg_cache_size = sizeof(twl4030_reg);
2197 codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), 2197 codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
2198 GFP_KERNEL); 2198 GFP_KERNEL);
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index dd6396ec9c7..f206d242ca3 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -25,7 +25,7 @@
25/* Register descriptions are here */ 25/* Register descriptions are here */
26#include <linux/mfd/twl4030-codec.h> 26#include <linux/mfd/twl4030-codec.h>
27 27
28/* Sgadow register used by the audio driver */ 28/* Shadow register used by the audio driver */
29#define TWL4030_REG_SW_SHADOW 0x4A 29#define TWL4030_REG_SW_SHADOW 0x4A
30#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) 30#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
31 31
diff --git a/sound/soc/codecs/wm8727.c b/sound/soc/codecs/wm8727.c
index d8ffbd641d7..63a254e293c 100644
--- a/sound/soc/codecs/wm8727.c
+++ b/sound/soc/codecs/wm8727.c
@@ -44,23 +44,16 @@ struct snd_soc_dai wm8727_dai = {
44}; 44};
45EXPORT_SYMBOL_GPL(wm8727_dai); 45EXPORT_SYMBOL_GPL(wm8727_dai);
46 46
47static struct snd_soc_codec *wm8727_codec;
48
47static int wm8727_soc_probe(struct platform_device *pdev) 49static int wm8727_soc_probe(struct platform_device *pdev)
48{ 50{
49 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 51 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
50 struct snd_soc_codec *codec;
51 int ret = 0; 52 int ret = 0;
52 53
53 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 54 BUG_ON(!wm8727_codec);
54 if (codec == NULL) 55
55 return -ENOMEM; 56 socdev->card->codec = wm8727_codec;
56 mutex_init(&codec->mutex);
57 codec->name = "WM8727";
58 codec->owner = THIS_MODULE;
59 codec->dai = &wm8727_dai;
60 codec->num_dai = 1;
61 socdev->card->codec = codec;
62 INIT_LIST_HEAD(&codec->dapm_widgets);
63 INIT_LIST_HEAD(&codec->dapm_paths);
64 57
65 /* register pcms */ 58 /* register pcms */
66 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 59 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -80,12 +73,9 @@ pcm_err:
80static int wm8727_soc_remove(struct platform_device *pdev) 73static int wm8727_soc_remove(struct platform_device *pdev)
81{ 74{
82 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 75 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
83 struct snd_soc_codec *codec = socdev->card->codec;
84 76
85 if (codec == NULL)
86 return 0;
87 snd_soc_free_pcms(socdev); 77 snd_soc_free_pcms(socdev);
88 kfree(codec); 78
89 return 0; 79 return 0;
90} 80}
91 81
@@ -98,13 +88,55 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8727);
98 88
99static __devinit int wm8727_platform_probe(struct platform_device *pdev) 89static __devinit int wm8727_platform_probe(struct platform_device *pdev)
100{ 90{
91 struct snd_soc_codec *codec;
92 int ret;
93
94 if (wm8727_codec) {
95 dev_err(&pdev->dev, "Another WM8727 is registered\n");
96 return -EBUSY;
97 }
98
99 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
100 if (codec == NULL)
101 return -ENOMEM;
102 wm8727_codec = codec;
103
104 platform_set_drvdata(pdev, codec);
105
106 mutex_init(&codec->mutex);
107 codec->dev = &pdev->dev;
108 codec->name = "WM8727";
109 codec->owner = THIS_MODULE;
110 codec->dai = &wm8727_dai;
111 codec->num_dai = 1;
112 INIT_LIST_HEAD(&codec->dapm_widgets);
113 INIT_LIST_HEAD(&codec->dapm_paths);
114
101 wm8727_dai.dev = &pdev->dev; 115 wm8727_dai.dev = &pdev->dev;
102 return snd_soc_register_dai(&wm8727_dai); 116
117 ret = snd_soc_register_codec(codec);
118 if (ret != 0) {
119 dev_err(&pdev->dev, "Failed to register CODEC: %d\n", ret);
120 goto err;
121 }
122
123 ret = snd_soc_register_dai(&wm8727_dai);
124 if (ret != 0) {
125 dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
126 goto err_codec;
127 }
128
129err_codec:
130 snd_soc_unregister_codec(codec);
131err:
132 kfree(codec);
133 return ret;
103} 134}
104 135
105static int __devexit wm8727_platform_remove(struct platform_device *pdev) 136static int __devexit wm8727_platform_remove(struct platform_device *pdev)
106{ 137{
107 snd_soc_unregister_dai(&wm8727_dai); 138 snd_soc_unregister_dai(&wm8727_dai);
139 snd_soc_unregister_codec(platform_get_drvdata(pdev));
108 return 0; 140 return 0;
109} 141}
110 142
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 3a497810f93..5a2619dbf28 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -456,6 +456,9 @@ static int wm8731_resume(struct platform_device *pdev)
456 456
457 /* Sync reg_cache with the hardware */ 457 /* Sync reg_cache with the hardware */
458 for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { 458 for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
459 if (cache[i] == wm8731_reg[i])
460 continue;
461
459 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); 462 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
460 data[1] = cache[i] & 0x00ff; 463 data[1] = cache[i] & 0x00ff;
461 codec->hw_write(codec->control_data, data, 2); 464 codec->hw_write(codec->control_data, data, 2);
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index d6850dacda2..c2444e7c848 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1507,10 +1507,6 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
1507 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1507 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1508 struct snd_soc_codec *codec = socdev->card->codec; 1508 struct snd_soc_codec *codec = socdev->card->codec;
1509 1509
1510 /* we only need to suspend if we are a valid card */
1511 if (!codec->card)
1512 return 0;
1513
1514 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); 1510 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
1515 return 0; 1511 return 0;
1516} 1512}
@@ -1523,10 +1519,6 @@ static int wm8753_resume(struct platform_device *pdev)
1523 u8 data[2]; 1519 u8 data[2];
1524 u16 *cache = codec->reg_cache; 1520 u16 *cache = codec->reg_cache;
1525 1521
1526 /* we only need to resume if we are a valid card */
1527 if (!codec->card)
1528 return 0;
1529
1530 /* Sync reg_cache with the hardware */ 1522 /* Sync reg_cache with the hardware */
1531 for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { 1523 for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) {
1532 if (i + 1 == WM8753_RESET) 1524 if (i + 1 == WM8753_RESET)
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index ab2c0da1809..44e7d9d82f8 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -406,6 +406,8 @@ static int wm8776_resume(struct platform_device *pdev)
406 406
407 /* Sync reg_cache with the hardware */ 407 /* Sync reg_cache with the hardware */
408 for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) { 408 for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) {
409 if (cache[i] == wm8776_reg[i])
410 continue;
409 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); 411 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
410 data[1] = cache[i] & 0x00ff; 412 data[1] = cache[i] & 0x00ff;
411 codec->hw_write(codec->control_data, data, 2); 413 codec->hw_write(codec->control_data, data, 2);
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
new file mode 100644
index 00000000000..992a7f23df5
--- /dev/null
+++ b/sound/soc/codecs/wm8904.c
@@ -0,0 +1,2556 @@
1/*
2 * wm8904.c -- WM8904 ALSA SoC Audio driver
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/init.h>
17#include <linux/delay.h>
18#include <linux/pm.h>
19#include <linux/i2c.h>
20#include <linux/platform_device.h>
21#include <linux/regulator/consumer.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <sound/soc-dapm.h>
27#include <sound/initval.h>
28#include <sound/tlv.h>
29#include <sound/wm8904.h>
30
31#include "wm8904.h"
32
33static struct snd_soc_codec *wm8904_codec;
34struct snd_soc_codec_device soc_codec_dev_wm8904;
35
36#define WM8904_NUM_DCS_CHANNELS 4
37
38#define WM8904_NUM_SUPPLIES 5
39static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
40 "DCVDD",
41 "DBVDD",
42 "AVDD",
43 "CPVDD",
44 "MICVDD",
45};
46
47/* codec private data */
48struct wm8904_priv {
49 struct snd_soc_codec codec;
50 u16 reg_cache[WM8904_MAX_REGISTER + 1];
51
52 struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
53
54 struct wm8904_pdata *pdata;
55
56 int deemph;
57
58 /* Platform provided DRC configuration */
59 const char **drc_texts;
60 int drc_cfg;
61 struct soc_enum drc_enum;
62
63 /* Platform provided ReTune mobile configuration */
64 int num_retune_mobile_texts;
65 const char **retune_mobile_texts;
66 int retune_mobile_cfg;
67 struct soc_enum retune_mobile_enum;
68
69 /* FLL setup */
70 int fll_src;
71 int fll_fref;
72 int fll_fout;
73
74 /* Clocking configuration */
75 unsigned int mclk_rate;
76 int sysclk_src;
77 unsigned int sysclk_rate;
78
79 int tdm_width;
80 int tdm_slots;
81 int bclk;
82 int fs;
83
84 /* DC servo configuration - cached offset values */
85 int dcs_state[WM8904_NUM_DCS_CHANNELS];
86};
87
88static const u16 wm8904_reg[WM8904_MAX_REGISTER + 1] = {
89 0x8904, /* R0 - SW Reset and ID */
90 0x0000, /* R1 - Revision */
91 0x0000, /* R2 */
92 0x0000, /* R3 */
93 0x0018, /* R4 - Bias Control 0 */
94 0x0000, /* R5 - VMID Control 0 */
95 0x0000, /* R6 - Mic Bias Control 0 */
96 0x0000, /* R7 - Mic Bias Control 1 */
97 0x0001, /* R8 - Analogue DAC 0 */
98 0x9696, /* R9 - mic Filter Control */
99 0x0001, /* R10 - Analogue ADC 0 */
100 0x0000, /* R11 */
101 0x0000, /* R12 - Power Management 0 */
102 0x0000, /* R13 */
103 0x0000, /* R14 - Power Management 2 */
104 0x0000, /* R15 - Power Management 3 */
105 0x0000, /* R16 */
106 0x0000, /* R17 */
107 0x0000, /* R18 - Power Management 6 */
108 0x0000, /* R19 */
109 0x945E, /* R20 - Clock Rates 0 */
110 0x0C05, /* R21 - Clock Rates 1 */
111 0x0006, /* R22 - Clock Rates 2 */
112 0x0000, /* R23 */
113 0x0050, /* R24 - Audio Interface 0 */
114 0x000A, /* R25 - Audio Interface 1 */
115 0x00E4, /* R26 - Audio Interface 2 */
116 0x0040, /* R27 - Audio Interface 3 */
117 0x0000, /* R28 */
118 0x0000, /* R29 */
119 0x00C0, /* R30 - DAC Digital Volume Left */
120 0x00C0, /* R31 - DAC Digital Volume Right */
121 0x0000, /* R32 - DAC Digital 0 */
122 0x0008, /* R33 - DAC Digital 1 */
123 0x0000, /* R34 */
124 0x0000, /* R35 */
125 0x00C0, /* R36 - ADC Digital Volume Left */
126 0x00C0, /* R37 - ADC Digital Volume Right */
127 0x0010, /* R38 - ADC Digital 0 */
128 0x0000, /* R39 - Digital Microphone 0 */
129 0x01AF, /* R40 - DRC 0 */
130 0x3248, /* R41 - DRC 1 */
131 0x0000, /* R42 - DRC 2 */
132 0x0000, /* R43 - DRC 3 */
133 0x0085, /* R44 - Analogue Left Input 0 */
134 0x0085, /* R45 - Analogue Right Input 0 */
135 0x0044, /* R46 - Analogue Left Input 1 */
136 0x0044, /* R47 - Analogue Right Input 1 */
137 0x0000, /* R48 */
138 0x0000, /* R49 */
139 0x0000, /* R50 */
140 0x0000, /* R51 */
141 0x0000, /* R52 */
142 0x0000, /* R53 */
143 0x0000, /* R54 */
144 0x0000, /* R55 */
145 0x0000, /* R56 */
146 0x002D, /* R57 - Analogue OUT1 Left */
147 0x002D, /* R58 - Analogue OUT1 Right */
148 0x0039, /* R59 - Analogue OUT2 Left */
149 0x0039, /* R60 - Analogue OUT2 Right */
150 0x0000, /* R61 - Analogue OUT12 ZC */
151 0x0000, /* R62 */
152 0x0000, /* R63 */
153 0x0000, /* R64 */
154 0x0000, /* R65 */
155 0x0000, /* R66 */
156 0x0000, /* R67 - DC Servo 0 */
157 0x0000, /* R68 - DC Servo 1 */
158 0xAAAA, /* R69 - DC Servo 2 */
159 0x0000, /* R70 */
160 0xAAAA, /* R71 - DC Servo 4 */
161 0xAAAA, /* R72 - DC Servo 5 */
162 0x0000, /* R73 - DC Servo 6 */
163 0x0000, /* R74 - DC Servo 7 */
164 0x0000, /* R75 - DC Servo 8 */
165 0x0000, /* R76 - DC Servo 9 */
166 0x0000, /* R77 - DC Servo Readback 0 */
167 0x0000, /* R78 */
168 0x0000, /* R79 */
169 0x0000, /* R80 */
170 0x0000, /* R81 */
171 0x0000, /* R82 */
172 0x0000, /* R83 */
173 0x0000, /* R84 */
174 0x0000, /* R85 */
175 0x0000, /* R86 */
176 0x0000, /* R87 */
177 0x0000, /* R88 */
178 0x0000, /* R89 */
179 0x0000, /* R90 - Analogue HP 0 */
180 0x0000, /* R91 */
181 0x0000, /* R92 */
182 0x0000, /* R93 */
183 0x0000, /* R94 - Analogue Lineout 0 */
184 0x0000, /* R95 */
185 0x0000, /* R96 */
186 0x0000, /* R97 */
187 0x0000, /* R98 - Charge Pump 0 */
188 0x0000, /* R99 */
189 0x0000, /* R100 */
190 0x0000, /* R101 */
191 0x0000, /* R102 */
192 0x0000, /* R103 */
193 0x0004, /* R104 - Class W 0 */
194 0x0000, /* R105 */
195 0x0000, /* R106 */
196 0x0000, /* R107 */
197 0x0000, /* R108 - Write Sequencer 0 */
198 0x0000, /* R109 - Write Sequencer 1 */
199 0x0000, /* R110 - Write Sequencer 2 */
200 0x0000, /* R111 - Write Sequencer 3 */
201 0x0000, /* R112 - Write Sequencer 4 */
202 0x0000, /* R113 */
203 0x0000, /* R114 */
204 0x0000, /* R115 */
205 0x0000, /* R116 - FLL Control 1 */
206 0x0007, /* R117 - FLL Control 2 */
207 0x0000, /* R118 - FLL Control 3 */
208 0x2EE0, /* R119 - FLL Control 4 */
209 0x0004, /* R120 - FLL Control 5 */
210 0x0014, /* R121 - GPIO Control 1 */
211 0x0010, /* R122 - GPIO Control 2 */
212 0x0010, /* R123 - GPIO Control 3 */
213 0x0000, /* R124 - GPIO Control 4 */
214 0x0000, /* R125 */
215 0x0000, /* R126 - Digital Pulls */
216 0x0000, /* R127 - Interrupt Status */
217 0xFFFF, /* R128 - Interrupt Status Mask */
218 0x0000, /* R129 - Interrupt Polarity */
219 0x0000, /* R130 - Interrupt Debounce */
220 0x0000, /* R131 */
221 0x0000, /* R132 */
222 0x0000, /* R133 */
223 0x0000, /* R134 - EQ1 */
224 0x000C, /* R135 - EQ2 */
225 0x000C, /* R136 - EQ3 */
226 0x000C, /* R137 - EQ4 */
227 0x000C, /* R138 - EQ5 */
228 0x000C, /* R139 - EQ6 */
229 0x0FCA, /* R140 - EQ7 */
230 0x0400, /* R141 - EQ8 */
231 0x00D8, /* R142 - EQ9 */
232 0x1EB5, /* R143 - EQ10 */
233 0xF145, /* R144 - EQ11 */
234 0x0B75, /* R145 - EQ12 */
235 0x01C5, /* R146 - EQ13 */
236 0x1C58, /* R147 - EQ14 */
237 0xF373, /* R148 - EQ15 */
238 0x0A54, /* R149 - EQ16 */
239 0x0558, /* R150 - EQ17 */
240 0x168E, /* R151 - EQ18 */
241 0xF829, /* R152 - EQ19 */
242 0x07AD, /* R153 - EQ20 */
243 0x1103, /* R154 - EQ21 */
244 0x0564, /* R155 - EQ22 */
245 0x0559, /* R156 - EQ23 */
246 0x4000, /* R157 - EQ24 */
247 0x0000, /* R158 */
248 0x0000, /* R159 */
249 0x0000, /* R160 */
250 0x0000, /* R161 - Control Interface Test 1 */
251 0x0000, /* R162 */
252 0x0000, /* R163 */
253 0x0000, /* R164 */
254 0x0000, /* R165 */
255 0x0000, /* R166 */
256 0x0000, /* R167 */
257 0x0000, /* R168 */
258 0x0000, /* R169 */
259 0x0000, /* R170 */
260 0x0000, /* R171 */
261 0x0000, /* R172 */
262 0x0000, /* R173 */
263 0x0000, /* R174 */
264 0x0000, /* R175 */
265 0x0000, /* R176 */
266 0x0000, /* R177 */
267 0x0000, /* R178 */
268 0x0000, /* R179 */
269 0x0000, /* R180 */
270 0x0000, /* R181 */
271 0x0000, /* R182 */
272 0x0000, /* R183 */
273 0x0000, /* R184 */
274 0x0000, /* R185 */
275 0x0000, /* R186 */
276 0x0000, /* R187 */
277 0x0000, /* R188 */
278 0x0000, /* R189 */
279 0x0000, /* R190 */
280 0x0000, /* R191 */
281 0x0000, /* R192 */
282 0x0000, /* R193 */
283 0x0000, /* R194 */
284 0x0000, /* R195 */
285 0x0000, /* R196 */
286 0x0000, /* R197 */
287 0x0000, /* R198 */
288 0x0000, /* R199 */
289 0x0000, /* R200 */
290 0x0000, /* R201 */
291 0x0000, /* R202 */
292 0x0000, /* R203 */
293 0x0000, /* R204 - Analogue Output Bias 0 */
294 0x0000, /* R205 */
295 0x0000, /* R206 */
296 0x0000, /* R207 */
297 0x0000, /* R208 */
298 0x0000, /* R209 */
299 0x0000, /* R210 */
300 0x0000, /* R211 */
301 0x0000, /* R212 */
302 0x0000, /* R213 */
303 0x0000, /* R214 */
304 0x0000, /* R215 */
305 0x0000, /* R216 */
306 0x0000, /* R217 */
307 0x0000, /* R218 */
308 0x0000, /* R219 */
309 0x0000, /* R220 */
310 0x0000, /* R221 */
311 0x0000, /* R222 */
312 0x0000, /* R223 */
313 0x0000, /* R224 */
314 0x0000, /* R225 */
315 0x0000, /* R226 */
316 0x0000, /* R227 */
317 0x0000, /* R228 */
318 0x0000, /* R229 */
319 0x0000, /* R230 */
320 0x0000, /* R231 */
321 0x0000, /* R232 */
322 0x0000, /* R233 */
323 0x0000, /* R234 */
324 0x0000, /* R235 */
325 0x0000, /* R236 */
326 0x0000, /* R237 */
327 0x0000, /* R238 */
328 0x0000, /* R239 */
329 0x0000, /* R240 */
330 0x0000, /* R241 */
331 0x0000, /* R242 */
332 0x0000, /* R243 */
333 0x0000, /* R244 */
334 0x0000, /* R245 */
335 0x0000, /* R246 */
336 0x0000, /* R247 - FLL NCO Test 0 */
337 0x0019, /* R248 - FLL NCO Test 1 */
338};
339
340static struct {
341 int readable;
342 int writable;
343 int vol;
344} wm8904_access[] = {
345 { 0xFFFF, 0xFFFF, 1 }, /* R0 - SW Reset and ID */
346 { 0x0000, 0x0000, 0 }, /* R1 - Revision */
347 { 0x0000, 0x0000, 0 }, /* R2 */
348 { 0x0000, 0x0000, 0 }, /* R3 */
349 { 0x001F, 0x001F, 0 }, /* R4 - Bias Control 0 */
350 { 0x0047, 0x0047, 0 }, /* R5 - VMID Control 0 */
351 { 0x007F, 0x007F, 0 }, /* R6 - Mic Bias Control 0 */
352 { 0xC007, 0xC007, 0 }, /* R7 - Mic Bias Control 1 */
353 { 0x001E, 0x001E, 0 }, /* R8 - Analogue DAC 0 */
354 { 0xFFFF, 0xFFFF, 0 }, /* R9 - mic Filter Control */
355 { 0x0001, 0x0001, 0 }, /* R10 - Analogue ADC 0 */
356 { 0x0000, 0x0000, 0 }, /* R11 */
357 { 0x0003, 0x0003, 0 }, /* R12 - Power Management 0 */
358 { 0x0000, 0x0000, 0 }, /* R13 */
359 { 0x0003, 0x0003, 0 }, /* R14 - Power Management 2 */
360 { 0x0003, 0x0003, 0 }, /* R15 - Power Management 3 */
361 { 0x0000, 0x0000, 0 }, /* R16 */
362 { 0x0000, 0x0000, 0 }, /* R17 */
363 { 0x000F, 0x000F, 0 }, /* R18 - Power Management 6 */
364 { 0x0000, 0x0000, 0 }, /* R19 */
365 { 0x7001, 0x7001, 0 }, /* R20 - Clock Rates 0 */
366 { 0x3C07, 0x3C07, 0 }, /* R21 - Clock Rates 1 */
367 { 0xD00F, 0xD00F, 0 }, /* R22 - Clock Rates 2 */
368 { 0x0000, 0x0000, 0 }, /* R23 */
369 { 0x1FFF, 0x1FFF, 0 }, /* R24 - Audio Interface 0 */
370 { 0x3DDF, 0x3DDF, 0 }, /* R25 - Audio Interface 1 */
371 { 0x0F1F, 0x0F1F, 0 }, /* R26 - Audio Interface 2 */
372 { 0x0FFF, 0x0FFF, 0 }, /* R27 - Audio Interface 3 */
373 { 0x0000, 0x0000, 0 }, /* R28 */
374 { 0x0000, 0x0000, 0 }, /* R29 */
375 { 0x00FF, 0x01FF, 0 }, /* R30 - DAC Digital Volume Left */
376 { 0x00FF, 0x01FF, 0 }, /* R31 - DAC Digital Volume Right */
377 { 0x0FFF, 0x0FFF, 0 }, /* R32 - DAC Digital 0 */
378 { 0x1E4E, 0x1E4E, 0 }, /* R33 - DAC Digital 1 */
379 { 0x0000, 0x0000, 0 }, /* R34 */
380 { 0x0000, 0x0000, 0 }, /* R35 */
381 { 0x00FF, 0x01FF, 0 }, /* R36 - ADC Digital Volume Left */
382 { 0x00FF, 0x01FF, 0 }, /* R37 - ADC Digital Volume Right */
383 { 0x0073, 0x0073, 0 }, /* R38 - ADC Digital 0 */
384 { 0x1800, 0x1800, 0 }, /* R39 - Digital Microphone 0 */
385 { 0xDFEF, 0xDFEF, 0 }, /* R40 - DRC 0 */
386 { 0xFFFF, 0xFFFF, 0 }, /* R41 - DRC 1 */
387 { 0x003F, 0x003F, 0 }, /* R42 - DRC 2 */
388 { 0x07FF, 0x07FF, 0 }, /* R43 - DRC 3 */
389 { 0x009F, 0x009F, 0 }, /* R44 - Analogue Left Input 0 */
390 { 0x009F, 0x009F, 0 }, /* R45 - Analogue Right Input 0 */
391 { 0x007F, 0x007F, 0 }, /* R46 - Analogue Left Input 1 */
392 { 0x007F, 0x007F, 0 }, /* R47 - Analogue Right Input 1 */
393 { 0x0000, 0x0000, 0 }, /* R48 */
394 { 0x0000, 0x0000, 0 }, /* R49 */
395 { 0x0000, 0x0000, 0 }, /* R50 */
396 { 0x0000, 0x0000, 0 }, /* R51 */
397 { 0x0000, 0x0000, 0 }, /* R52 */
398 { 0x0000, 0x0000, 0 }, /* R53 */
399 { 0x0000, 0x0000, 0 }, /* R54 */
400 { 0x0000, 0x0000, 0 }, /* R55 */
401 { 0x0000, 0x0000, 0 }, /* R56 */
402 { 0x017F, 0x01FF, 0 }, /* R57 - Analogue OUT1 Left */
403 { 0x017F, 0x01FF, 0 }, /* R58 - Analogue OUT1 Right */
404 { 0x017F, 0x01FF, 0 }, /* R59 - Analogue OUT2 Left */
405 { 0x017F, 0x01FF, 0 }, /* R60 - Analogue OUT2 Right */
406 { 0x000F, 0x000F, 0 }, /* R61 - Analogue OUT12 ZC */
407 { 0x0000, 0x0000, 0 }, /* R62 */
408 { 0x0000, 0x0000, 0 }, /* R63 */
409 { 0x0000, 0x0000, 0 }, /* R64 */
410 { 0x0000, 0x0000, 0 }, /* R65 */
411 { 0x0000, 0x0000, 0 }, /* R66 */
412 { 0x000F, 0x000F, 0 }, /* R67 - DC Servo 0 */
413 { 0xFFFF, 0xFFFF, 1 }, /* R68 - DC Servo 1 */
414 { 0x0F0F, 0x0F0F, 0 }, /* R69 - DC Servo 2 */
415 { 0x0000, 0x0000, 0 }, /* R70 */
416 { 0x007F, 0x007F, 0 }, /* R71 - DC Servo 4 */
417 { 0x007F, 0x007F, 0 }, /* R72 - DC Servo 5 */
418 { 0x00FF, 0x00FF, 1 }, /* R73 - DC Servo 6 */
419 { 0x00FF, 0x00FF, 1 }, /* R74 - DC Servo 7 */
420 { 0x00FF, 0x00FF, 1 }, /* R75 - DC Servo 8 */
421 { 0x00FF, 0x00FF, 1 }, /* R76 - DC Servo 9 */
422 { 0x0FFF, 0x0000, 1 }, /* R77 - DC Servo Readback 0 */
423 { 0x0000, 0x0000, 0 }, /* R78 */
424 { 0x0000, 0x0000, 0 }, /* R79 */
425 { 0x0000, 0x0000, 0 }, /* R80 */
426 { 0x0000, 0x0000, 0 }, /* R81 */
427 { 0x0000, 0x0000, 0 }, /* R82 */
428 { 0x0000, 0x0000, 0 }, /* R83 */
429 { 0x0000, 0x0000, 0 }, /* R84 */
430 { 0x0000, 0x0000, 0 }, /* R85 */
431 { 0x0000, 0x0000, 0 }, /* R86 */
432 { 0x0000, 0x0000, 0 }, /* R87 */
433 { 0x0000, 0x0000, 0 }, /* R88 */
434 { 0x0000, 0x0000, 0 }, /* R89 */
435 { 0x00FF, 0x00FF, 0 }, /* R90 - Analogue HP 0 */
436 { 0x0000, 0x0000, 0 }, /* R91 */
437 { 0x0000, 0x0000, 0 }, /* R92 */
438 { 0x0000, 0x0000, 0 }, /* R93 */
439 { 0x00FF, 0x00FF, 0 }, /* R94 - Analogue Lineout 0 */
440 { 0x0000, 0x0000, 0 }, /* R95 */
441 { 0x0000, 0x0000, 0 }, /* R96 */
442 { 0x0000, 0x0000, 0 }, /* R97 */
443 { 0x0001, 0x0001, 0 }, /* R98 - Charge Pump 0 */
444 { 0x0000, 0x0000, 0 }, /* R99 */
445 { 0x0000, 0x0000, 0 }, /* R100 */
446 { 0x0000, 0x0000, 0 }, /* R101 */
447 { 0x0000, 0x0000, 0 }, /* R102 */
448 { 0x0000, 0x0000, 0 }, /* R103 */
449 { 0x0001, 0x0001, 0 }, /* R104 - Class W 0 */
450 { 0x0000, 0x0000, 0 }, /* R105 */
451 { 0x0000, 0x0000, 0 }, /* R106 */
452 { 0x0000, 0x0000, 0 }, /* R107 */
453 { 0x011F, 0x011F, 0 }, /* R108 - Write Sequencer 0 */
454 { 0x7FFF, 0x7FFF, 0 }, /* R109 - Write Sequencer 1 */
455 { 0x4FFF, 0x4FFF, 0 }, /* R110 - Write Sequencer 2 */
456 { 0x003F, 0x033F, 0 }, /* R111 - Write Sequencer 3 */
457 { 0x03F1, 0x0000, 0 }, /* R112 - Write Sequencer 4 */
458 { 0x0000, 0x0000, 0 }, /* R113 */
459 { 0x0000, 0x0000, 0 }, /* R114 */
460 { 0x0000, 0x0000, 0 }, /* R115 */
461 { 0x0007, 0x0007, 0 }, /* R116 - FLL Control 1 */
462 { 0x3F77, 0x3F77, 0 }, /* R117 - FLL Control 2 */
463 { 0xFFFF, 0xFFFF, 0 }, /* R118 - FLL Control 3 */
464 { 0x7FEF, 0x7FEF, 0 }, /* R119 - FLL Control 4 */
465 { 0x001B, 0x001B, 0 }, /* R120 - FLL Control 5 */
466 { 0x003F, 0x003F, 0 }, /* R121 - GPIO Control 1 */
467 { 0x003F, 0x003F, 0 }, /* R122 - GPIO Control 2 */
468 { 0x003F, 0x003F, 0 }, /* R123 - GPIO Control 3 */
469 { 0x038F, 0x038F, 0 }, /* R124 - GPIO Control 4 */
470 { 0x0000, 0x0000, 0 }, /* R125 */
471 { 0x00FF, 0x00FF, 0 }, /* R126 - Digital Pulls */
472 { 0x07FF, 0x03FF, 1 }, /* R127 - Interrupt Status */
473 { 0x03FF, 0x03FF, 0 }, /* R128 - Interrupt Status Mask */
474 { 0x03FF, 0x03FF, 0 }, /* R129 - Interrupt Polarity */
475 { 0x03FF, 0x03FF, 0 }, /* R130 - Interrupt Debounce */
476 { 0x0000, 0x0000, 0 }, /* R131 */
477 { 0x0000, 0x0000, 0 }, /* R132 */
478 { 0x0000, 0x0000, 0 }, /* R133 */
479 { 0x0001, 0x0001, 0 }, /* R134 - EQ1 */
480 { 0x001F, 0x001F, 0 }, /* R135 - EQ2 */
481 { 0x001F, 0x001F, 0 }, /* R136 - EQ3 */
482 { 0x001F, 0x001F, 0 }, /* R137 - EQ4 */
483 { 0x001F, 0x001F, 0 }, /* R138 - EQ5 */
484 { 0x001F, 0x001F, 0 }, /* R139 - EQ6 */
485 { 0xFFFF, 0xFFFF, 0 }, /* R140 - EQ7 */
486 { 0xFFFF, 0xFFFF, 0 }, /* R141 - EQ8 */
487 { 0xFFFF, 0xFFFF, 0 }, /* R142 - EQ9 */
488 { 0xFFFF, 0xFFFF, 0 }, /* R143 - EQ10 */
489 { 0xFFFF, 0xFFFF, 0 }, /* R144 - EQ11 */
490 { 0xFFFF, 0xFFFF, 0 }, /* R145 - EQ12 */
491 { 0xFFFF, 0xFFFF, 0 }, /* R146 - EQ13 */
492 { 0xFFFF, 0xFFFF, 0 }, /* R147 - EQ14 */
493 { 0xFFFF, 0xFFFF, 0 }, /* R148 - EQ15 */
494 { 0xFFFF, 0xFFFF, 0 }, /* R149 - EQ16 */
495 { 0xFFFF, 0xFFFF, 0 }, /* R150 - EQ17 */
496 { 0xFFFF, 0xFFFF, 0 }, /* R151wm8523_dai - EQ18 */
497 { 0xFFFF, 0xFFFF, 0 }, /* R152 - EQ19 */
498 { 0xFFFF, 0xFFFF, 0 }, /* R153 - EQ20 */
499 { 0xFFFF, 0xFFFF, 0 }, /* R154 - EQ21 */
500 { 0xFFFF, 0xFFFF, 0 }, /* R155 - EQ22 */
501 { 0xFFFF, 0xFFFF, 0 }, /* R156 - EQ23 */
502 { 0xFFFF, 0xFFFF, 0 }, /* R157 - EQ24 */
503 { 0x0000, 0x0000, 0 }, /* R158 */
504 { 0x0000, 0x0000, 0 }, /* R159 */
505 { 0x0000, 0x0000, 0 }, /* R160 */
506 { 0x0002, 0x0002, 0 }, /* R161 - Control Interface Test 1 */
507 { 0x0000, 0x0000, 0 }, /* R162 */
508 { 0x0000, 0x0000, 0 }, /* R163 */
509 { 0x0000, 0x0000, 0 }, /* R164 */
510 { 0x0000, 0x0000, 0 }, /* R165 */
511 { 0x0000, 0x0000, 0 }, /* R166 */
512 { 0x0000, 0x0000, 0 }, /* R167 */
513 { 0x0000, 0x0000, 0 }, /* R168 */
514 { 0x0000, 0x0000, 0 }, /* R169 */
515 { 0x0000, 0x0000, 0 }, /* R170 */
516 { 0x0000, 0x0000, 0 }, /* R171 */
517 { 0x0000, 0x0000, 0 }, /* R172 */
518 { 0x0000, 0x0000, 0 }, /* R173 */
519 { 0x0000, 0x0000, 0 }, /* R174 */
520 { 0x0000, 0x0000, 0 }, /* R175 */
521 { 0x0000, 0x0000, 0 }, /* R176 */
522 { 0x0000, 0x0000, 0 }, /* R177 */
523 { 0x0000, 0x0000, 0 }, /* R178 */
524 { 0x0000, 0x0000, 0 }, /* R179 */
525 { 0x0000, 0x0000, 0 }, /* R180 */
526 { 0x0000, 0x0000, 0 }, /* R181 */
527 { 0x0000, 0x0000, 0 }, /* R182 */
528 { 0x0000, 0x0000, 0 }, /* R183 */
529 { 0x0000, 0x0000, 0 }, /* R184 */
530 { 0x0000, 0x0000, 0 }, /* R185 */
531 { 0x0000, 0x0000, 0 }, /* R186 */
532 { 0x0000, 0x0000, 0 }, /* R187 */
533 { 0x0000, 0x0000, 0 }, /* R188 */
534 { 0x0000, 0x0000, 0 }, /* R189 */
535 { 0x0000, 0x0000, 0 }, /* R190 */
536 { 0x0000, 0x0000, 0 }, /* R191 */
537 { 0x0000, 0x0000, 0 }, /* R192 */
538 { 0x0000, 0x0000, 0 }, /* R193 */
539 { 0x0000, 0x0000, 0 }, /* R194 */
540 { 0x0000, 0x0000, 0 }, /* R195 */
541 { 0x0000, 0x0000, 0 }, /* R196 */
542 { 0x0000, 0x0000, 0 }, /* R197 */
543 { 0x0000, 0x0000, 0 }, /* R198 */
544 { 0x0000, 0x0000, 0 }, /* R199 */
545 { 0x0000, 0x0000, 0 }, /* R200 */
546 { 0x0000, 0x0000, 0 }, /* R201 */
547 { 0x0000, 0x0000, 0 }, /* R202 */
548 { 0x0000, 0x0000, 0 }, /* R203 */
549 { 0x0070, 0x0070, 0 }, /* R204 - Analogue Output Bias 0 */
550 { 0x0000, 0x0000, 0 }, /* R205 */
551 { 0x0000, 0x0000, 0 }, /* R206 */
552 { 0x0000, 0x0000, 0 }, /* R207 */
553 { 0x0000, 0x0000, 0 }, /* R208 */
554 { 0x0000, 0x0000, 0 }, /* R209 */
555 { 0x0000, 0x0000, 0 }, /* R210 */
556 { 0x0000, 0x0000, 0 }, /* R211 */
557 { 0x0000, 0x0000, 0 }, /* R212 */
558 { 0x0000, 0x0000, 0 }, /* R213 */
559 { 0x0000, 0x0000, 0 }, /* R214 */
560 { 0x0000, 0x0000, 0 }, /* R215 */
561 { 0x0000, 0x0000, 0 }, /* R216 */
562 { 0x0000, 0x0000, 0 }, /* R217 */
563 { 0x0000, 0x0000, 0 }, /* R218 */
564 { 0x0000, 0x0000, 0 }, /* R219 */
565 { 0x0000, 0x0000, 0 }, /* R220 */
566 { 0x0000, 0x0000, 0 }, /* R221 */
567 { 0x0000, 0x0000, 0 }, /* R222 */
568 { 0x0000, 0x0000, 0 }, /* R223 */
569 { 0x0000, 0x0000, 0 }, /* R224 */
570 { 0x0000, 0x0000, 0 }, /* R225 */
571 { 0x0000, 0x0000, 0 }, /* R226 */
572 { 0x0000, 0x0000, 0 }, /* R227 */
573 { 0x0000, 0x0000, 0 }, /* R228 */
574 { 0x0000, 0x0000, 0 }, /* R229 */
575 { 0x0000, 0x0000, 0 }, /* R230 */
576 { 0x0000, 0x0000, 0 }, /* R231 */
577 { 0x0000, 0x0000, 0 }, /* R232 */
578 { 0x0000, 0x0000, 0 }, /* R233 */
579 { 0x0000, 0x0000, 0 }, /* R234 */
580 { 0x0000, 0x0000, 0 }, /* R235 */
581 { 0x0000, 0x0000, 0 }, /* R236 */
582 { 0x0000, 0x0000, 0 }, /* R237 */
583 { 0x0000, 0x0000, 0 }, /* R238 */
584 { 0x0000, 0x0000, 0 }, /* R239 */
585 { 0x0000, 0x0000, 0 }, /* R240 */
586 { 0x0000, 0x0000, 0 }, /* R241 */
587 { 0x0000, 0x0000, 0 }, /* R242 */
588 { 0x0000, 0x0000, 0 }, /* R243 */
589 { 0x0000, 0x0000, 0 }, /* R244 */
590 { 0x0000, 0x0000, 0 }, /* R245 */
591 { 0x0000, 0x0000, 0 }, /* R246 */
592 { 0x0001, 0x0001, 0 }, /* R247 - FLL NCO Test 0 */
593 { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */
594};
595
596static int wm8904_volatile_register(unsigned int reg)
597{
598 return wm8904_access[reg].vol;
599}
600
601static int wm8904_reset(struct snd_soc_codec *codec)
602{
603 return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0);
604}
605
606static int wm8904_configure_clocking(struct snd_soc_codec *codec)
607{
608 struct wm8904_priv *wm8904 = codec->private_data;
609 unsigned int clock0, clock2, rate;
610
611 /* Gate the clock while we're updating to avoid misclocking */
612 clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
613 snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
614 WM8904_SYSCLK_SRC, 0);
615
616 /* This should be done on init() for bypass paths */
617 switch (wm8904->sysclk_src) {
618 case WM8904_CLK_MCLK:
619 dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8904->mclk_rate);
620
621 clock2 &= ~WM8904_SYSCLK_SRC;
622 rate = wm8904->mclk_rate;
623
624 /* Ensure the FLL is stopped */
625 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
626 WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
627 break;
628
629 case WM8904_CLK_FLL:
630 dev_dbg(codec->dev, "Using %dHz FLL clock\n",
631 wm8904->fll_fout);
632
633 clock2 |= WM8904_SYSCLK_SRC;
634 rate = wm8904->fll_fout;
635 break;
636
637 default:
638 dev_err(codec->dev, "System clock not configured\n");
639 return -EINVAL;
640 }
641
642 /* SYSCLK shouldn't be over 13.5MHz */
643 if (rate > 13500000) {
644 clock0 = WM8904_MCLK_DIV;
645 wm8904->sysclk_rate = rate / 2;
646 } else {
647 clock0 = 0;
648 wm8904->sysclk_rate = rate;
649 }
650
651 snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, WM8904_MCLK_DIV,
652 clock0);
653
654 snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
655 WM8904_CLK_SYS_ENA | WM8904_SYSCLK_SRC, clock2);
656
657 dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8904->sysclk_rate);
658
659 return 0;
660}
661
662static void wm8904_set_drc(struct snd_soc_codec *codec)
663{
664 struct wm8904_priv *wm8904 = codec->private_data;
665 struct wm8904_pdata *pdata = wm8904->pdata;
666 int save, i;
667
668 /* Save any enables; the configuration should clear them. */
669 save = snd_soc_read(codec, WM8904_DRC_0);
670
671 for (i = 0; i < WM8904_DRC_REGS; i++)
672 snd_soc_update_bits(codec, WM8904_DRC_0 + i, 0xffff,
673 pdata->drc_cfgs[wm8904->drc_cfg].regs[i]);
674
675 /* Reenable the DRC */
676 snd_soc_update_bits(codec, WM8904_DRC_0,
677 WM8904_DRC_ENA | WM8904_DRC_DAC_PATH, save);
678}
679
680static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
681 struct snd_ctl_elem_value *ucontrol)
682{
683 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
684 struct wm8904_priv *wm8904 = codec->private_data;
685 struct wm8904_pdata *pdata = wm8904->pdata;
686 int value = ucontrol->value.integer.value[0];
687
688 if (value >= pdata->num_drc_cfgs)
689 return -EINVAL;
690
691 wm8904->drc_cfg = value;
692
693 wm8904_set_drc(codec);
694
695 return 0;
696}
697
698static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
699 struct snd_ctl_elem_value *ucontrol)
700{
701 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
702 struct wm8904_priv *wm8904 = codec->private_data;
703
704 ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
705
706 return 0;
707}
708
709static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
710{
711 struct wm8904_priv *wm8904 = codec->private_data;
712 struct wm8904_pdata *pdata = wm8904->pdata;
713 int best, best_val, save, i, cfg;
714
715 if (!pdata || !wm8904->num_retune_mobile_texts)
716 return;
717
718 /* Find the version of the currently selected configuration
719 * with the nearest sample rate. */
720 cfg = wm8904->retune_mobile_cfg;
721 best = 0;
722 best_val = INT_MAX;
723 for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
724 if (strcmp(pdata->retune_mobile_cfgs[i].name,
725 wm8904->retune_mobile_texts[cfg]) == 0 &&
726 abs(pdata->retune_mobile_cfgs[i].rate
727 - wm8904->fs) < best_val) {
728 best = i;
729 best_val = abs(pdata->retune_mobile_cfgs[i].rate
730 - wm8904->fs);
731 }
732 }
733
734 dev_dbg(codec->dev, "ReTune Mobile %s/%dHz for %dHz sample rate\n",
735 pdata->retune_mobile_cfgs[best].name,
736 pdata->retune_mobile_cfgs[best].rate,
737 wm8904->fs);
738
739 /* The EQ will be disabled while reconfiguring it, remember the
740 * current configuration.
741 */
742 save = snd_soc_read(codec, WM8904_EQ1);
743
744 for (i = 0; i < WM8904_EQ_REGS; i++)
745 snd_soc_update_bits(codec, WM8904_EQ1 + i, 0xffff,
746 pdata->retune_mobile_cfgs[best].regs[i]);
747
748 snd_soc_update_bits(codec, WM8904_EQ1, WM8904_EQ_ENA, save);
749}
750
751static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
752 struct snd_ctl_elem_value *ucontrol)
753{
754 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
755 struct wm8904_priv *wm8904 = codec->private_data;
756 struct wm8904_pdata *pdata = wm8904->pdata;
757 int value = ucontrol->value.integer.value[0];
758
759 if (value >= pdata->num_retune_mobile_cfgs)
760 return -EINVAL;
761
762 wm8904->retune_mobile_cfg = value;
763
764 wm8904_set_retune_mobile(codec);
765
766 return 0;
767}
768
769static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
770 struct snd_ctl_elem_value *ucontrol)
771{
772 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
773 struct wm8904_priv *wm8904 = codec->private_data;
774
775 ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
776
777 return 0;
778}
779
780static int deemph_settings[] = { 0, 32000, 44100, 48000 };
781
782static int wm8904_set_deemph(struct snd_soc_codec *codec)
783{
784 struct wm8904_priv *wm8904 = codec->private_data;
785 int val, i, best;
786
787 /* If we're using deemphasis select the nearest available sample
788 * rate.
789 */
790 if (wm8904->deemph) {
791 best = 1;
792 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
793 if (abs(deemph_settings[i] - wm8904->fs) <
794 abs(deemph_settings[best] - wm8904->fs))
795 best = i;
796 }
797
798 val = best << WM8904_DEEMPH_SHIFT;
799 } else {
800 val = 0;
801 }
802
803 dev_dbg(codec->dev, "Set deemphasis %d\n", val);
804
805 return snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
806 WM8904_DEEMPH_MASK, val);
807}
808
809static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
810 struct snd_ctl_elem_value *ucontrol)
811{
812 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
813 struct wm8904_priv *wm8904 = codec->private_data;
814
815 return wm8904->deemph;
816}
817
818static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
819 struct snd_ctl_elem_value *ucontrol)
820{
821 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
822 struct wm8904_priv *wm8904 = codec->private_data;
823 int deemph = ucontrol->value.enumerated.item[0];
824
825 if (deemph > 1)
826 return -EINVAL;
827
828 wm8904->deemph = deemph;
829
830 return wm8904_set_deemph(codec);
831}
832
833static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
834static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
835static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
836static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 300, 0);
837static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
838
839static const char *input_mode_text[] = {
840 "Single-Ended", "Differential Line", "Differential Mic"
841};
842
843static const struct soc_enum lin_mode =
844 SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text);
845
846static const struct soc_enum rin_mode =
847 SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text);
848
849static const char *hpf_mode_text[] = {
850 "Hi-fi", "Voice 1", "Voice 2", "Voice 3"
851};
852
853static const struct soc_enum hpf_mode =
854 SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text);
855
856static const struct snd_kcontrol_new wm8904_adc_snd_controls[] = {
857SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8904_ADC_DIGITAL_VOLUME_LEFT,
858 WM8904_ADC_DIGITAL_VOLUME_RIGHT, 1, 119, 0, digital_tlv),
859
860SOC_ENUM("Left Caputure Mode", lin_mode),
861SOC_ENUM("Right Capture Mode", rin_mode),
862
863/* No TLV since it depends on mode */
864SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0,
865 WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0),
866SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0,
867 WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0),
868
869SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0),
870SOC_ENUM("High Pass Filter Mode", hpf_mode),
871
872SOC_SINGLE("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0),
873};
874
875static const char *drc_path_text[] = {
876 "ADC", "DAC"
877};
878
879static const struct soc_enum drc_path =
880 SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text);
881
882static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = {
883SOC_SINGLE_TLV("Digital Playback Boost Volume",
884 WM8904_AUDIO_INTERFACE_0, 9, 3, 0, dac_boost_tlv),
885SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8904_DAC_DIGITAL_VOLUME_LEFT,
886 WM8904_DAC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
887
888SOC_DOUBLE_R_TLV("Headphone Volume", WM8904_ANALOGUE_OUT1_LEFT,
889 WM8904_ANALOGUE_OUT1_RIGHT, 0, 63, 0, out_tlv),
890SOC_DOUBLE_R("Headphone Switch", WM8904_ANALOGUE_OUT1_LEFT,
891 WM8904_ANALOGUE_OUT1_RIGHT, 8, 1, 1),
892SOC_DOUBLE_R("Headphone ZC Switch", WM8904_ANALOGUE_OUT1_LEFT,
893 WM8904_ANALOGUE_OUT1_RIGHT, 6, 1, 0),
894
895SOC_DOUBLE_R_TLV("Line Output Volume", WM8904_ANALOGUE_OUT2_LEFT,
896 WM8904_ANALOGUE_OUT2_RIGHT, 0, 63, 0, out_tlv),
897SOC_DOUBLE_R("Line Output Switch", WM8904_ANALOGUE_OUT2_LEFT,
898 WM8904_ANALOGUE_OUT2_RIGHT, 8, 1, 1),
899SOC_DOUBLE_R("Line Output ZC Switch", WM8904_ANALOGUE_OUT2_LEFT,
900 WM8904_ANALOGUE_OUT2_RIGHT, 6, 1, 0),
901
902SOC_SINGLE("EQ Switch", WM8904_EQ1, 0, 1, 0),
903SOC_SINGLE("DRC Switch", WM8904_DRC_0, 15, 1, 0),
904SOC_ENUM("DRC Path", drc_path),
905SOC_SINGLE("DAC OSRx2 Switch", WM8904_DAC_DIGITAL_1, 6, 1, 0),
906SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
907 wm8904_get_deemph, wm8904_put_deemph),
908};
909
910static const struct snd_kcontrol_new wm8904_snd_controls[] = {
911SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8904_DAC_DIGITAL_0, 4, 8, 15, 0,
912 sidetone_tlv),
913};
914
915static const struct snd_kcontrol_new wm8904_eq_controls[] = {
916SOC_SINGLE_TLV("EQ1 Volume", WM8904_EQ2, 0, 24, 0, eq_tlv),
917SOC_SINGLE_TLV("EQ2 Volume", WM8904_EQ3, 0, 24, 0, eq_tlv),
918SOC_SINGLE_TLV("EQ3 Volume", WM8904_EQ4, 0, 24, 0, eq_tlv),
919SOC_SINGLE_TLV("EQ4 Volume", WM8904_EQ5, 0, 24, 0, eq_tlv),
920SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv),
921};
922
923static int cp_event(struct snd_soc_dapm_widget *w,
924 struct snd_kcontrol *kcontrol, int event)
925{
926 BUG_ON(event != SND_SOC_DAPM_POST_PMU);
927
928 /* Maximum startup time */
929 udelay(500);
930
931 return 0;
932}
933
934static int sysclk_event(struct snd_soc_dapm_widget *w,
935 struct snd_kcontrol *kcontrol, int event)
936{
937 struct snd_soc_codec *codec = w->codec;
938 struct wm8904_priv *wm8904 = codec->private_data;
939
940 switch (event) {
941 case SND_SOC_DAPM_PRE_PMU:
942 /* If we're using the FLL then we only start it when
943 * required; we assume that the configuration has been
944 * done previously and all we need to do is kick it
945 * off.
946 */
947 switch (wm8904->sysclk_src) {
948 case WM8904_CLK_FLL:
949 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
950 WM8904_FLL_OSC_ENA,
951 WM8904_FLL_OSC_ENA);
952
953 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
954 WM8904_FLL_ENA,
955 WM8904_FLL_ENA);
956 break;
957
958 default:
959 break;
960 }
961 break;
962
963 case SND_SOC_DAPM_POST_PMD:
964 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
965 WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
966 break;
967 }
968
969 return 0;
970}
971
972static int out_pga_event(struct snd_soc_dapm_widget *w,
973 struct snd_kcontrol *kcontrol, int event)
974{
975 struct snd_soc_codec *codec = w->codec;
976 struct wm8904_priv *wm8904 = codec->private_data;
977 int reg, val;
978 int dcs_mask;
979 int dcs_l, dcs_r;
980 int dcs_l_reg, dcs_r_reg;
981 int timeout;
982
983 /* This code is shared between HP and LINEOUT; we do all our
984 * power management in stereo pairs to avoid latency issues so
985 * we reuse shift to identify which rather than strcmp() the
986 * name. */
987 reg = w->shift;
988
989 switch (reg) {
990 case WM8904_ANALOGUE_HP_0:
991 dcs_mask = WM8904_DCS_ENA_CHAN_0 | WM8904_DCS_ENA_CHAN_1;
992 dcs_r_reg = WM8904_DC_SERVO_8;
993 dcs_l_reg = WM8904_DC_SERVO_9;
994 dcs_l = 0;
995 dcs_r = 1;
996 break;
997 case WM8904_ANALOGUE_LINEOUT_0:
998 dcs_mask = WM8904_DCS_ENA_CHAN_2 | WM8904_DCS_ENA_CHAN_3;
999 dcs_r_reg = WM8904_DC_SERVO_6;
1000 dcs_l_reg = WM8904_DC_SERVO_7;
1001 dcs_l = 2;
1002 dcs_r = 3;
1003 break;
1004 default:
1005 BUG();
1006 return -EINVAL;
1007 }
1008
1009 switch (event) {
1010 case SND_SOC_DAPM_POST_PMU:
1011 /* Power on the amplifier */
1012 snd_soc_update_bits(codec, reg,
1013 WM8904_HPL_ENA | WM8904_HPR_ENA,
1014 WM8904_HPL_ENA | WM8904_HPR_ENA);
1015
1016 /* Enable the first stage */
1017 snd_soc_update_bits(codec, reg,
1018 WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY,
1019 WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY);
1020
1021 /* Power up the DC servo */
1022 snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
1023 dcs_mask, dcs_mask);
1024
1025 /* Either calibrate the DC servo or restore cached state
1026 * if we have that.
1027 */
1028 if (wm8904->dcs_state[dcs_l] || wm8904->dcs_state[dcs_r]) {
1029 dev_dbg(codec->dev, "Restoring DC servo state\n");
1030
1031 snd_soc_write(codec, dcs_l_reg,
1032 wm8904->dcs_state[dcs_l]);
1033 snd_soc_write(codec, dcs_r_reg,
1034 wm8904->dcs_state[dcs_r]);
1035
1036 snd_soc_write(codec, WM8904_DC_SERVO_1, dcs_mask);
1037
1038 timeout = 20;
1039 } else {
1040 dev_dbg(codec->dev, "Calibrating DC servo\n");
1041
1042 snd_soc_write(codec, WM8904_DC_SERVO_1,
1043 dcs_mask << WM8904_DCS_TRIG_STARTUP_0_SHIFT);
1044
1045 timeout = 500;
1046 }
1047
1048 /* Wait for DC servo to complete */
1049 dcs_mask <<= WM8904_DCS_CAL_COMPLETE_SHIFT;
1050 do {
1051 val = snd_soc_read(codec, WM8904_DC_SERVO_READBACK_0);
1052 if ((val & dcs_mask) == dcs_mask)
1053 break;
1054
1055 msleep(1);
1056 } while (--timeout);
1057
1058 if ((val & dcs_mask) != dcs_mask)
1059 dev_warn(codec->dev, "DC servo timed out\n");
1060 else
1061 dev_dbg(codec->dev, "DC servo ready\n");
1062
1063 /* Enable the output stage */
1064 snd_soc_update_bits(codec, reg,
1065 WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
1066 WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP);
1067
1068 /* Unshort the output itself */
1069 snd_soc_update_bits(codec, reg,
1070 WM8904_HPL_RMV_SHORT |
1071 WM8904_HPR_RMV_SHORT,
1072 WM8904_HPL_RMV_SHORT |
1073 WM8904_HPR_RMV_SHORT);
1074
1075 break;
1076
1077 case SND_SOC_DAPM_PRE_PMD:
1078 /* Short the output */
1079 snd_soc_update_bits(codec, reg,
1080 WM8904_HPL_RMV_SHORT |
1081 WM8904_HPR_RMV_SHORT, 0);
1082
1083 /* Cache the DC servo configuration; this will be
1084 * invalidated if we change the configuration. */
1085 wm8904->dcs_state[dcs_l] = snd_soc_read(codec, dcs_l_reg);
1086 wm8904->dcs_state[dcs_r] = snd_soc_read(codec, dcs_r_reg);
1087
1088 snd_soc_update_bits(codec, WM8904_DC_SERVO_0,
1089 dcs_mask, 0);
1090
1091 /* Disable the amplifier input and output stages */
1092 snd_soc_update_bits(codec, reg,
1093 WM8904_HPL_ENA | WM8904_HPR_ENA |
1094 WM8904_HPL_ENA_DLY | WM8904_HPR_ENA_DLY |
1095 WM8904_HPL_ENA_OUTP | WM8904_HPR_ENA_OUTP,
1096 0);
1097 break;
1098 }
1099
1100 return 0;
1101}
1102
1103static const char *lin_text[] = {
1104 "IN1L", "IN2L", "IN3L"
1105};
1106
1107static const struct soc_enum lin_enum =
1108 SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text);
1109
1110static const struct snd_kcontrol_new lin_mux =
1111 SOC_DAPM_ENUM("Left Capture Mux", lin_enum);
1112
1113static const struct soc_enum lin_inv_enum =
1114 SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text);
1115
1116static const struct snd_kcontrol_new lin_inv_mux =
1117 SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum);
1118
1119static const char *rin_text[] = {
1120 "IN1R", "IN2R", "IN3R"
1121};
1122
1123static const struct soc_enum rin_enum =
1124 SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text);
1125
1126static const struct snd_kcontrol_new rin_mux =
1127 SOC_DAPM_ENUM("Right Capture Mux", rin_enum);
1128
1129static const struct soc_enum rin_inv_enum =
1130 SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text);
1131
1132static const struct snd_kcontrol_new rin_inv_mux =
1133 SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum);
1134
1135static const char *aif_text[] = {
1136 "Left", "Right"
1137};
1138
1139static const struct soc_enum aifoutl_enum =
1140 SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text);
1141
1142static const struct snd_kcontrol_new aifoutl_mux =
1143 SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum);
1144
1145static const struct soc_enum aifoutr_enum =
1146 SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text);
1147
1148static const struct snd_kcontrol_new aifoutr_mux =
1149 SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum);
1150
1151static const struct soc_enum aifinl_enum =
1152 SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text);
1153
1154static const struct snd_kcontrol_new aifinl_mux =
1155 SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum);
1156
1157static const struct soc_enum aifinr_enum =
1158 SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text);
1159
1160static const struct snd_kcontrol_new aifinr_mux =
1161 SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum);
1162
1163static const struct snd_soc_dapm_widget wm8904_core_dapm_widgets[] = {
1164SND_SOC_DAPM_SUPPLY("SYSCLK", WM8904_CLOCK_RATES_2, 2, 0, sysclk_event,
1165 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1166SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8904_CLOCK_RATES_2, 1, 0, NULL, 0),
1167SND_SOC_DAPM_SUPPLY("TOCLK", WM8904_CLOCK_RATES_2, 0, 0, NULL, 0),
1168};
1169
1170static const struct snd_soc_dapm_widget wm8904_adc_dapm_widgets[] = {
1171SND_SOC_DAPM_INPUT("IN1L"),
1172SND_SOC_DAPM_INPUT("IN1R"),
1173SND_SOC_DAPM_INPUT("IN2L"),
1174SND_SOC_DAPM_INPUT("IN2R"),
1175SND_SOC_DAPM_INPUT("IN3L"),
1176SND_SOC_DAPM_INPUT("IN3R"),
1177
1178SND_SOC_DAPM_MICBIAS("MICBIAS", WM8904_MIC_BIAS_CONTROL_0, 0, 0),
1179
1180SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lin_mux),
1181SND_SOC_DAPM_MUX("Left Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
1182 &lin_inv_mux),
1183SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rin_mux),
1184SND_SOC_DAPM_MUX("Right Capture Inverting Mux", SND_SOC_NOPM, 0, 0,
1185 &rin_inv_mux),
1186
1187SND_SOC_DAPM_PGA("Left Capture PGA", WM8904_POWER_MANAGEMENT_0, 1, 0,
1188 NULL, 0),
1189SND_SOC_DAPM_PGA("Right Capture PGA", WM8904_POWER_MANAGEMENT_0, 0, 0,
1190 NULL, 0),
1191
1192SND_SOC_DAPM_ADC("ADCL", NULL, WM8904_POWER_MANAGEMENT_6, 1, 0),
1193SND_SOC_DAPM_ADC("ADCR", NULL, WM8904_POWER_MANAGEMENT_6, 0, 0),
1194
1195SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux),
1196SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux),
1197
1198SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
1199SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
1200};
1201
1202static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = {
1203SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
1204SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
1205
1206SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux),
1207SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux),
1208
1209SND_SOC_DAPM_DAC("DACL", NULL, WM8904_POWER_MANAGEMENT_6, 3, 0),
1210SND_SOC_DAPM_DAC("DACR", NULL, WM8904_POWER_MANAGEMENT_6, 2, 0),
1211
1212SND_SOC_DAPM_SUPPLY("Charge pump", WM8904_CHARGE_PUMP_0, 0, 0, cp_event,
1213 SND_SOC_DAPM_POST_PMU),
1214
1215SND_SOC_DAPM_PGA("HPL PGA", WM8904_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
1216SND_SOC_DAPM_PGA("HPR PGA", WM8904_POWER_MANAGEMENT_2, 0, 0, NULL, 0),
1217
1218SND_SOC_DAPM_PGA("LINEL PGA", WM8904_POWER_MANAGEMENT_3, 1, 0, NULL, 0),
1219SND_SOC_DAPM_PGA("LINER PGA", WM8904_POWER_MANAGEMENT_3, 0, 0, NULL, 0),
1220
1221SND_SOC_DAPM_PGA_E("Headphone Output", SND_SOC_NOPM, WM8904_ANALOGUE_HP_0,
1222 0, NULL, 0, out_pga_event,
1223 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1224SND_SOC_DAPM_PGA_E("Line Output", SND_SOC_NOPM, WM8904_ANALOGUE_LINEOUT_0,
1225 0, NULL, 0, out_pga_event,
1226 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
1227
1228SND_SOC_DAPM_OUTPUT("HPOUTL"),
1229SND_SOC_DAPM_OUTPUT("HPOUTR"),
1230SND_SOC_DAPM_OUTPUT("LINEOUTL"),
1231SND_SOC_DAPM_OUTPUT("LINEOUTR"),
1232};
1233
1234static const char *out_mux_text[] = {
1235 "DAC", "Bypass"
1236};
1237
1238static const struct soc_enum hpl_enum =
1239 SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text);
1240
1241static const struct snd_kcontrol_new hpl_mux =
1242 SOC_DAPM_ENUM("HPL Mux", hpl_enum);
1243
1244static const struct soc_enum hpr_enum =
1245 SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text);
1246
1247static const struct snd_kcontrol_new hpr_mux =
1248 SOC_DAPM_ENUM("HPR Mux", hpr_enum);
1249
1250static const struct soc_enum linel_enum =
1251 SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text);
1252
1253static const struct snd_kcontrol_new linel_mux =
1254 SOC_DAPM_ENUM("LINEL Mux", linel_enum);
1255
1256static const struct soc_enum liner_enum =
1257 SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text);
1258
1259static const struct snd_kcontrol_new liner_mux =
1260 SOC_DAPM_ENUM("LINEL Mux", liner_enum);
1261
1262static const char *sidetone_text[] = {
1263 "None", "Left", "Right"
1264};
1265
1266static const struct soc_enum dacl_sidetone_enum =
1267 SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text);
1268
1269static const struct snd_kcontrol_new dacl_sidetone_mux =
1270 SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum);
1271
1272static const struct soc_enum dacr_sidetone_enum =
1273 SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text);
1274
1275static const struct snd_kcontrol_new dacr_sidetone_mux =
1276 SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum);
1277
1278static const struct snd_soc_dapm_widget wm8904_dapm_widgets[] = {
1279SND_SOC_DAPM_SUPPLY("Class G", WM8904_CLASS_W_0, 0, 1, NULL, 0),
1280SND_SOC_DAPM_PGA("Left Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
1281SND_SOC_DAPM_PGA("Right Bypass", SND_SOC_NOPM, 0, 0, NULL, 0),
1282
1283SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &dacl_sidetone_mux),
1284SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &dacr_sidetone_mux),
1285
1286SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
1287SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
1288SND_SOC_DAPM_MUX("LINEL Mux", SND_SOC_NOPM, 0, 0, &linel_mux),
1289SND_SOC_DAPM_MUX("LINER Mux", SND_SOC_NOPM, 0, 0, &liner_mux),
1290};
1291
1292static const struct snd_soc_dapm_route core_intercon[] = {
1293 { "CLK_DSP", NULL, "SYSCLK" },
1294 { "TOCLK", NULL, "SYSCLK" },
1295};
1296
1297static const struct snd_soc_dapm_route adc_intercon[] = {
1298 { "Left Capture Mux", "IN1L", "IN1L" },
1299 { "Left Capture Mux", "IN2L", "IN2L" },
1300 { "Left Capture Mux", "IN3L", "IN3L" },
1301
1302 { "Left Capture Inverting Mux", "IN1L", "IN1L" },
1303 { "Left Capture Inverting Mux", "IN2L", "IN2L" },
1304 { "Left Capture Inverting Mux", "IN3L", "IN3L" },
1305
1306 { "Right Capture Mux", "IN1R", "IN1R" },
1307 { "Right Capture Mux", "IN2R", "IN2R" },
1308 { "Right Capture Mux", "IN3R", "IN3R" },
1309
1310 { "Right Capture Inverting Mux", "IN1R", "IN1R" },
1311 { "Right Capture Inverting Mux", "IN2R", "IN2R" },
1312 { "Right Capture Inverting Mux", "IN3R", "IN3R" },
1313
1314 { "Left Capture PGA", NULL, "Left Capture Mux" },
1315 { "Left Capture PGA", NULL, "Left Capture Inverting Mux" },
1316
1317 { "Right Capture PGA", NULL, "Right Capture Mux" },
1318 { "Right Capture PGA", NULL, "Right Capture Inverting Mux" },
1319
1320 { "AIFOUTL", "Left", "ADCL" },
1321 { "AIFOUTL", "Right", "ADCR" },
1322 { "AIFOUTR", "Left", "ADCL" },
1323 { "AIFOUTR", "Right", "ADCR" },
1324
1325 { "ADCL", NULL, "CLK_DSP" },
1326 { "ADCL", NULL, "Left Capture PGA" },
1327
1328 { "ADCR", NULL, "CLK_DSP" },
1329 { "ADCR", NULL, "Right Capture PGA" },
1330};
1331
1332static const struct snd_soc_dapm_route dac_intercon[] = {
1333 { "DACL", "Right", "AIFINR" },
1334 { "DACL", "Left", "AIFINL" },
1335 { "DACL", NULL, "CLK_DSP" },
1336
1337 { "DACR", "Right", "AIFINR" },
1338 { "DACR", "Left", "AIFINL" },
1339 { "DACR", NULL, "CLK_DSP" },
1340
1341 { "Charge pump", NULL, "SYSCLK" },
1342
1343 { "Headphone Output", NULL, "HPL PGA" },
1344 { "Headphone Output", NULL, "HPR PGA" },
1345 { "Headphone Output", NULL, "Charge pump" },
1346 { "Headphone Output", NULL, "TOCLK" },
1347
1348 { "Line Output", NULL, "LINEL PGA" },
1349 { "Line Output", NULL, "LINER PGA" },
1350 { "Line Output", NULL, "Charge pump" },
1351 { "Line Output", NULL, "TOCLK" },
1352
1353 { "HPOUTL", NULL, "Headphone Output" },
1354 { "HPOUTR", NULL, "Headphone Output" },
1355
1356 { "LINEOUTL", NULL, "Line Output" },
1357 { "LINEOUTR", NULL, "Line Output" },
1358};
1359
1360static const struct snd_soc_dapm_route wm8904_intercon[] = {
1361 { "Left Sidetone", "Left", "ADCL" },
1362 { "Left Sidetone", "Right", "ADCR" },
1363 { "DACL", NULL, "Left Sidetone" },
1364
1365 { "Right Sidetone", "Left", "ADCL" },
1366 { "Right Sidetone", "Right", "ADCR" },
1367 { "DACR", NULL, "Right Sidetone" },
1368
1369 { "Left Bypass", NULL, "Class G" },
1370 { "Left Bypass", NULL, "Left Capture PGA" },
1371
1372 { "Right Bypass", NULL, "Class G" },
1373 { "Right Bypass", NULL, "Right Capture PGA" },
1374
1375 { "HPL Mux", "DAC", "DACL" },
1376 { "HPL Mux", "Bypass", "Left Bypass" },
1377
1378 { "HPR Mux", "DAC", "DACR" },
1379 { "HPR Mux", "Bypass", "Right Bypass" },
1380
1381 { "LINEL Mux", "DAC", "DACL" },
1382 { "LINEL Mux", "Bypass", "Left Bypass" },
1383
1384 { "LINER Mux", "DAC", "DACR" },
1385 { "LINER Mux", "Bypass", "Right Bypass" },
1386
1387 { "HPL PGA", NULL, "HPL Mux" },
1388 { "HPR PGA", NULL, "HPR Mux" },
1389
1390 { "LINEL PGA", NULL, "LINEL Mux" },
1391 { "LINER PGA", NULL, "LINER Mux" },
1392};
1393
1394static int wm8904_add_widgets(struct snd_soc_codec *codec)
1395{
1396 snd_soc_add_controls(codec, wm8904_adc_snd_controls,
1397 ARRAY_SIZE(wm8904_adc_snd_controls));
1398 snd_soc_add_controls(codec, wm8904_dac_snd_controls,
1399 ARRAY_SIZE(wm8904_dac_snd_controls));
1400 snd_soc_add_controls(codec, wm8904_snd_controls,
1401 ARRAY_SIZE(wm8904_snd_controls));
1402
1403 snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets,
1404 ARRAY_SIZE(wm8904_core_dapm_widgets));
1405 snd_soc_dapm_new_controls(codec, wm8904_adc_dapm_widgets,
1406 ARRAY_SIZE(wm8904_adc_dapm_widgets));
1407 snd_soc_dapm_new_controls(codec, wm8904_dac_dapm_widgets,
1408 ARRAY_SIZE(wm8904_dac_dapm_widgets));
1409 snd_soc_dapm_new_controls(codec, wm8904_dapm_widgets,
1410 ARRAY_SIZE(wm8904_dapm_widgets));
1411
1412 snd_soc_dapm_add_routes(codec, core_intercon,
1413 ARRAY_SIZE(core_intercon));
1414 snd_soc_dapm_add_routes(codec, adc_intercon, ARRAY_SIZE(adc_intercon));
1415 snd_soc_dapm_add_routes(codec, dac_intercon, ARRAY_SIZE(dac_intercon));
1416 snd_soc_dapm_add_routes(codec, wm8904_intercon,
1417 ARRAY_SIZE(wm8904_intercon));
1418
1419 snd_soc_dapm_new_widgets(codec);
1420 return 0;
1421}
1422
1423static struct {
1424 int ratio;
1425 unsigned int clk_sys_rate;
1426} clk_sys_rates[] = {
1427 { 64, 0 },
1428 { 128, 1 },
1429 { 192, 2 },
1430 { 256, 3 },
1431 { 384, 4 },
1432 { 512, 5 },
1433 { 786, 6 },
1434 { 1024, 7 },
1435 { 1408, 8 },
1436 { 1536, 9 },
1437};
1438
1439static struct {
1440 int rate;
1441 int sample_rate;
1442} sample_rates[] = {
1443 { 8000, 0 },
1444 { 11025, 1 },
1445 { 12000, 1 },
1446 { 16000, 2 },
1447 { 22050, 3 },
1448 { 24000, 3 },
1449 { 32000, 4 },
1450 { 44100, 5 },
1451 { 48000, 5 },
1452};
1453
1454static struct {
1455 int div; /* *10 due to .5s */
1456 int bclk_div;
1457} bclk_divs[] = {
1458 { 10, 0 },
1459 { 15, 1 },
1460 { 20, 2 },
1461 { 30, 3 },
1462 { 40, 4 },
1463 { 50, 5 },
1464 { 55, 6 },
1465 { 60, 7 },
1466 { 80, 8 },
1467 { 100, 9 },
1468 { 110, 10 },
1469 { 120, 11 },
1470 { 160, 12 },
1471 { 200, 13 },
1472 { 220, 14 },
1473 { 240, 16 },
1474 { 200, 17 },
1475 { 320, 18 },
1476 { 440, 19 },
1477 { 480, 20 },
1478};
1479
1480
1481static int wm8904_hw_params(struct snd_pcm_substream *substream,
1482 struct snd_pcm_hw_params *params,
1483 struct snd_soc_dai *dai)
1484{
1485 struct snd_soc_codec *codec = dai->codec;
1486 struct wm8904_priv *wm8904 = codec->private_data;
1487 int ret, i, best, best_val, cur_val;
1488 unsigned int aif1 = 0;
1489 unsigned int aif2 = 0;
1490 unsigned int aif3 = 0;
1491 unsigned int clock1 = 0;
1492 unsigned int dac_digital1 = 0;
1493
1494 /* What BCLK do we need? */
1495 wm8904->fs = params_rate(params);
1496 if (wm8904->tdm_slots) {
1497 dev_dbg(codec->dev, "Configuring for %d %d bit TDM slots\n",
1498 wm8904->tdm_slots, wm8904->tdm_width);
1499 wm8904->bclk = snd_soc_calc_bclk(wm8904->fs,
1500 wm8904->tdm_width, 2,
1501 wm8904->tdm_slots);
1502 } else {
1503 wm8904->bclk = snd_soc_params_to_bclk(params);
1504 }
1505
1506 switch (params_format(params)) {
1507 case SNDRV_PCM_FORMAT_S16_LE:
1508 break;
1509 case SNDRV_PCM_FORMAT_S20_3LE:
1510 aif1 |= 0x40;
1511 break;
1512 case SNDRV_PCM_FORMAT_S24_LE:
1513 aif1 |= 0x80;
1514 break;
1515 case SNDRV_PCM_FORMAT_S32_LE:
1516 aif1 |= 0xc0;
1517 break;
1518 default:
1519 return -EINVAL;
1520 }
1521
1522
1523 dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8904->bclk);
1524
1525 ret = wm8904_configure_clocking(codec);
1526 if (ret != 0)
1527 return ret;
1528
1529 /* Select nearest CLK_SYS_RATE */
1530 best = 0;
1531 best_val = abs((wm8904->sysclk_rate / clk_sys_rates[0].ratio)
1532 - wm8904->fs);
1533 for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) {
1534 cur_val = abs((wm8904->sysclk_rate /
1535 clk_sys_rates[i].ratio) - wm8904->fs);;
1536 if (cur_val < best_val) {
1537 best = i;
1538 best_val = cur_val;
1539 }
1540 }
1541 dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n",
1542 clk_sys_rates[best].ratio);
1543 clock1 |= (clk_sys_rates[best].clk_sys_rate
1544 << WM8904_CLK_SYS_RATE_SHIFT);
1545
1546 /* SAMPLE_RATE */
1547 best = 0;
1548 best_val = abs(wm8904->fs - sample_rates[0].rate);
1549 for (i = 1; i < ARRAY_SIZE(sample_rates); i++) {
1550 /* Closest match */
1551 cur_val = abs(wm8904->fs - sample_rates[i].rate);
1552 if (cur_val < best_val) {
1553 best = i;
1554 best_val = cur_val;
1555 }
1556 }
1557 dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n",
1558 sample_rates[best].rate);
1559 clock1 |= (sample_rates[best].sample_rate
1560 << WM8904_SAMPLE_RATE_SHIFT);
1561
1562 /* Enable sloping stopband filter for low sample rates */
1563 if (wm8904->fs <= 24000)
1564 dac_digital1 |= WM8904_DAC_SB_FILT;
1565
1566 /* BCLK_DIV */
1567 best = 0;
1568 best_val = INT_MAX;
1569 for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
1570 cur_val = ((wm8904->sysclk_rate * 10) / bclk_divs[i].div)
1571 - wm8904->bclk;
1572 if (cur_val < 0) /* Table is sorted */
1573 break;
1574 if (cur_val < best_val) {
1575 best = i;
1576 best_val = cur_val;
1577 }
1578 }
1579 wm8904->bclk = (wm8904->sysclk_rate * 10) / bclk_divs[best].div;
1580 dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n",
1581 bclk_divs[best].div, wm8904->bclk);
1582 aif2 |= bclk_divs[best].bclk_div;
1583
1584 /* LRCLK is a simple fraction of BCLK */
1585 dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8904->bclk / wm8904->fs);
1586 aif3 |= wm8904->bclk / wm8904->fs;
1587
1588 /* Apply the settings */
1589 snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1,
1590 WM8904_DAC_SB_FILT, dac_digital1);
1591 snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
1592 WM8904_AIF_WL_MASK, aif1);
1593 snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_2,
1594 WM8904_BCLK_DIV_MASK, aif2);
1595 snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
1596 WM8904_LRCLK_RATE_MASK, aif3);
1597 snd_soc_update_bits(codec, WM8904_CLOCK_RATES_1,
1598 WM8904_SAMPLE_RATE_MASK |
1599 WM8904_CLK_SYS_RATE_MASK, clock1);
1600
1601 /* Update filters for the new settings */
1602 wm8904_set_retune_mobile(codec);
1603 wm8904_set_deemph(codec);
1604
1605 return 0;
1606}
1607
1608
1609static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
1610 unsigned int freq, int dir)
1611{
1612 struct snd_soc_codec *codec = dai->codec;
1613 struct wm8904_priv *priv = codec->private_data;
1614
1615 switch (clk_id) {
1616 case WM8904_CLK_MCLK:
1617 priv->sysclk_src = clk_id;
1618 priv->mclk_rate = freq;
1619 break;
1620
1621 case WM8904_CLK_FLL:
1622 priv->sysclk_src = clk_id;
1623 break;
1624
1625 default:
1626 return -EINVAL;
1627 }
1628
1629 dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
1630
1631 wm8904_configure_clocking(codec);
1632
1633 return 0;
1634}
1635
1636static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1637{
1638 struct snd_soc_codec *codec = dai->codec;
1639 unsigned int aif1 = 0;
1640 unsigned int aif3 = 0;
1641
1642 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1643 case SND_SOC_DAIFMT_CBS_CFS:
1644 break;
1645 case SND_SOC_DAIFMT_CBS_CFM:
1646 aif3 |= WM8904_LRCLK_DIR;
1647 break;
1648 case SND_SOC_DAIFMT_CBM_CFS:
1649 aif1 |= WM8904_BCLK_DIR;
1650 break;
1651 case SND_SOC_DAIFMT_CBM_CFM:
1652 aif1 |= WM8904_BCLK_DIR;
1653 aif3 |= WM8904_LRCLK_DIR;
1654 break;
1655 default:
1656 return -EINVAL;
1657 }
1658
1659 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1660 case SND_SOC_DAIFMT_DSP_B:
1661 aif1 |= WM8904_AIF_LRCLK_INV;
1662 case SND_SOC_DAIFMT_DSP_A:
1663 aif1 |= 0x3;
1664 break;
1665 case SND_SOC_DAIFMT_I2S:
1666 aif1 |= 0x2;
1667 break;
1668 case SND_SOC_DAIFMT_RIGHT_J:
1669 break;
1670 case SND_SOC_DAIFMT_LEFT_J:
1671 aif1 |= 0x1;
1672 break;
1673 default:
1674 return -EINVAL;
1675 }
1676
1677 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1678 case SND_SOC_DAIFMT_DSP_A:
1679 case SND_SOC_DAIFMT_DSP_B:
1680 /* frame inversion not valid for DSP modes */
1681 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1682 case SND_SOC_DAIFMT_NB_NF:
1683 break;
1684 case SND_SOC_DAIFMT_IB_NF:
1685 aif1 |= WM8904_AIF_BCLK_INV;
1686 break;
1687 default:
1688 return -EINVAL;
1689 }
1690 break;
1691
1692 case SND_SOC_DAIFMT_I2S:
1693 case SND_SOC_DAIFMT_RIGHT_J:
1694 case SND_SOC_DAIFMT_LEFT_J:
1695 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1696 case SND_SOC_DAIFMT_NB_NF:
1697 break;
1698 case SND_SOC_DAIFMT_IB_IF:
1699 aif1 |= WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV;
1700 break;
1701 case SND_SOC_DAIFMT_IB_NF:
1702 aif1 |= WM8904_AIF_BCLK_INV;
1703 break;
1704 case SND_SOC_DAIFMT_NB_IF:
1705 aif1 |= WM8904_AIF_LRCLK_INV;
1706 break;
1707 default:
1708 return -EINVAL;
1709 }
1710 break;
1711 default:
1712 return -EINVAL;
1713 }
1714
1715 snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
1716 WM8904_AIF_BCLK_INV | WM8904_AIF_LRCLK_INV |
1717 WM8904_AIF_FMT_MASK | WM8904_BCLK_DIR, aif1);
1718 snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_3,
1719 WM8904_LRCLK_DIR, aif3);
1720
1721 return 0;
1722}
1723
1724
1725static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1726 unsigned int rx_mask, int slots, int slot_width)
1727{
1728 struct snd_soc_codec *codec = dai->codec;
1729 struct wm8904_priv *wm8904 = codec->private_data;
1730 int aif1 = 0;
1731
1732 /* Don't need to validate anything if we're turning off TDM */
1733 if (slots == 0)
1734 goto out;
1735
1736 /* Note that we allow configurations we can't handle ourselves -
1737 * for example, we can generate clocks for slots 2 and up even if
1738 * we can't use those slots ourselves.
1739 */
1740 aif1 |= WM8904_AIFADC_TDM | WM8904_AIFDAC_TDM;
1741
1742 switch (rx_mask) {
1743 case 3:
1744 break;
1745 case 0xc:
1746 aif1 |= WM8904_AIFADC_TDM_CHAN;
1747 break;
1748 default:
1749 return -EINVAL;
1750 }
1751
1752
1753 switch (tx_mask) {
1754 case 3:
1755 break;
1756 case 0xc:
1757 aif1 |= WM8904_AIFDAC_TDM_CHAN;
1758 break;
1759 default:
1760 return -EINVAL;
1761 }
1762
1763out:
1764 wm8904->tdm_width = slot_width;
1765 wm8904->tdm_slots = slots / 2;
1766
1767 snd_soc_update_bits(codec, WM8904_AUDIO_INTERFACE_1,
1768 WM8904_AIFADC_TDM | WM8904_AIFADC_TDM_CHAN |
1769 WM8904_AIFDAC_TDM | WM8904_AIFDAC_TDM_CHAN, aif1);
1770
1771 return 0;
1772}
1773
1774struct _fll_div {
1775 u16 fll_fratio;
1776 u16 fll_outdiv;
1777 u16 fll_clk_ref_div;
1778 u16 n;
1779 u16 k;
1780};
1781
1782/* The size in bits of the FLL divide multiplied by 10
1783 * to allow rounding later */
1784#define FIXED_FLL_SIZE ((1 << 16) * 10)
1785
1786static struct {
1787 unsigned int min;
1788 unsigned int max;
1789 u16 fll_fratio;
1790 int ratio;
1791} fll_fratios[] = {
1792 { 0, 64000, 4, 16 },
1793 { 64000, 128000, 3, 8 },
1794 { 128000, 256000, 2, 4 },
1795 { 256000, 1000000, 1, 2 },
1796 { 1000000, 13500000, 0, 1 },
1797};
1798
1799static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
1800 unsigned int Fout)
1801{
1802 u64 Kpart;
1803 unsigned int K, Ndiv, Nmod, target;
1804 unsigned int div;
1805 int i;
1806
1807 /* Fref must be <=13.5MHz */
1808 div = 1;
1809 fll_div->fll_clk_ref_div = 0;
1810 while ((Fref / div) > 13500000) {
1811 div *= 2;
1812 fll_div->fll_clk_ref_div++;
1813
1814 if (div > 8) {
1815 pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
1816 Fref);
1817 return -EINVAL;
1818 }
1819 }
1820
1821 pr_debug("Fref=%u Fout=%u\n", Fref, Fout);
1822
1823 /* Apply the division for our remaining calculations */
1824 Fref /= div;
1825
1826 /* Fvco should be 90-100MHz; don't check the upper bound */
1827 div = 4;
1828 while (Fout * div < 90000000) {
1829 div++;
1830 if (div > 64) {
1831 pr_err("Unable to find FLL_OUTDIV for Fout=%uHz\n",
1832 Fout);
1833 return -EINVAL;
1834 }
1835 }
1836 target = Fout * div;
1837 fll_div->fll_outdiv = div - 1;
1838
1839 pr_debug("Fvco=%dHz\n", target);
1840
1841 /* Find an appropraite FLL_FRATIO and factor it out of the target */
1842 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
1843 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
1844 fll_div->fll_fratio = fll_fratios[i].fll_fratio;
1845 target /= fll_fratios[i].ratio;
1846 break;
1847 }
1848 }
1849 if (i == ARRAY_SIZE(fll_fratios)) {
1850 pr_err("Unable to find FLL_FRATIO for Fref=%uHz\n", Fref);
1851 return -EINVAL;
1852 }
1853
1854 /* Now, calculate N.K */
1855 Ndiv = target / Fref;
1856
1857 fll_div->n = Ndiv;
1858 Nmod = target % Fref;
1859 pr_debug("Nmod=%d\n", Nmod);
1860
1861 /* Calculate fractional part - scale up so we can round. */
1862 Kpart = FIXED_FLL_SIZE * (long long)Nmod;
1863
1864 do_div(Kpart, Fref);
1865
1866 K = Kpart & 0xFFFFFFFF;
1867
1868 if ((K % 10) >= 5)
1869 K += 5;
1870
1871 /* Move down to proper range now rounding is done */
1872 fll_div->k = K / 10;
1873
1874 pr_debug("N=%x K=%x FLL_FRATIO=%x FLL_OUTDIV=%x FLL_CLK_REF_DIV=%x\n",
1875 fll_div->n, fll_div->k,
1876 fll_div->fll_fratio, fll_div->fll_outdiv,
1877 fll_div->fll_clk_ref_div);
1878
1879 return 0;
1880}
1881
1882static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
1883 unsigned int Fref, unsigned int Fout)
1884{
1885 struct snd_soc_codec *codec = dai->codec;
1886 struct wm8904_priv *wm8904 = codec->private_data;
1887 struct _fll_div fll_div;
1888 int ret, val;
1889 int clock2, fll1;
1890
1891 /* Any change? */
1892 if (source == wm8904->fll_src && Fref == wm8904->fll_fref &&
1893 Fout == wm8904->fll_fout)
1894 return 0;
1895
1896 clock2 = snd_soc_read(codec, WM8904_CLOCK_RATES_2);
1897
1898 if (Fout == 0) {
1899 dev_dbg(codec->dev, "FLL disabled\n");
1900
1901 wm8904->fll_fref = 0;
1902 wm8904->fll_fout = 0;
1903
1904 /* Gate SYSCLK to avoid glitches */
1905 snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
1906 WM8904_CLK_SYS_ENA, 0);
1907
1908 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
1909 WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
1910
1911 goto out;
1912 }
1913
1914 /* Validate the FLL ID */
1915 switch (source) {
1916 case WM8904_FLL_MCLK:
1917 case WM8904_FLL_LRCLK:
1918 case WM8904_FLL_BCLK:
1919 ret = fll_factors(&fll_div, Fref, Fout);
1920 if (ret != 0)
1921 return ret;
1922 break;
1923
1924 case WM8904_FLL_FREE_RUNNING:
1925 dev_dbg(codec->dev, "Using free running FLL\n");
1926 /* Force 12MHz and output/4 for now */
1927 Fout = 12000000;
1928 Fref = 12000000;
1929
1930 memset(&fll_div, 0, sizeof(fll_div));
1931 fll_div.fll_outdiv = 3;
1932 break;
1933
1934 default:
1935 dev_err(codec->dev, "Unknown FLL ID %d\n", fll_id);
1936 return -EINVAL;
1937 }
1938
1939 /* Save current state then disable the FLL and SYSCLK to avoid
1940 * misclocking */
1941 fll1 = snd_soc_read(codec, WM8904_FLL_CONTROL_1);
1942 snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
1943 WM8904_CLK_SYS_ENA, 0);
1944 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
1945 WM8904_FLL_OSC_ENA | WM8904_FLL_ENA, 0);
1946
1947 /* Unlock forced oscilator control to switch it on/off */
1948 snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
1949 WM8904_USER_KEY, WM8904_USER_KEY);
1950
1951 if (fll_id == WM8904_FLL_FREE_RUNNING) {
1952 val = WM8904_FLL_FRC_NCO;
1953 } else {
1954 val = 0;
1955 }
1956
1957 snd_soc_update_bits(codec, WM8904_FLL_NCO_TEST_1, WM8904_FLL_FRC_NCO,
1958 val);
1959 snd_soc_update_bits(codec, WM8904_CONTROL_INTERFACE_TEST_1,
1960 WM8904_USER_KEY, 0);
1961
1962 switch (fll_id) {
1963 case WM8904_FLL_MCLK:
1964 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
1965 WM8904_FLL_CLK_REF_SRC_MASK, 0);
1966 break;
1967
1968 case WM8904_FLL_LRCLK:
1969 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
1970 WM8904_FLL_CLK_REF_SRC_MASK, 1);
1971 break;
1972
1973 case WM8904_FLL_BCLK:
1974 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
1975 WM8904_FLL_CLK_REF_SRC_MASK, 2);
1976 break;
1977 }
1978
1979 if (fll_div.k)
1980 val = WM8904_FLL_FRACN_ENA;
1981 else
1982 val = 0;
1983 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
1984 WM8904_FLL_FRACN_ENA, val);
1985
1986 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_2,
1987 WM8904_FLL_OUTDIV_MASK | WM8904_FLL_FRATIO_MASK,
1988 (fll_div.fll_outdiv << WM8904_FLL_OUTDIV_SHIFT) |
1989 (fll_div.fll_fratio << WM8904_FLL_FRATIO_SHIFT));
1990
1991 snd_soc_write(codec, WM8904_FLL_CONTROL_3, fll_div.k);
1992
1993 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_4, WM8904_FLL_N_MASK,
1994 fll_div.n << WM8904_FLL_N_SHIFT);
1995
1996 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_5,
1997 WM8904_FLL_CLK_REF_DIV_MASK,
1998 fll_div.fll_clk_ref_div
1999 << WM8904_FLL_CLK_REF_DIV_SHIFT);
2000
2001 dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
2002
2003 wm8904->fll_fref = Fref;
2004 wm8904->fll_fout = Fout;
2005 wm8904->fll_src = source;
2006
2007 /* Enable the FLL if it was previously active */
2008 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
2009 WM8904_FLL_OSC_ENA, fll1);
2010 snd_soc_update_bits(codec, WM8904_FLL_CONTROL_1,
2011 WM8904_FLL_ENA, fll1);
2012
2013out:
2014 /* Reenable SYSCLK if it was previously active */
2015 snd_soc_update_bits(codec, WM8904_CLOCK_RATES_2,
2016 WM8904_CLK_SYS_ENA, clock2);
2017
2018 return 0;
2019}
2020
2021static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
2022{
2023 struct snd_soc_codec *codec = codec_dai->codec;
2024 int val;
2025
2026 if (mute)
2027 val = WM8904_DAC_MUTE;
2028 else
2029 val = 0;
2030
2031 snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_1, WM8904_DAC_MUTE, val);
2032
2033 return 0;
2034}
2035
2036static int wm8904_set_bias_level(struct snd_soc_codec *codec,
2037 enum snd_soc_bias_level level)
2038{
2039 struct wm8904_priv *wm8904 = codec->private_data;
2040 int ret, i;
2041
2042 switch (level) {
2043 case SND_SOC_BIAS_ON:
2044 break;
2045
2046 case SND_SOC_BIAS_PREPARE:
2047 /* VMID resistance 2*50k */
2048 snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
2049 WM8904_VMID_RES_MASK,
2050 0x1 << WM8904_VMID_RES_SHIFT);
2051
2052 /* Normal bias current */
2053 snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
2054 WM8904_ISEL_MASK, 2 << WM8904_ISEL_SHIFT);
2055 break;
2056
2057 case SND_SOC_BIAS_STANDBY:
2058 if (codec->bias_level == SND_SOC_BIAS_OFF) {
2059 ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
2060 wm8904->supplies);
2061 if (ret != 0) {
2062 dev_err(codec->dev,
2063 "Failed to enable supplies: %d\n",
2064 ret);
2065 return ret;
2066 }
2067
2068 /* Sync back cached values if they're
2069 * different from the hardware default.
2070 */
2071 for (i = 1; i < ARRAY_SIZE(wm8904->reg_cache); i++) {
2072 if (!wm8904_access[i].writable)
2073 continue;
2074
2075 if (wm8904->reg_cache[i] == wm8904_reg[i])
2076 continue;
2077
2078 snd_soc_write(codec, i, wm8904->reg_cache[i]);
2079 }
2080
2081 /* Enable bias */
2082 snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
2083 WM8904_BIAS_ENA, WM8904_BIAS_ENA);
2084
2085 /* Enable VMID, VMID buffering, 2*5k resistance */
2086 snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
2087 WM8904_VMID_ENA |
2088 WM8904_VMID_RES_MASK,
2089 WM8904_VMID_ENA |
2090 0x3 << WM8904_VMID_RES_SHIFT);
2091
2092 /* Let VMID ramp */
2093 msleep(1);
2094 }
2095
2096 /* Maintain VMID with 2*250k */
2097 snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
2098 WM8904_VMID_RES_MASK,
2099 0x2 << WM8904_VMID_RES_SHIFT);
2100
2101 /* Bias current *0.5 */
2102 snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
2103 WM8904_ISEL_MASK, 0);
2104 break;
2105
2106 case SND_SOC_BIAS_OFF:
2107 /* Turn off VMID */
2108 snd_soc_update_bits(codec, WM8904_VMID_CONTROL_0,
2109 WM8904_VMID_RES_MASK | WM8904_VMID_ENA, 0);
2110
2111 /* Stop bias generation */
2112 snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0,
2113 WM8904_BIAS_ENA, 0);
2114
2115 regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies),
2116 wm8904->supplies);
2117 break;
2118 }
2119 codec->bias_level = level;
2120 return 0;
2121}
2122
2123#define WM8904_RATES SNDRV_PCM_RATE_8000_96000
2124
2125#define WM8904_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
2126 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
2127
2128static struct snd_soc_dai_ops wm8904_dai_ops = {
2129 .set_sysclk = wm8904_set_sysclk,
2130 .set_fmt = wm8904_set_fmt,
2131 .set_tdm_slot = wm8904_set_tdm_slot,
2132 .set_pll = wm8904_set_fll,
2133 .hw_params = wm8904_hw_params,
2134 .digital_mute = wm8904_digital_mute,
2135};
2136
2137struct snd_soc_dai wm8904_dai = {
2138 .name = "WM8904",
2139 .playback = {
2140 .stream_name = "Playback",
2141 .channels_min = 2,
2142 .channels_max = 2,
2143 .rates = WM8904_RATES,
2144 .formats = WM8904_FORMATS,
2145 },
2146 .capture = {
2147 .stream_name = "Capture",
2148 .channels_min = 2,
2149 .channels_max = 2,
2150 .rates = WM8904_RATES,
2151 .formats = WM8904_FORMATS,
2152 },
2153 .ops = &wm8904_dai_ops,
2154 .symmetric_rates = 1,
2155};
2156EXPORT_SYMBOL_GPL(wm8904_dai);
2157
2158#ifdef CONFIG_PM
2159static int wm8904_suspend(struct platform_device *pdev, pm_message_t state)
2160{
2161 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2162 struct snd_soc_codec *codec = socdev->card->codec;
2163
2164 wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF);
2165
2166 return 0;
2167}
2168
2169static int wm8904_resume(struct platform_device *pdev)
2170{
2171 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2172 struct snd_soc_codec *codec = socdev->card->codec;
2173
2174 wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
2175
2176 return 0;
2177}
2178#else
2179#define wm8904_suspend NULL
2180#define wm8904_resume NULL
2181#endif
2182
2183static void wm8904_handle_retune_mobile_pdata(struct wm8904_priv *wm8904)
2184{
2185 struct snd_soc_codec *codec = &wm8904->codec;
2186 struct wm8904_pdata *pdata = wm8904->pdata;
2187 struct snd_kcontrol_new control =
2188 SOC_ENUM_EXT("EQ Mode",
2189 wm8904->retune_mobile_enum,
2190 wm8904_get_retune_mobile_enum,
2191 wm8904_put_retune_mobile_enum);
2192 int ret, i, j;
2193 const char **t;
2194
2195 /* We need an array of texts for the enum API but the number
2196 * of texts is likely to be less than the number of
2197 * configurations due to the sample rate dependency of the
2198 * configurations. */
2199 wm8904->num_retune_mobile_texts = 0;
2200 wm8904->retune_mobile_texts = NULL;
2201 for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
2202 for (j = 0; j < wm8904->num_retune_mobile_texts; j++) {
2203 if (strcmp(pdata->retune_mobile_cfgs[i].name,
2204 wm8904->retune_mobile_texts[j]) == 0)
2205 break;
2206 }
2207
2208 if (j != wm8904->num_retune_mobile_texts)
2209 continue;
2210
2211 /* Expand the array... */
2212 t = krealloc(wm8904->retune_mobile_texts,
2213 sizeof(char *) *
2214 (wm8904->num_retune_mobile_texts + 1),
2215 GFP_KERNEL);
2216 if (t == NULL)
2217 continue;
2218
2219 /* ...store the new entry... */
2220 t[wm8904->num_retune_mobile_texts] =
2221 pdata->retune_mobile_cfgs[i].name;
2222
2223 /* ...and remember the new version. */
2224 wm8904->num_retune_mobile_texts++;
2225 wm8904->retune_mobile_texts = t;
2226 }
2227
2228 dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
2229 wm8904->num_retune_mobile_texts);
2230
2231 wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts;
2232 wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts;
2233
2234 ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
2235 if (ret != 0)
2236 dev_err(wm8904->codec.dev,
2237 "Failed to add ReTune Mobile control: %d\n", ret);
2238}
2239
2240static void wm8904_handle_pdata(struct wm8904_priv *wm8904)
2241{
2242 struct snd_soc_codec *codec = &wm8904->codec;
2243 struct wm8904_pdata *pdata = wm8904->pdata;
2244 int ret, i;
2245
2246 if (!pdata) {
2247 snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
2248 ARRAY_SIZE(wm8904_eq_controls));
2249 return;
2250 }
2251
2252 dev_dbg(codec->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
2253
2254 if (pdata->num_drc_cfgs) {
2255 struct snd_kcontrol_new control =
2256 SOC_ENUM_EXT("DRC Mode", wm8904->drc_enum,
2257 wm8904_get_drc_enum, wm8904_put_drc_enum);
2258
2259 /* We need an array of texts for the enum API */
2260 wm8904->drc_texts = kmalloc(sizeof(char *)
2261 * pdata->num_drc_cfgs, GFP_KERNEL);
2262 if (!wm8904->drc_texts) {
2263 dev_err(wm8904->codec.dev,
2264 "Failed to allocate %d DRC config texts\n",
2265 pdata->num_drc_cfgs);
2266 return;
2267 }
2268
2269 for (i = 0; i < pdata->num_drc_cfgs; i++)
2270 wm8904->drc_texts[i] = pdata->drc_cfgs[i].name;
2271
2272 wm8904->drc_enum.max = pdata->num_drc_cfgs;
2273 wm8904->drc_enum.texts = wm8904->drc_texts;
2274
2275 ret = snd_soc_add_controls(&wm8904->codec, &control, 1);
2276 if (ret != 0)
2277 dev_err(wm8904->codec.dev,
2278 "Failed to add DRC mode control: %d\n", ret);
2279
2280 wm8904_set_drc(codec);
2281 }
2282
2283 dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
2284 pdata->num_retune_mobile_cfgs);
2285
2286 if (pdata->num_retune_mobile_cfgs)
2287 wm8904_handle_retune_mobile_pdata(wm8904);
2288 else
2289 snd_soc_add_controls(&wm8904->codec, wm8904_eq_controls,
2290 ARRAY_SIZE(wm8904_eq_controls));
2291}
2292
2293static int wm8904_probe(struct platform_device *pdev)
2294{
2295 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2296 struct snd_soc_codec *codec;
2297 int ret = 0;
2298
2299 if (wm8904_codec == NULL) {
2300 dev_err(&pdev->dev, "Codec device not registered\n");
2301 return -ENODEV;
2302 }
2303
2304 socdev->card->codec = wm8904_codec;
2305 codec = wm8904_codec;
2306
2307 /* register pcms */
2308 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
2309 if (ret < 0) {
2310 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
2311 goto pcm_err;
2312 }
2313
2314 wm8904_handle_pdata(codec->private_data);
2315
2316 wm8904_add_widgets(codec);
2317
2318 return ret;
2319
2320pcm_err:
2321 return ret;
2322}
2323
2324static int wm8904_remove(struct platform_device *pdev)
2325{
2326 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2327
2328 snd_soc_free_pcms(socdev);
2329 snd_soc_dapm_free(socdev);
2330
2331 return 0;
2332}
2333
2334struct snd_soc_codec_device soc_codec_dev_wm8904 = {
2335 .probe = wm8904_probe,
2336 .remove = wm8904_remove,
2337 .suspend = wm8904_suspend,
2338 .resume = wm8904_resume,
2339};
2340EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904);
2341
2342static int wm8904_register(struct wm8904_priv *wm8904,
2343 enum snd_soc_control_type control)
2344{
2345 int ret;
2346 struct snd_soc_codec *codec = &wm8904->codec;
2347 int i;
2348
2349 if (wm8904_codec) {
2350 dev_err(codec->dev, "Another WM8904 is registered\n");
2351 return -EINVAL;
2352 }
2353
2354 mutex_init(&codec->mutex);
2355 INIT_LIST_HEAD(&codec->dapm_widgets);
2356 INIT_LIST_HEAD(&codec->dapm_paths);
2357
2358 codec->private_data = wm8904;
2359 codec->name = "WM8904";
2360 codec->owner = THIS_MODULE;
2361 codec->bias_level = SND_SOC_BIAS_OFF;
2362 codec->set_bias_level = wm8904_set_bias_level;
2363 codec->dai = &wm8904_dai;
2364 codec->num_dai = 1;
2365 codec->reg_cache_size = WM8904_MAX_REGISTER;
2366 codec->reg_cache = &wm8904->reg_cache;
2367 codec->volatile_register = wm8904_volatile_register;
2368
2369 memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
2370
2371 ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
2372 if (ret != 0) {
2373 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
2374 goto err;
2375 }
2376
2377 for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
2378 wm8904->supplies[i].supply = wm8904_supply_names[i];
2379
2380 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies),
2381 wm8904->supplies);
2382 if (ret != 0) {
2383 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
2384 goto err;
2385 }
2386
2387 ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies),
2388 wm8904->supplies);
2389 if (ret != 0) {
2390 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
2391 goto err_get;
2392 }
2393
2394 ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID);
2395 if (ret < 0) {
2396 dev_err(codec->dev, "Failed to read ID register\n");
2397 goto err_enable;
2398 }
2399 if (ret != wm8904_reg[WM8904_SW_RESET_AND_ID]) {
2400 dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret);
2401 ret = -EINVAL;
2402 goto err_enable;
2403 }
2404
2405 ret = snd_soc_read(codec, WM8904_REVISION);
2406 if (ret < 0) {
2407 dev_err(codec->dev, "Failed to read device revision: %d\n",
2408 ret);
2409 goto err_enable;
2410 }
2411 dev_info(codec->dev, "revision %c\n", ret + 'A');
2412
2413 ret = wm8904_reset(codec);
2414 if (ret < 0) {
2415 dev_err(codec->dev, "Failed to issue reset\n");
2416 goto err_enable;
2417 }
2418
2419 wm8904_dai.dev = codec->dev;
2420
2421 /* Change some default settings - latch VU and enable ZC */
2422 wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU;
2423 wm8904->reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU;
2424 wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU;
2425 wm8904->reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU;
2426 wm8904->reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU |
2427 WM8904_HPOUTLZC;
2428 wm8904->reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU |
2429 WM8904_HPOUTRZC;
2430 wm8904->reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU |
2431 WM8904_LINEOUTLZC;
2432 wm8904->reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU |
2433 WM8904_LINEOUTRZC;
2434 wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
2435
2436 /* Set Class W by default - this will be managed by the Class
2437 * G widget at runtime where bypass paths are available.
2438 */
2439 wm8904->reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR;
2440
2441 /* Use normal bias source */
2442 wm8904->reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL;
2443
2444 wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
2445
2446 /* Bias level configuration will have done an extra enable */
2447 regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
2448
2449 wm8904_codec = codec;
2450
2451 ret = snd_soc_register_codec(codec);
2452 if (ret != 0) {
2453 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
2454 return ret;
2455 }
2456
2457 ret = snd_soc_register_dai(&wm8904_dai);
2458 if (ret != 0) {
2459 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
2460 snd_soc_unregister_codec(codec);
2461 return ret;
2462 }
2463
2464 return 0;
2465
2466err_enable:
2467 regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
2468err_get:
2469 regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
2470err:
2471 kfree(wm8904);
2472 return ret;
2473}
2474
2475static void wm8904_unregister(struct wm8904_priv *wm8904)
2476{
2477 wm8904_set_bias_level(&wm8904->codec, SND_SOC_BIAS_OFF);
2478 regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
2479 snd_soc_unregister_dai(&wm8904_dai);
2480 snd_soc_unregister_codec(&wm8904->codec);
2481 kfree(wm8904);
2482 wm8904_codec = NULL;
2483}
2484
2485#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
2486static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
2487 const struct i2c_device_id *id)
2488{
2489 struct wm8904_priv *wm8904;
2490 struct snd_soc_codec *codec;
2491
2492 wm8904 = kzalloc(sizeof(struct wm8904_priv), GFP_KERNEL);
2493 if (wm8904 == NULL)
2494 return -ENOMEM;
2495
2496 codec = &wm8904->codec;
2497 codec->hw_write = (hw_write_t)i2c_master_send;
2498
2499 i2c_set_clientdata(i2c, wm8904);
2500 codec->control_data = i2c;
2501 wm8904->pdata = i2c->dev.platform_data;
2502
2503 codec->dev = &i2c->dev;
2504
2505 return wm8904_register(wm8904, SND_SOC_I2C);
2506}
2507
2508static __devexit int wm8904_i2c_remove(struct i2c_client *client)
2509{
2510 struct wm8904_priv *wm8904 = i2c_get_clientdata(client);
2511 wm8904_unregister(wm8904);
2512 return 0;
2513}
2514
2515static const struct i2c_device_id wm8904_i2c_id[] = {
2516 { "wm8904", 0 },
2517 { }
2518};
2519MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id);
2520
2521static struct i2c_driver wm8904_i2c_driver = {
2522 .driver = {
2523 .name = "WM8904",
2524 .owner = THIS_MODULE,
2525 },
2526 .probe = wm8904_i2c_probe,
2527 .remove = __devexit_p(wm8904_i2c_remove),
2528 .id_table = wm8904_i2c_id,
2529};
2530#endif
2531
2532static int __init wm8904_modinit(void)
2533{
2534 int ret;
2535#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
2536 ret = i2c_add_driver(&wm8904_i2c_driver);
2537 if (ret != 0) {
2538 printk(KERN_ERR "Failed to register WM8904 I2C driver: %d\n",
2539 ret);
2540 }
2541#endif
2542 return 0;
2543}
2544module_init(wm8904_modinit);
2545
2546static void __exit wm8904_exit(void)
2547{
2548#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
2549 i2c_del_driver(&wm8904_i2c_driver);
2550#endif
2551}
2552module_exit(wm8904_exit);
2553
2554MODULE_DESCRIPTION("ASoC WM8904 driver");
2555MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2556MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8904.h b/sound/soc/codecs/wm8904.h
new file mode 100644
index 00000000000..b68886df34e
--- /dev/null
+++ b/sound/soc/codecs/wm8904.h
@@ -0,0 +1,1681 @@
1/*
2 * wm8904.h -- WM8904 ASoC driver
3 *
4 * Copyright 2009 Wolfson Microelectronics, plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef _WM8904_H
14#define _WM8904_H
15
16#define WM8904_CLK_MCLK 1
17#define WM8904_CLK_FLL 2
18
19#define WM8904_FLL_MCLK 1
20#define WM8904_FLL_BCLK 2
21#define WM8904_FLL_LRCLK 3
22#define WM8904_FLL_FREE_RUNNING 4
23
24extern struct snd_soc_dai wm8904_dai;
25extern struct snd_soc_codec_device soc_codec_dev_wm8904;
26
27/*
28 * Register values.
29 */
30#define WM8904_SW_RESET_AND_ID 0x00
31#define WM8904_REVISION 0x01
32#define WM8904_BIAS_CONTROL_0 0x04
33#define WM8904_VMID_CONTROL_0 0x05
34#define WM8904_MIC_BIAS_CONTROL_0 0x06
35#define WM8904_MIC_BIAS_CONTROL_1 0x07
36#define WM8904_ANALOGUE_DAC_0 0x08
37#define WM8904_MIC_FILTER_CONTROL 0x09
38#define WM8904_ANALOGUE_ADC_0 0x0A
39#define WM8904_POWER_MANAGEMENT_0 0x0C
40#define WM8904_POWER_MANAGEMENT_2 0x0E
41#define WM8904_POWER_MANAGEMENT_3 0x0F
42#define WM8904_POWER_MANAGEMENT_6 0x12
43#define WM8904_CLOCK_RATES_0 0x14
44#define WM8904_CLOCK_RATES_1 0x15
45#define WM8904_CLOCK_RATES_2 0x16
46#define WM8904_AUDIO_INTERFACE_0 0x18
47#define WM8904_AUDIO_INTERFACE_1 0x19
48#define WM8904_AUDIO_INTERFACE_2 0x1A
49#define WM8904_AUDIO_INTERFACE_3 0x1B
50#define WM8904_DAC_DIGITAL_VOLUME_LEFT 0x1E
51#define WM8904_DAC_DIGITAL_VOLUME_RIGHT 0x1F
52#define WM8904_DAC_DIGITAL_0 0x20
53#define WM8904_DAC_DIGITAL_1 0x21
54#define WM8904_ADC_DIGITAL_VOLUME_LEFT 0x24
55#define WM8904_ADC_DIGITAL_VOLUME_RIGHT 0x25
56#define WM8904_ADC_DIGITAL_0 0x26
57#define WM8904_DIGITAL_MICROPHONE_0 0x27
58#define WM8904_DRC_0 0x28
59#define WM8904_DRC_1 0x29
60#define WM8904_DRC_2 0x2A
61#define WM8904_DRC_3 0x2B
62#define WM8904_ANALOGUE_LEFT_INPUT_0 0x2C
63#define WM8904_ANALOGUE_RIGHT_INPUT_0 0x2D
64#define WM8904_ANALOGUE_LEFT_INPUT_1 0x2E
65#define WM8904_ANALOGUE_RIGHT_INPUT_1 0x2F
66#define WM8904_ANALOGUE_OUT1_LEFT 0x39
67#define WM8904_ANALOGUE_OUT1_RIGHT 0x3A
68#define WM8904_ANALOGUE_OUT2_LEFT 0x3B
69#define WM8904_ANALOGUE_OUT2_RIGHT 0x3C
70#define WM8904_ANALOGUE_OUT12_ZC 0x3D
71#define WM8904_DC_SERVO_0 0x43
72#define WM8904_DC_SERVO_1 0x44
73#define WM8904_DC_SERVO_2 0x45
74#define WM8904_DC_SERVO_4 0x47
75#define WM8904_DC_SERVO_5 0x48
76#define WM8904_DC_SERVO_6 0x49
77#define WM8904_DC_SERVO_7 0x4A
78#define WM8904_DC_SERVO_8 0x4B
79#define WM8904_DC_SERVO_9 0x4C
80#define WM8904_DC_SERVO_READBACK_0 0x4D
81#define WM8904_ANALOGUE_HP_0 0x5A
82#define WM8904_ANALOGUE_LINEOUT_0 0x5E
83#define WM8904_CHARGE_PUMP_0 0x62
84#define WM8904_CLASS_W_0 0x68
85#define WM8904_WRITE_SEQUENCER_0 0x6C
86#define WM8904_WRITE_SEQUENCER_1 0x6D
87#define WM8904_WRITE_SEQUENCER_2 0x6E
88#define WM8904_WRITE_SEQUENCER_3 0x6F
89#define WM8904_WRITE_SEQUENCER_4 0x70
90#define WM8904_FLL_CONTROL_1 0x74
91#define WM8904_FLL_CONTROL_2 0x75
92#define WM8904_FLL_CONTROL_3 0x76
93#define WM8904_FLL_CONTROL_4 0x77
94#define WM8904_FLL_CONTROL_5 0x78
95#define WM8904_GPIO_CONTROL_1 0x79
96#define WM8904_GPIO_CONTROL_2 0x7A
97#define WM8904_GPIO_CONTROL_3 0x7B
98#define WM8904_GPIO_CONTROL_4 0x7C
99#define WM8904_DIGITAL_PULLS 0x7E
100#define WM8904_INTERRUPT_STATUS 0x7F
101#define WM8904_INTERRUPT_STATUS_MASK 0x80
102#define WM8904_INTERRUPT_POLARITY 0x81
103#define WM8904_INTERRUPT_DEBOUNCE 0x82
104#define WM8904_EQ1 0x86
105#define WM8904_EQ2 0x87
106#define WM8904_EQ3 0x88
107#define WM8904_EQ4 0x89
108#define WM8904_EQ5 0x8A
109#define WM8904_EQ6 0x8B
110#define WM8904_EQ7 0x8C
111#define WM8904_EQ8 0x8D
112#define WM8904_EQ9 0x8E
113#define WM8904_EQ10 0x8F
114#define WM8904_EQ11 0x90
115#define WM8904_EQ12 0x91
116#define WM8904_EQ13 0x92
117#define WM8904_EQ14 0x93
118#define WM8904_EQ15 0x94
119#define WM8904_EQ16 0x95
120#define WM8904_EQ17 0x96
121#define WM8904_EQ18 0x97
122#define WM8904_EQ19 0x98
123#define WM8904_EQ20 0x99
124#define WM8904_EQ21 0x9A
125#define WM8904_EQ22 0x9B
126#define WM8904_EQ23 0x9C
127#define WM8904_EQ24 0x9D
128#define WM8904_CONTROL_INTERFACE_TEST_1 0xA1
129#define WM8904_ANALOGUE_OUTPUT_BIAS_0 0xCC
130#define WM8904_FLL_NCO_TEST_0 0xF7
131#define WM8904_FLL_NCO_TEST_1 0xF8
132
133#define WM8904_REGISTER_COUNT 101
134#define WM8904_MAX_REGISTER 0xF8
135
136/*
137 * Field Definitions.
138 */
139
140/*
141 * R0 (0x00) - SW Reset and ID
142 */
143#define WM8904_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */
144#define WM8904_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */
145#define WM8904_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */
146
147/*
148 * R1 (0x01) - Revision
149 */
150#define WM8904_REVISION_MASK 0x000F /* REVISION - [3:0] */
151#define WM8904_REVISION_SHIFT 0 /* REVISION - [3:0] */
152#define WM8904_REVISION_WIDTH 16 /* REVISION - [3:0] */
153
154/*
155 * R4 (0x04) - Bias Control 0
156 */
157#define WM8904_POBCTRL 0x0010 /* POBCTRL */
158#define WM8904_POBCTRL_MASK 0x0010 /* POBCTRL */
159#define WM8904_POBCTRL_SHIFT 4 /* POBCTRL */
160#define WM8904_POBCTRL_WIDTH 1 /* POBCTRL */
161#define WM8904_ISEL_MASK 0x000C /* ISEL - [3:2] */
162#define WM8904_ISEL_SHIFT 2 /* ISEL - [3:2] */
163#define WM8904_ISEL_WIDTH 2 /* ISEL - [3:2] */
164#define WM8904_STARTUP_BIAS_ENA 0x0002 /* STARTUP_BIAS_ENA */
165#define WM8904_STARTUP_BIAS_ENA_MASK 0x0002 /* STARTUP_BIAS_ENA */
166#define WM8904_STARTUP_BIAS_ENA_SHIFT 1 /* STARTUP_BIAS_ENA */
167#define WM8904_STARTUP_BIAS_ENA_WIDTH 1 /* STARTUP_BIAS_ENA */
168#define WM8904_BIAS_ENA 0x0001 /* BIAS_ENA */
169#define WM8904_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */
170#define WM8904_BIAS_ENA_SHIFT 0 /* BIAS_ENA */
171#define WM8904_BIAS_ENA_WIDTH 1 /* BIAS_ENA */
172
173/*
174 * R5 (0x05) - VMID Control 0
175 */
176#define WM8904_VMID_BUF_ENA 0x0040 /* VMID_BUF_ENA */
177#define WM8904_VMID_BUF_ENA_MASK 0x0040 /* VMID_BUF_ENA */
178#define WM8904_VMID_BUF_ENA_SHIFT 6 /* VMID_BUF_ENA */
179#define WM8904_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */
180#define WM8904_VMID_RES_MASK 0x0006 /* VMID_RES - [2:1] */
181#define WM8904_VMID_RES_SHIFT 1 /* VMID_RES - [2:1] */
182#define WM8904_VMID_RES_WIDTH 2 /* VMID_RES - [2:1] */
183#define WM8904_VMID_ENA 0x0001 /* VMID_ENA */
184#define WM8904_VMID_ENA_MASK 0x0001 /* VMID_ENA */
185#define WM8904_VMID_ENA_SHIFT 0 /* VMID_ENA */
186#define WM8904_VMID_ENA_WIDTH 1 /* VMID_ENA */
187
188/*
189 * R6 (0x06) - Mic Bias Control 0
190 */
191#define WM8904_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */
192#define WM8904_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */
193#define WM8904_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */
194#define WM8904_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */
195#define WM8904_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */
196#define WM8904_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */
197#define WM8904_MICDET_ENA 0x0002 /* MICDET_ENA */
198#define WM8904_MICDET_ENA_MASK 0x0002 /* MICDET_ENA */
199#define WM8904_MICDET_ENA_SHIFT 1 /* MICDET_ENA */
200#define WM8904_MICDET_ENA_WIDTH 1 /* MICDET_ENA */
201#define WM8904_MICBIAS_ENA 0x0001 /* MICBIAS_ENA */
202#define WM8904_MICBIAS_ENA_MASK 0x0001 /* MICBIAS_ENA */
203#define WM8904_MICBIAS_ENA_SHIFT 0 /* MICBIAS_ENA */
204#define WM8904_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */
205
206/*
207 * R7 (0x07) - Mic Bias Control 1
208 */
209#define WM8904_MIC_DET_FILTER_ENA 0x8000 /* MIC_DET_FILTER_ENA */
210#define WM8904_MIC_DET_FILTER_ENA_MASK 0x8000 /* MIC_DET_FILTER_ENA */
211#define WM8904_MIC_DET_FILTER_ENA_SHIFT 15 /* MIC_DET_FILTER_ENA */
212#define WM8904_MIC_DET_FILTER_ENA_WIDTH 1 /* MIC_DET_FILTER_ENA */
213#define WM8904_MIC_SHORT_FILTER_ENA 0x4000 /* MIC_SHORT_FILTER_ENA */
214#define WM8904_MIC_SHORT_FILTER_ENA_MASK 0x4000 /* MIC_SHORT_FILTER_ENA */
215#define WM8904_MIC_SHORT_FILTER_ENA_SHIFT 14 /* MIC_SHORT_FILTER_ENA */
216#define WM8904_MIC_SHORT_FILTER_ENA_WIDTH 1 /* MIC_SHORT_FILTER_ENA */
217#define WM8904_MICBIAS_SEL_MASK 0x0007 /* MICBIAS_SEL - [2:0] */
218#define WM8904_MICBIAS_SEL_SHIFT 0 /* MICBIAS_SEL - [2:0] */
219#define WM8904_MICBIAS_SEL_WIDTH 3 /* MICBIAS_SEL - [2:0] */
220
221/*
222 * R8 (0x08) - Analogue DAC 0
223 */
224#define WM8904_DAC_BIAS_SEL_MASK 0x0018 /* DAC_BIAS_SEL - [4:3] */
225#define WM8904_DAC_BIAS_SEL_SHIFT 3 /* DAC_BIAS_SEL - [4:3] */
226#define WM8904_DAC_BIAS_SEL_WIDTH 2 /* DAC_BIAS_SEL - [4:3] */
227#define WM8904_DAC_VMID_BIAS_SEL_MASK 0x0006 /* DAC_VMID_BIAS_SEL - [2:1] */
228#define WM8904_DAC_VMID_BIAS_SEL_SHIFT 1 /* DAC_VMID_BIAS_SEL - [2:1] */
229#define WM8904_DAC_VMID_BIAS_SEL_WIDTH 2 /* DAC_VMID_BIAS_SEL - [2:1] */
230
231/*
232 * R9 (0x09) - mic Filter Control
233 */
234#define WM8904_MIC_DET_SET_THRESHOLD_MASK 0xF000 /* MIC_DET_SET_THRESHOLD - [15:12] */
235#define WM8904_MIC_DET_SET_THRESHOLD_SHIFT 12 /* MIC_DET_SET_THRESHOLD - [15:12] */
236#define WM8904_MIC_DET_SET_THRESHOLD_WIDTH 4 /* MIC_DET_SET_THRESHOLD - [15:12] */
237#define WM8904_MIC_DET_RESET_THRESHOLD_MASK 0x0F00 /* MIC_DET_RESET_THRESHOLD - [11:8] */
238#define WM8904_MIC_DET_RESET_THRESHOLD_SHIFT 8 /* MIC_DET_RESET_THRESHOLD - [11:8] */
239#define WM8904_MIC_DET_RESET_THRESHOLD_WIDTH 4 /* MIC_DET_RESET_THRESHOLD - [11:8] */
240#define WM8904_MIC_SHORT_SET_THRESHOLD_MASK 0x00F0 /* MIC_SHORT_SET_THRESHOLD - [7:4] */
241#define WM8904_MIC_SHORT_SET_THRESHOLD_SHIFT 4 /* MIC_SHORT_SET_THRESHOLD - [7:4] */
242#define WM8904_MIC_SHORT_SET_THRESHOLD_WIDTH 4 /* MIC_SHORT_SET_THRESHOLD - [7:4] */
243#define WM8904_MIC_SHORT_RESET_THRESHOLD_MASK 0x000F /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
244#define WM8904_MIC_SHORT_RESET_THRESHOLD_SHIFT 0 /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
245#define WM8904_MIC_SHORT_RESET_THRESHOLD_WIDTH 4 /* MIC_SHORT_RESET_THRESHOLD - [3:0] */
246
247/*
248 * R10 (0x0A) - Analogue ADC 0
249 */
250#define WM8904_ADC_OSR128 0x0001 /* ADC_OSR128 */
251#define WM8904_ADC_OSR128_MASK 0x0001 /* ADC_OSR128 */
252#define WM8904_ADC_OSR128_SHIFT 0 /* ADC_OSR128 */
253#define WM8904_ADC_OSR128_WIDTH 1 /* ADC_OSR128 */
254
255/*
256 * R12 (0x0C) - Power Management 0
257 */
258#define WM8904_INL_ENA 0x0002 /* INL_ENA */
259#define WM8904_INL_ENA_MASK 0x0002 /* INL_ENA */
260#define WM8904_INL_ENA_SHIFT 1 /* INL_ENA */
261#define WM8904_INL_ENA_WIDTH 1 /* INL_ENA */
262#define WM8904_INR_ENA 0x0001 /* INR_ENA */
263#define WM8904_INR_ENA_MASK 0x0001 /* INR_ENA */
264#define WM8904_INR_ENA_SHIFT 0 /* INR_ENA */
265#define WM8904_INR_ENA_WIDTH 1 /* INR_ENA */
266
267/*
268 * R14 (0x0E) - Power Management 2
269 */
270#define WM8904_HPL_PGA_ENA 0x0002 /* HPL_PGA_ENA */
271#define WM8904_HPL_PGA_ENA_MASK 0x0002 /* HPL_PGA_ENA */
272#define WM8904_HPL_PGA_ENA_SHIFT 1 /* HPL_PGA_ENA */
273#define WM8904_HPL_PGA_ENA_WIDTH 1 /* HPL_PGA_ENA */
274#define WM8904_HPR_PGA_ENA 0x0001 /* HPR_PGA_ENA */
275#define WM8904_HPR_PGA_ENA_MASK 0x0001 /* HPR_PGA_ENA */
276#define WM8904_HPR_PGA_ENA_SHIFT 0 /* HPR_PGA_ENA */
277#define WM8904_HPR_PGA_ENA_WIDTH 1 /* HPR_PGA_ENA */
278
279/*
280 * R15 (0x0F) - Power Management 3
281 */
282#define WM8904_LINEOUTL_PGA_ENA 0x0002 /* LINEOUTL_PGA_ENA */
283#define WM8904_LINEOUTL_PGA_ENA_MASK 0x0002 /* LINEOUTL_PGA_ENA */
284#define WM8904_LINEOUTL_PGA_ENA_SHIFT 1 /* LINEOUTL_PGA_ENA */
285#define WM8904_LINEOUTL_PGA_ENA_WIDTH 1 /* LINEOUTL_PGA_ENA */
286#define WM8904_LINEOUTR_PGA_ENA 0x0001 /* LINEOUTR_PGA_ENA */
287#define WM8904_LINEOUTR_PGA_ENA_MASK 0x0001 /* LINEOUTR_PGA_ENA */
288#define WM8904_LINEOUTR_PGA_ENA_SHIFT 0 /* LINEOUTR_PGA_ENA */
289#define WM8904_LINEOUTR_PGA_ENA_WIDTH 1 /* LINEOUTR_PGA_ENA */
290
291/*
292 * R18 (0x12) - Power Management 6
293 */
294#define WM8904_DACL_ENA 0x0008 /* DACL_ENA */
295#define WM8904_DACL_ENA_MASK 0x0008 /* DACL_ENA */
296#define WM8904_DACL_ENA_SHIFT 3 /* DACL_ENA */
297#define WM8904_DACL_ENA_WIDTH 1 /* DACL_ENA */
298#define WM8904_DACR_ENA 0x0004 /* DACR_ENA */
299#define WM8904_DACR_ENA_MASK 0x0004 /* DACR_ENA */
300#define WM8904_DACR_ENA_SHIFT 2 /* DACR_ENA */
301#define WM8904_DACR_ENA_WIDTH 1 /* DACR_ENA */
302#define WM8904_ADCL_ENA 0x0002 /* ADCL_ENA */
303#define WM8904_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */
304#define WM8904_ADCL_ENA_SHIFT 1 /* ADCL_ENA */
305#define WM8904_ADCL_ENA_WIDTH 1 /* ADCL_ENA */
306#define WM8904_ADCR_ENA 0x0001 /* ADCR_ENA */
307#define WM8904_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */
308#define WM8904_ADCR_ENA_SHIFT 0 /* ADCR_ENA */
309#define WM8904_ADCR_ENA_WIDTH 1 /* ADCR_ENA */
310
311/*
312 * R20 (0x14) - Clock Rates 0
313 */
314#define WM8904_TOCLK_RATE_DIV16 0x4000 /* TOCLK_RATE_DIV16 */
315#define WM8904_TOCLK_RATE_DIV16_MASK 0x4000 /* TOCLK_RATE_DIV16 */
316#define WM8904_TOCLK_RATE_DIV16_SHIFT 14 /* TOCLK_RATE_DIV16 */
317#define WM8904_TOCLK_RATE_DIV16_WIDTH 1 /* TOCLK_RATE_DIV16 */
318#define WM8904_TOCLK_RATE_X4 0x2000 /* TOCLK_RATE_X4 */
319#define WM8904_TOCLK_RATE_X4_MASK 0x2000 /* TOCLK_RATE_X4 */
320#define WM8904_TOCLK_RATE_X4_SHIFT 13 /* TOCLK_RATE_X4 */
321#define WM8904_TOCLK_RATE_X4_WIDTH 1 /* TOCLK_RATE_X4 */
322#define WM8904_SR_MODE 0x1000 /* SR_MODE */
323#define WM8904_SR_MODE_MASK 0x1000 /* SR_MODE */
324#define WM8904_SR_MODE_SHIFT 12 /* SR_MODE */
325#define WM8904_SR_MODE_WIDTH 1 /* SR_MODE */
326#define WM8904_MCLK_DIV 0x0001 /* MCLK_DIV */
327#define WM8904_MCLK_DIV_MASK 0x0001 /* MCLK_DIV */
328#define WM8904_MCLK_DIV_SHIFT 0 /* MCLK_DIV */
329#define WM8904_MCLK_DIV_WIDTH 1 /* MCLK_DIV */
330
331/*
332 * R21 (0x15) - Clock Rates 1
333 */
334#define WM8904_CLK_SYS_RATE_MASK 0x3C00 /* CLK_SYS_RATE - [13:10] */
335#define WM8904_CLK_SYS_RATE_SHIFT 10 /* CLK_SYS_RATE - [13:10] */
336#define WM8904_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [13:10] */
337#define WM8904_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */
338#define WM8904_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */
339#define WM8904_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */
340
341/*
342 * R22 (0x16) - Clock Rates 2
343 */
344#define WM8904_MCLK_INV 0x8000 /* MCLK_INV */
345#define WM8904_MCLK_INV_MASK 0x8000 /* MCLK_INV */
346#define WM8904_MCLK_INV_SHIFT 15 /* MCLK_INV */
347#define WM8904_MCLK_INV_WIDTH 1 /* MCLK_INV */
348#define WM8904_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */
349#define WM8904_SYSCLK_SRC_MASK 0x4000 /* SYSCLK_SRC */
350#define WM8904_SYSCLK_SRC_SHIFT 14 /* SYSCLK_SRC */
351#define WM8904_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */
352#define WM8904_TOCLK_RATE 0x1000 /* TOCLK_RATE */
353#define WM8904_TOCLK_RATE_MASK 0x1000 /* TOCLK_RATE */
354#define WM8904_TOCLK_RATE_SHIFT 12 /* TOCLK_RATE */
355#define WM8904_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */
356#define WM8904_OPCLK_ENA 0x0008 /* OPCLK_ENA */
357#define WM8904_OPCLK_ENA_MASK 0x0008 /* OPCLK_ENA */
358#define WM8904_OPCLK_ENA_SHIFT 3 /* OPCLK_ENA */
359#define WM8904_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */
360#define WM8904_CLK_SYS_ENA 0x0004 /* CLK_SYS_ENA */
361#define WM8904_CLK_SYS_ENA_MASK 0x0004 /* CLK_SYS_ENA */
362#define WM8904_CLK_SYS_ENA_SHIFT 2 /* CLK_SYS_ENA */
363#define WM8904_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */
364#define WM8904_CLK_DSP_ENA 0x0002 /* CLK_DSP_ENA */
365#define WM8904_CLK_DSP_ENA_MASK 0x0002 /* CLK_DSP_ENA */
366#define WM8904_CLK_DSP_ENA_SHIFT 1 /* CLK_DSP_ENA */
367#define WM8904_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */
368#define WM8904_TOCLK_ENA 0x0001 /* TOCLK_ENA */
369#define WM8904_TOCLK_ENA_MASK 0x0001 /* TOCLK_ENA */
370#define WM8904_TOCLK_ENA_SHIFT 0 /* TOCLK_ENA */
371#define WM8904_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */
372
373/*
374 * R24 (0x18) - Audio Interface 0
375 */
376#define WM8904_DACL_DATINV 0x1000 /* DACL_DATINV */
377#define WM8904_DACL_DATINV_MASK 0x1000 /* DACL_DATINV */
378#define WM8904_DACL_DATINV_SHIFT 12 /* DACL_DATINV */
379#define WM8904_DACL_DATINV_WIDTH 1 /* DACL_DATINV */
380#define WM8904_DACR_DATINV 0x0800 /* DACR_DATINV */
381#define WM8904_DACR_DATINV_MASK 0x0800 /* DACR_DATINV */
382#define WM8904_DACR_DATINV_SHIFT 11 /* DACR_DATINV */
383#define WM8904_DACR_DATINV_WIDTH 1 /* DACR_DATINV */
384#define WM8904_DAC_BOOST_MASK 0x0600 /* DAC_BOOST - [10:9] */
385#define WM8904_DAC_BOOST_SHIFT 9 /* DAC_BOOST - [10:9] */
386#define WM8904_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [10:9] */
387#define WM8904_LOOPBACK 0x0100 /* LOOPBACK */
388#define WM8904_LOOPBACK_MASK 0x0100 /* LOOPBACK */
389#define WM8904_LOOPBACK_SHIFT 8 /* LOOPBACK */
390#define WM8904_LOOPBACK_WIDTH 1 /* LOOPBACK */
391#define WM8904_AIFADCL_SRC 0x0080 /* AIFADCL_SRC */
392#define WM8904_AIFADCL_SRC_MASK 0x0080 /* AIFADCL_SRC */
393#define WM8904_AIFADCL_SRC_SHIFT 7 /* AIFADCL_SRC */
394#define WM8904_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */
395#define WM8904_AIFADCR_SRC 0x0040 /* AIFADCR_SRC */
396#define WM8904_AIFADCR_SRC_MASK 0x0040 /* AIFADCR_SRC */
397#define WM8904_AIFADCR_SRC_SHIFT 6 /* AIFADCR_SRC */
398#define WM8904_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */
399#define WM8904_AIFDACL_SRC 0x0020 /* AIFDACL_SRC */
400#define WM8904_AIFDACL_SRC_MASK 0x0020 /* AIFDACL_SRC */
401#define WM8904_AIFDACL_SRC_SHIFT 5 /* AIFDACL_SRC */
402#define WM8904_AIFDACL_SRC_WIDTH 1 /* AIFDACL_SRC */
403#define WM8904_AIFDACR_SRC 0x0010 /* AIFDACR_SRC */
404#define WM8904_AIFDACR_SRC_MASK 0x0010 /* AIFDACR_SRC */
405#define WM8904_AIFDACR_SRC_SHIFT 4 /* AIFDACR_SRC */
406#define WM8904_AIFDACR_SRC_WIDTH 1 /* AIFDACR_SRC */
407#define WM8904_ADC_COMP 0x0008 /* ADC_COMP */
408#define WM8904_ADC_COMP_MASK 0x0008 /* ADC_COMP */
409#define WM8904_ADC_COMP_SHIFT 3 /* ADC_COMP */
410#define WM8904_ADC_COMP_WIDTH 1 /* ADC_COMP */
411#define WM8904_ADC_COMPMODE 0x0004 /* ADC_COMPMODE */
412#define WM8904_ADC_COMPMODE_MASK 0x0004 /* ADC_COMPMODE */
413#define WM8904_ADC_COMPMODE_SHIFT 2 /* ADC_COMPMODE */
414#define WM8904_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */
415#define WM8904_DAC_COMP 0x0002 /* DAC_COMP */
416#define WM8904_DAC_COMP_MASK 0x0002 /* DAC_COMP */
417#define WM8904_DAC_COMP_SHIFT 1 /* DAC_COMP */
418#define WM8904_DAC_COMP_WIDTH 1 /* DAC_COMP */
419#define WM8904_DAC_COMPMODE 0x0001 /* DAC_COMPMODE */
420#define WM8904_DAC_COMPMODE_MASK 0x0001 /* DAC_COMPMODE */
421#define WM8904_DAC_COMPMODE_SHIFT 0 /* DAC_COMPMODE */
422#define WM8904_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */
423
424/*
425 * R25 (0x19) - Audio Interface 1
426 */
427#define WM8904_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */
428#define WM8904_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */
429#define WM8904_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */
430#define WM8904_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */
431#define WM8904_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */
432#define WM8904_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */
433#define WM8904_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */
434#define WM8904_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */
435#define WM8904_AIFADC_TDM 0x0800 /* AIFADC_TDM */
436#define WM8904_AIFADC_TDM_MASK 0x0800 /* AIFADC_TDM */
437#define WM8904_AIFADC_TDM_SHIFT 11 /* AIFADC_TDM */
438#define WM8904_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */
439#define WM8904_AIFADC_TDM_CHAN 0x0400 /* AIFADC_TDM_CHAN */
440#define WM8904_AIFADC_TDM_CHAN_MASK 0x0400 /* AIFADC_TDM_CHAN */
441#define WM8904_AIFADC_TDM_CHAN_SHIFT 10 /* AIFADC_TDM_CHAN */
442#define WM8904_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */
443#define WM8904_AIF_TRIS 0x0100 /* AIF_TRIS */
444#define WM8904_AIF_TRIS_MASK 0x0100 /* AIF_TRIS */
445#define WM8904_AIF_TRIS_SHIFT 8 /* AIF_TRIS */
446#define WM8904_AIF_TRIS_WIDTH 1 /* AIF_TRIS */
447#define WM8904_AIF_BCLK_INV 0x0080 /* AIF_BCLK_INV */
448#define WM8904_AIF_BCLK_INV_MASK 0x0080 /* AIF_BCLK_INV */
449#define WM8904_AIF_BCLK_INV_SHIFT 7 /* AIF_BCLK_INV */
450#define WM8904_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */
451#define WM8904_BCLK_DIR 0x0040 /* BCLK_DIR */
452#define WM8904_BCLK_DIR_MASK 0x0040 /* BCLK_DIR */
453#define WM8904_BCLK_DIR_SHIFT 6 /* BCLK_DIR */
454#define WM8904_BCLK_DIR_WIDTH 1 /* BCLK_DIR */
455#define WM8904_AIF_LRCLK_INV 0x0010 /* AIF_LRCLK_INV */
456#define WM8904_AIF_LRCLK_INV_MASK 0x0010 /* AIF_LRCLK_INV */
457#define WM8904_AIF_LRCLK_INV_SHIFT 4 /* AIF_LRCLK_INV */
458#define WM8904_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */
459#define WM8904_AIF_WL_MASK 0x000C /* AIF_WL - [3:2] */
460#define WM8904_AIF_WL_SHIFT 2 /* AIF_WL - [3:2] */
461#define WM8904_AIF_WL_WIDTH 2 /* AIF_WL - [3:2] */
462#define WM8904_AIF_FMT_MASK 0x0003 /* AIF_FMT - [1:0] */
463#define WM8904_AIF_FMT_SHIFT 0 /* AIF_FMT - [1:0] */
464#define WM8904_AIF_FMT_WIDTH 2 /* AIF_FMT - [1:0] */
465
466/*
467 * R26 (0x1A) - Audio Interface 2
468 */
469#define WM8904_OPCLK_DIV_MASK 0x0F00 /* OPCLK_DIV - [11:8] */
470#define WM8904_OPCLK_DIV_SHIFT 8 /* OPCLK_DIV - [11:8] */
471#define WM8904_OPCLK_DIV_WIDTH 4 /* OPCLK_DIV - [11:8] */
472#define WM8904_BCLK_DIV_MASK 0x001F /* BCLK_DIV - [4:0] */
473#define WM8904_BCLK_DIV_SHIFT 0 /* BCLK_DIV - [4:0] */
474#define WM8904_BCLK_DIV_WIDTH 5 /* BCLK_DIV - [4:0] */
475
476/*
477 * R27 (0x1B) - Audio Interface 3
478 */
479#define WM8904_LRCLK_DIR 0x0800 /* LRCLK_DIR */
480#define WM8904_LRCLK_DIR_MASK 0x0800 /* LRCLK_DIR */
481#define WM8904_LRCLK_DIR_SHIFT 11 /* LRCLK_DIR */
482#define WM8904_LRCLK_DIR_WIDTH 1 /* LRCLK_DIR */
483#define WM8904_LRCLK_RATE_MASK 0x07FF /* LRCLK_RATE - [10:0] */
484#define WM8904_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [10:0] */
485#define WM8904_LRCLK_RATE_WIDTH 11 /* LRCLK_RATE - [10:0] */
486
487/*
488 * R30 (0x1E) - DAC Digital Volume Left
489 */
490#define WM8904_DAC_VU 0x0100 /* DAC_VU */
491#define WM8904_DAC_VU_MASK 0x0100 /* DAC_VU */
492#define WM8904_DAC_VU_SHIFT 8 /* DAC_VU */
493#define WM8904_DAC_VU_WIDTH 1 /* DAC_VU */
494#define WM8904_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
495#define WM8904_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */
496#define WM8904_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */
497
498/*
499 * R31 (0x1F) - DAC Digital Volume Right
500 */
501#define WM8904_DAC_VU 0x0100 /* DAC_VU */
502#define WM8904_DAC_VU_MASK 0x0100 /* DAC_VU */
503#define WM8904_DAC_VU_SHIFT 8 /* DAC_VU */
504#define WM8904_DAC_VU_WIDTH 1 /* DAC_VU */
505#define WM8904_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
506#define WM8904_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */
507#define WM8904_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */
508
509/*
510 * R32 (0x20) - DAC Digital 0
511 */
512#define WM8904_ADCL_DAC_SVOL_MASK 0x0F00 /* ADCL_DAC_SVOL - [11:8] */
513#define WM8904_ADCL_DAC_SVOL_SHIFT 8 /* ADCL_DAC_SVOL - [11:8] */
514#define WM8904_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [11:8] */
515#define WM8904_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */
516#define WM8904_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */
517#define WM8904_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */
518#define WM8904_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
519#define WM8904_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
520#define WM8904_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
521#define WM8904_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */
522#define WM8904_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */
523#define WM8904_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */
524
525/*
526 * R33 (0x21) - DAC Digital 1
527 */
528#define WM8904_DAC_MONO 0x1000 /* DAC_MONO */
529#define WM8904_DAC_MONO_MASK 0x1000 /* DAC_MONO */
530#define WM8904_DAC_MONO_SHIFT 12 /* DAC_MONO */
531#define WM8904_DAC_MONO_WIDTH 1 /* DAC_MONO */
532#define WM8904_DAC_SB_FILT 0x0800 /* DAC_SB_FILT */
533#define WM8904_DAC_SB_FILT_MASK 0x0800 /* DAC_SB_FILT */
534#define WM8904_DAC_SB_FILT_SHIFT 11 /* DAC_SB_FILT */
535#define WM8904_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */
536#define WM8904_DAC_MUTERATE 0x0400 /* DAC_MUTERATE */
537#define WM8904_DAC_MUTERATE_MASK 0x0400 /* DAC_MUTERATE */
538#define WM8904_DAC_MUTERATE_SHIFT 10 /* DAC_MUTERATE */
539#define WM8904_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */
540#define WM8904_DAC_UNMUTE_RAMP 0x0200 /* DAC_UNMUTE_RAMP */
541#define WM8904_DAC_UNMUTE_RAMP_MASK 0x0200 /* DAC_UNMUTE_RAMP */
542#define WM8904_DAC_UNMUTE_RAMP_SHIFT 9 /* DAC_UNMUTE_RAMP */
543#define WM8904_DAC_UNMUTE_RAMP_WIDTH 1 /* DAC_UNMUTE_RAMP */
544#define WM8904_DAC_OSR128 0x0040 /* DAC_OSR128 */
545#define WM8904_DAC_OSR128_MASK 0x0040 /* DAC_OSR128 */
546#define WM8904_DAC_OSR128_SHIFT 6 /* DAC_OSR128 */
547#define WM8904_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */
548#define WM8904_DAC_MUTE 0x0008 /* DAC_MUTE */
549#define WM8904_DAC_MUTE_MASK 0x0008 /* DAC_MUTE */
550#define WM8904_DAC_MUTE_SHIFT 3 /* DAC_MUTE */
551#define WM8904_DAC_MUTE_WIDTH 1 /* DAC_MUTE */
552#define WM8904_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */
553#define WM8904_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */
554#define WM8904_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */
555
556/*
557 * R36 (0x24) - ADC Digital Volume Left
558 */
559#define WM8904_ADC_VU 0x0100 /* ADC_VU */
560#define WM8904_ADC_VU_MASK 0x0100 /* ADC_VU */
561#define WM8904_ADC_VU_SHIFT 8 /* ADC_VU */
562#define WM8904_ADC_VU_WIDTH 1 /* ADC_VU */
563#define WM8904_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
564#define WM8904_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */
565#define WM8904_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */
566
567/*
568 * R37 (0x25) - ADC Digital Volume Right
569 */
570#define WM8904_ADC_VU 0x0100 /* ADC_VU */
571#define WM8904_ADC_VU_MASK 0x0100 /* ADC_VU */
572#define WM8904_ADC_VU_SHIFT 8 /* ADC_VU */
573#define WM8904_ADC_VU_WIDTH 1 /* ADC_VU */
574#define WM8904_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
575#define WM8904_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */
576#define WM8904_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */
577
578/*
579 * R38 (0x26) - ADC Digital 0
580 */
581#define WM8904_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */
582#define WM8904_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */
583#define WM8904_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */
584#define WM8904_ADC_HPF 0x0010 /* ADC_HPF */
585#define WM8904_ADC_HPF_MASK 0x0010 /* ADC_HPF */
586#define WM8904_ADC_HPF_SHIFT 4 /* ADC_HPF */
587#define WM8904_ADC_HPF_WIDTH 1 /* ADC_HPF */
588#define WM8904_ADCL_DATINV 0x0002 /* ADCL_DATINV */
589#define WM8904_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */
590#define WM8904_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */
591#define WM8904_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */
592#define WM8904_ADCR_DATINV 0x0001 /* ADCR_DATINV */
593#define WM8904_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */
594#define WM8904_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */
595#define WM8904_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */
596
597/*
598 * R39 (0x27) - Digital Microphone 0
599 */
600#define WM8904_DMIC_ENA 0x1000 /* DMIC_ENA */
601#define WM8904_DMIC_ENA_MASK 0x1000 /* DMIC_ENA */
602#define WM8904_DMIC_ENA_SHIFT 12 /* DMIC_ENA */
603#define WM8904_DMIC_ENA_WIDTH 1 /* DMIC_ENA */
604#define WM8904_DMIC_SRC 0x0800 /* DMIC_SRC */
605#define WM8904_DMIC_SRC_MASK 0x0800 /* DMIC_SRC */
606#define WM8904_DMIC_SRC_SHIFT 11 /* DMIC_SRC */
607#define WM8904_DMIC_SRC_WIDTH 1 /* DMIC_SRC */
608
609/*
610 * R40 (0x28) - DRC 0
611 */
612#define WM8904_DRC_ENA 0x8000 /* DRC_ENA */
613#define WM8904_DRC_ENA_MASK 0x8000 /* DRC_ENA */
614#define WM8904_DRC_ENA_SHIFT 15 /* DRC_ENA */
615#define WM8904_DRC_ENA_WIDTH 1 /* DRC_ENA */
616#define WM8904_DRC_DAC_PATH 0x4000 /* DRC_DAC_PATH */
617#define WM8904_DRC_DAC_PATH_MASK 0x4000 /* DRC_DAC_PATH */
618#define WM8904_DRC_DAC_PATH_SHIFT 14 /* DRC_DAC_PATH */
619#define WM8904_DRC_DAC_PATH_WIDTH 1 /* DRC_DAC_PATH */
620#define WM8904_DRC_GS_HYST_LVL_MASK 0x1800 /* DRC_GS_HYST_LVL - [12:11] */
621#define WM8904_DRC_GS_HYST_LVL_SHIFT 11 /* DRC_GS_HYST_LVL - [12:11] */
622#define WM8904_DRC_GS_HYST_LVL_WIDTH 2 /* DRC_GS_HYST_LVL - [12:11] */
623#define WM8904_DRC_STARTUP_GAIN_MASK 0x07C0 /* DRC_STARTUP_GAIN - [10:6] */
624#define WM8904_DRC_STARTUP_GAIN_SHIFT 6 /* DRC_STARTUP_GAIN - [10:6] */
625#define WM8904_DRC_STARTUP_GAIN_WIDTH 5 /* DRC_STARTUP_GAIN - [10:6] */
626#define WM8904_DRC_FF_DELAY 0x0020 /* DRC_FF_DELAY */
627#define WM8904_DRC_FF_DELAY_MASK 0x0020 /* DRC_FF_DELAY */
628#define WM8904_DRC_FF_DELAY_SHIFT 5 /* DRC_FF_DELAY */
629#define WM8904_DRC_FF_DELAY_WIDTH 1 /* DRC_FF_DELAY */
630#define WM8904_DRC_GS_ENA 0x0008 /* DRC_GS_ENA */
631#define WM8904_DRC_GS_ENA_MASK 0x0008 /* DRC_GS_ENA */
632#define WM8904_DRC_GS_ENA_SHIFT 3 /* DRC_GS_ENA */
633#define WM8904_DRC_GS_ENA_WIDTH 1 /* DRC_GS_ENA */
634#define WM8904_DRC_QR 0x0004 /* DRC_QR */
635#define WM8904_DRC_QR_MASK 0x0004 /* DRC_QR */
636#define WM8904_DRC_QR_SHIFT 2 /* DRC_QR */
637#define WM8904_DRC_QR_WIDTH 1 /* DRC_QR */
638#define WM8904_DRC_ANTICLIP 0x0002 /* DRC_ANTICLIP */
639#define WM8904_DRC_ANTICLIP_MASK 0x0002 /* DRC_ANTICLIP */
640#define WM8904_DRC_ANTICLIP_SHIFT 1 /* DRC_ANTICLIP */
641#define WM8904_DRC_ANTICLIP_WIDTH 1 /* DRC_ANTICLIP */
642#define WM8904_DRC_GS_HYST 0x0001 /* DRC_GS_HYST */
643#define WM8904_DRC_GS_HYST_MASK 0x0001 /* DRC_GS_HYST */
644#define WM8904_DRC_GS_HYST_SHIFT 0 /* DRC_GS_HYST */
645#define WM8904_DRC_GS_HYST_WIDTH 1 /* DRC_GS_HYST */
646
647/*
648 * R41 (0x29) - DRC 1
649 */
650#define WM8904_DRC_ATK_MASK 0xF000 /* DRC_ATK - [15:12] */
651#define WM8904_DRC_ATK_SHIFT 12 /* DRC_ATK - [15:12] */
652#define WM8904_DRC_ATK_WIDTH 4 /* DRC_ATK - [15:12] */
653#define WM8904_DRC_DCY_MASK 0x0F00 /* DRC_DCY - [11:8] */
654#define WM8904_DRC_DCY_SHIFT 8 /* DRC_DCY - [11:8] */
655#define WM8904_DRC_DCY_WIDTH 4 /* DRC_DCY - [11:8] */
656#define WM8904_DRC_QR_THR_MASK 0x00C0 /* DRC_QR_THR - [7:6] */
657#define WM8904_DRC_QR_THR_SHIFT 6 /* DRC_QR_THR - [7:6] */
658#define WM8904_DRC_QR_THR_WIDTH 2 /* DRC_QR_THR - [7:6] */
659#define WM8904_DRC_QR_DCY_MASK 0x0030 /* DRC_QR_DCY - [5:4] */
660#define WM8904_DRC_QR_DCY_SHIFT 4 /* DRC_QR_DCY - [5:4] */
661#define WM8904_DRC_QR_DCY_WIDTH 2 /* DRC_QR_DCY - [5:4] */
662#define WM8904_DRC_MINGAIN_MASK 0x000C /* DRC_MINGAIN - [3:2] */
663#define WM8904_DRC_MINGAIN_SHIFT 2 /* DRC_MINGAIN - [3:2] */
664#define WM8904_DRC_MINGAIN_WIDTH 2 /* DRC_MINGAIN - [3:2] */
665#define WM8904_DRC_MAXGAIN_MASK 0x0003 /* DRC_MAXGAIN - [1:0] */
666#define WM8904_DRC_MAXGAIN_SHIFT 0 /* DRC_MAXGAIN - [1:0] */
667#define WM8904_DRC_MAXGAIN_WIDTH 2 /* DRC_MAXGAIN - [1:0] */
668
669/*
670 * R42 (0x2A) - DRC 2
671 */
672#define WM8904_DRC_HI_COMP_MASK 0x0038 /* DRC_HI_COMP - [5:3] */
673#define WM8904_DRC_HI_COMP_SHIFT 3 /* DRC_HI_COMP - [5:3] */
674#define WM8904_DRC_HI_COMP_WIDTH 3 /* DRC_HI_COMP - [5:3] */
675#define WM8904_DRC_LO_COMP_MASK 0x0007 /* DRC_LO_COMP - [2:0] */
676#define WM8904_DRC_LO_COMP_SHIFT 0 /* DRC_LO_COMP - [2:0] */
677#define WM8904_DRC_LO_COMP_WIDTH 3 /* DRC_LO_COMP - [2:0] */
678
679/*
680 * R43 (0x2B) - DRC 3
681 */
682#define WM8904_DRC_KNEE_IP_MASK 0x07E0 /* DRC_KNEE_IP - [10:5] */
683#define WM8904_DRC_KNEE_IP_SHIFT 5 /* DRC_KNEE_IP - [10:5] */
684#define WM8904_DRC_KNEE_IP_WIDTH 6 /* DRC_KNEE_IP - [10:5] */
685#define WM8904_DRC_KNEE_OP_MASK 0x001F /* DRC_KNEE_OP - [4:0] */
686#define WM8904_DRC_KNEE_OP_SHIFT 0 /* DRC_KNEE_OP - [4:0] */
687#define WM8904_DRC_KNEE_OP_WIDTH 5 /* DRC_KNEE_OP - [4:0] */
688
689/*
690 * R44 (0x2C) - Analogue Left Input 0
691 */
692#define WM8904_LINMUTE 0x0080 /* LINMUTE */
693#define WM8904_LINMUTE_MASK 0x0080 /* LINMUTE */
694#define WM8904_LINMUTE_SHIFT 7 /* LINMUTE */
695#define WM8904_LINMUTE_WIDTH 1 /* LINMUTE */
696#define WM8904_LIN_VOL_MASK 0x001F /* LIN_VOL - [4:0] */
697#define WM8904_LIN_VOL_SHIFT 0 /* LIN_VOL - [4:0] */
698#define WM8904_LIN_VOL_WIDTH 5 /* LIN_VOL - [4:0] */
699
700/*
701 * R45 (0x2D) - Analogue Right Input 0
702 */
703#define WM8904_RINMUTE 0x0080 /* RINMUTE */
704#define WM8904_RINMUTE_MASK 0x0080 /* RINMUTE */
705#define WM8904_RINMUTE_SHIFT 7 /* RINMUTE */
706#define WM8904_RINMUTE_WIDTH 1 /* RINMUTE */
707#define WM8904_RIN_VOL_MASK 0x001F /* RIN_VOL - [4:0] */
708#define WM8904_RIN_VOL_SHIFT 0 /* RIN_VOL - [4:0] */
709#define WM8904_RIN_VOL_WIDTH 5 /* RIN_VOL - [4:0] */
710
711/*
712 * R46 (0x2E) - Analogue Left Input 1
713 */
714#define WM8904_INL_CM_ENA 0x0040 /* INL_CM_ENA */
715#define WM8904_INL_CM_ENA_MASK 0x0040 /* INL_CM_ENA */
716#define WM8904_INL_CM_ENA_SHIFT 6 /* INL_CM_ENA */
717#define WM8904_INL_CM_ENA_WIDTH 1 /* INL_CM_ENA */
718#define WM8904_L_IP_SEL_N_MASK 0x0030 /* L_IP_SEL_N - [5:4] */
719#define WM8904_L_IP_SEL_N_SHIFT 4 /* L_IP_SEL_N - [5:4] */
720#define WM8904_L_IP_SEL_N_WIDTH 2 /* L_IP_SEL_N - [5:4] */
721#define WM8904_L_IP_SEL_P_MASK 0x000C /* L_IP_SEL_P - [3:2] */
722#define WM8904_L_IP_SEL_P_SHIFT 2 /* L_IP_SEL_P - [3:2] */
723#define WM8904_L_IP_SEL_P_WIDTH 2 /* L_IP_SEL_P - [3:2] */
724#define WM8904_L_MODE_MASK 0x0003 /* L_MODE - [1:0] */
725#define WM8904_L_MODE_SHIFT 0 /* L_MODE - [1:0] */
726#define WM8904_L_MODE_WIDTH 2 /* L_MODE - [1:0] */
727
728/*
729 * R47 (0x2F) - Analogue Right Input 1
730 */
731#define WM8904_INR_CM_ENA 0x0040 /* INR_CM_ENA */
732#define WM8904_INR_CM_ENA_MASK 0x0040 /* INR_CM_ENA */
733#define WM8904_INR_CM_ENA_SHIFT 6 /* INR_CM_ENA */
734#define WM8904_INR_CM_ENA_WIDTH 1 /* INR_CM_ENA */
735#define WM8904_R_IP_SEL_N_MASK 0x0030 /* R_IP_SEL_N - [5:4] */
736#define WM8904_R_IP_SEL_N_SHIFT 4 /* R_IP_SEL_N - [5:4] */
737#define WM8904_R_IP_SEL_N_WIDTH 2 /* R_IP_SEL_N - [5:4] */
738#define WM8904_R_IP_SEL_P_MASK 0x000C /* R_IP_SEL_P - [3:2] */
739#define WM8904_R_IP_SEL_P_SHIFT 2 /* R_IP_SEL_P - [3:2] */
740#define WM8904_R_IP_SEL_P_WIDTH 2 /* R_IP_SEL_P - [3:2] */
741#define WM8904_R_MODE_MASK 0x0003 /* R_MODE - [1:0] */
742#define WM8904_R_MODE_SHIFT 0 /* R_MODE - [1:0] */
743#define WM8904_R_MODE_WIDTH 2 /* R_MODE - [1:0] */
744
745/*
746 * R57 (0x39) - Analogue OUT1 Left
747 */
748#define WM8904_HPOUTL_MUTE 0x0100 /* HPOUTL_MUTE */
749#define WM8904_HPOUTL_MUTE_MASK 0x0100 /* HPOUTL_MUTE */
750#define WM8904_HPOUTL_MUTE_SHIFT 8 /* HPOUTL_MUTE */
751#define WM8904_HPOUTL_MUTE_WIDTH 1 /* HPOUTL_MUTE */
752#define WM8904_HPOUT_VU 0x0080 /* HPOUT_VU */
753#define WM8904_HPOUT_VU_MASK 0x0080 /* HPOUT_VU */
754#define WM8904_HPOUT_VU_SHIFT 7 /* HPOUT_VU */
755#define WM8904_HPOUT_VU_WIDTH 1 /* HPOUT_VU */
756#define WM8904_HPOUTLZC 0x0040 /* HPOUTLZC */
757#define WM8904_HPOUTLZC_MASK 0x0040 /* HPOUTLZC */
758#define WM8904_HPOUTLZC_SHIFT 6 /* HPOUTLZC */
759#define WM8904_HPOUTLZC_WIDTH 1 /* HPOUTLZC */
760#define WM8904_HPOUTL_VOL_MASK 0x003F /* HPOUTL_VOL - [5:0] */
761#define WM8904_HPOUTL_VOL_SHIFT 0 /* HPOUTL_VOL - [5:0] */
762#define WM8904_HPOUTL_VOL_WIDTH 6 /* HPOUTL_VOL - [5:0] */
763
764/*
765 * R58 (0x3A) - Analogue OUT1 Right
766 */
767#define WM8904_HPOUTR_MUTE 0x0100 /* HPOUTR_MUTE */
768#define WM8904_HPOUTR_MUTE_MASK 0x0100 /* HPOUTR_MUTE */
769#define WM8904_HPOUTR_MUTE_SHIFT 8 /* HPOUTR_MUTE */
770#define WM8904_HPOUTR_MUTE_WIDTH 1 /* HPOUTR_MUTE */
771#define WM8904_HPOUT_VU 0x0080 /* HPOUT_VU */
772#define WM8904_HPOUT_VU_MASK 0x0080 /* HPOUT_VU */
773#define WM8904_HPOUT_VU_SHIFT 7 /* HPOUT_VU */
774#define WM8904_HPOUT_VU_WIDTH 1 /* HPOUT_VU */
775#define WM8904_HPOUTRZC 0x0040 /* HPOUTRZC */
776#define WM8904_HPOUTRZC_MASK 0x0040 /* HPOUTRZC */
777#define WM8904_HPOUTRZC_SHIFT 6 /* HPOUTRZC */
778#define WM8904_HPOUTRZC_WIDTH 1 /* HPOUTRZC */
779#define WM8904_HPOUTR_VOL_MASK 0x003F /* HPOUTR_VOL - [5:0] */
780#define WM8904_HPOUTR_VOL_SHIFT 0 /* HPOUTR_VOL - [5:0] */
781#define WM8904_HPOUTR_VOL_WIDTH 6 /* HPOUTR_VOL - [5:0] */
782
783/*
784 * R59 (0x3B) - Analogue OUT2 Left
785 */
786#define WM8904_LINEOUTL_MUTE 0x0100 /* LINEOUTL_MUTE */
787#define WM8904_LINEOUTL_MUTE_MASK 0x0100 /* LINEOUTL_MUTE */
788#define WM8904_LINEOUTL_MUTE_SHIFT 8 /* LINEOUTL_MUTE */
789#define WM8904_LINEOUTL_MUTE_WIDTH 1 /* LINEOUTL_MUTE */
790#define WM8904_LINEOUT_VU 0x0080 /* LINEOUT_VU */
791#define WM8904_LINEOUT_VU_MASK 0x0080 /* LINEOUT_VU */
792#define WM8904_LINEOUT_VU_SHIFT 7 /* LINEOUT_VU */
793#define WM8904_LINEOUT_VU_WIDTH 1 /* LINEOUT_VU */
794#define WM8904_LINEOUTLZC 0x0040 /* LINEOUTLZC */
795#define WM8904_LINEOUTLZC_MASK 0x0040 /* LINEOUTLZC */
796#define WM8904_LINEOUTLZC_SHIFT 6 /* LINEOUTLZC */
797#define WM8904_LINEOUTLZC_WIDTH 1 /* LINEOUTLZC */
798#define WM8904_LINEOUTL_VOL_MASK 0x003F /* LINEOUTL_VOL - [5:0] */
799#define WM8904_LINEOUTL_VOL_SHIFT 0 /* LINEOUTL_VOL - [5:0] */
800#define WM8904_LINEOUTL_VOL_WIDTH 6 /* LINEOUTL_VOL - [5:0] */
801
802/*
803 * R60 (0x3C) - Analogue OUT2 Right
804 */
805#define WM8904_LINEOUTR_MUTE 0x0100 /* LINEOUTR_MUTE */
806#define WM8904_LINEOUTR_MUTE_MASK 0x0100 /* LINEOUTR_MUTE */
807#define WM8904_LINEOUTR_MUTE_SHIFT 8 /* LINEOUTR_MUTE */
808#define WM8904_LINEOUTR_MUTE_WIDTH 1 /* LINEOUTR_MUTE */
809#define WM8904_LINEOUT_VU 0x0080 /* LINEOUT_VU */
810#define WM8904_LINEOUT_VU_MASK 0x0080 /* LINEOUT_VU */
811#define WM8904_LINEOUT_VU_SHIFT 7 /* LINEOUT_VU */
812#define WM8904_LINEOUT_VU_WIDTH 1 /* LINEOUT_VU */
813#define WM8904_LINEOUTRZC 0x0040 /* LINEOUTRZC */
814#define WM8904_LINEOUTRZC_MASK 0x0040 /* LINEOUTRZC */
815#define WM8904_LINEOUTRZC_SHIFT 6 /* LINEOUTRZC */
816#define WM8904_LINEOUTRZC_WIDTH 1 /* LINEOUTRZC */
817#define WM8904_LINEOUTR_VOL_MASK 0x003F /* LINEOUTR_VOL - [5:0] */
818#define WM8904_LINEOUTR_VOL_SHIFT 0 /* LINEOUTR_VOL - [5:0] */
819#define WM8904_LINEOUTR_VOL_WIDTH 6 /* LINEOUTR_VOL - [5:0] */
820
821/*
822 * R61 (0x3D) - Analogue OUT12 ZC
823 */
824#define WM8904_HPL_BYP_ENA 0x0008 /* HPL_BYP_ENA */
825#define WM8904_HPL_BYP_ENA_MASK 0x0008 /* HPL_BYP_ENA */
826#define WM8904_HPL_BYP_ENA_SHIFT 3 /* HPL_BYP_ENA */
827#define WM8904_HPL_BYP_ENA_WIDTH 1 /* HPL_BYP_ENA */
828#define WM8904_HPR_BYP_ENA 0x0004 /* HPR_BYP_ENA */
829#define WM8904_HPR_BYP_ENA_MASK 0x0004 /* HPR_BYP_ENA */
830#define WM8904_HPR_BYP_ENA_SHIFT 2 /* HPR_BYP_ENA */
831#define WM8904_HPR_BYP_ENA_WIDTH 1 /* HPR_BYP_ENA */
832#define WM8904_LINEOUTL_BYP_ENA 0x0002 /* LINEOUTL_BYP_ENA */
833#define WM8904_LINEOUTL_BYP_ENA_MASK 0x0002 /* LINEOUTL_BYP_ENA */
834#define WM8904_LINEOUTL_BYP_ENA_SHIFT 1 /* LINEOUTL_BYP_ENA */
835#define WM8904_LINEOUTL_BYP_ENA_WIDTH 1 /* LINEOUTL_BYP_ENA */
836#define WM8904_LINEOUTR_BYP_ENA 0x0001 /* LINEOUTR_BYP_ENA */
837#define WM8904_LINEOUTR_BYP_ENA_MASK 0x0001 /* LINEOUTR_BYP_ENA */
838#define WM8904_LINEOUTR_BYP_ENA_SHIFT 0 /* LINEOUTR_BYP_ENA */
839#define WM8904_LINEOUTR_BYP_ENA_WIDTH 1 /* LINEOUTR_BYP_ENA */
840
841/*
842 * R67 (0x43) - DC Servo 0
843 */
844#define WM8904_DCS_ENA_CHAN_3 0x0008 /* DCS_ENA_CHAN_3 */
845#define WM8904_DCS_ENA_CHAN_3_MASK 0x0008 /* DCS_ENA_CHAN_3 */
846#define WM8904_DCS_ENA_CHAN_3_SHIFT 3 /* DCS_ENA_CHAN_3 */
847#define WM8904_DCS_ENA_CHAN_3_WIDTH 1 /* DCS_ENA_CHAN_3 */
848#define WM8904_DCS_ENA_CHAN_2 0x0004 /* DCS_ENA_CHAN_2 */
849#define WM8904_DCS_ENA_CHAN_2_MASK 0x0004 /* DCS_ENA_CHAN_2 */
850#define WM8904_DCS_ENA_CHAN_2_SHIFT 2 /* DCS_ENA_CHAN_2 */
851#define WM8904_DCS_ENA_CHAN_2_WIDTH 1 /* DCS_ENA_CHAN_2 */
852#define WM8904_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */
853#define WM8904_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */
854#define WM8904_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */
855#define WM8904_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */
856#define WM8904_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */
857#define WM8904_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */
858#define WM8904_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */
859#define WM8904_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */
860
861/*
862 * R68 (0x44) - DC Servo 1
863 */
864#define WM8904_DCS_TRIG_SINGLE_3 0x8000 /* DCS_TRIG_SINGLE_3 */
865#define WM8904_DCS_TRIG_SINGLE_3_MASK 0x8000 /* DCS_TRIG_SINGLE_3 */
866#define WM8904_DCS_TRIG_SINGLE_3_SHIFT 15 /* DCS_TRIG_SINGLE_3 */
867#define WM8904_DCS_TRIG_SINGLE_3_WIDTH 1 /* DCS_TRIG_SINGLE_3 */
868#define WM8904_DCS_TRIG_SINGLE_2 0x4000 /* DCS_TRIG_SINGLE_2 */
869#define WM8904_DCS_TRIG_SINGLE_2_MASK 0x4000 /* DCS_TRIG_SINGLE_2 */
870#define WM8904_DCS_TRIG_SINGLE_2_SHIFT 14 /* DCS_TRIG_SINGLE_2 */
871#define WM8904_DCS_TRIG_SINGLE_2_WIDTH 1 /* DCS_TRIG_SINGLE_2 */
872#define WM8904_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */
873#define WM8904_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */
874#define WM8904_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */
875#define WM8904_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */
876#define WM8904_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */
877#define WM8904_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */
878#define WM8904_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */
879#define WM8904_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */
880#define WM8904_DCS_TRIG_SERIES_3 0x0800 /* DCS_TRIG_SERIES_3 */
881#define WM8904_DCS_TRIG_SERIES_3_MASK 0x0800 /* DCS_TRIG_SERIES_3 */
882#define WM8904_DCS_TRIG_SERIES_3_SHIFT 11 /* DCS_TRIG_SERIES_3 */
883#define WM8904_DCS_TRIG_SERIES_3_WIDTH 1 /* DCS_TRIG_SERIES_3 */
884#define WM8904_DCS_TRIG_SERIES_2 0x0400 /* DCS_TRIG_SERIES_2 */
885#define WM8904_DCS_TRIG_SERIES_2_MASK 0x0400 /* DCS_TRIG_SERIES_2 */
886#define WM8904_DCS_TRIG_SERIES_2_SHIFT 10 /* DCS_TRIG_SERIES_2 */
887#define WM8904_DCS_TRIG_SERIES_2_WIDTH 1 /* DCS_TRIG_SERIES_2 */
888#define WM8904_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */
889#define WM8904_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */
890#define WM8904_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */
891#define WM8904_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */
892#define WM8904_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */
893#define WM8904_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */
894#define WM8904_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */
895#define WM8904_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */
896#define WM8904_DCS_TRIG_STARTUP_3 0x0080 /* DCS_TRIG_STARTUP_3 */
897#define WM8904_DCS_TRIG_STARTUP_3_MASK 0x0080 /* DCS_TRIG_STARTUP_3 */
898#define WM8904_DCS_TRIG_STARTUP_3_SHIFT 7 /* DCS_TRIG_STARTUP_3 */
899#define WM8904_DCS_TRIG_STARTUP_3_WIDTH 1 /* DCS_TRIG_STARTUP_3 */
900#define WM8904_DCS_TRIG_STARTUP_2 0x0040 /* DCS_TRIG_STARTUP_2 */
901#define WM8904_DCS_TRIG_STARTUP_2_MASK 0x0040 /* DCS_TRIG_STARTUP_2 */
902#define WM8904_DCS_TRIG_STARTUP_2_SHIFT 6 /* DCS_TRIG_STARTUP_2 */
903#define WM8904_DCS_TRIG_STARTUP_2_WIDTH 1 /* DCS_TRIG_STARTUP_2 */
904#define WM8904_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */
905#define WM8904_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */
906#define WM8904_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */
907#define WM8904_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */
908#define WM8904_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */
909#define WM8904_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */
910#define WM8904_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */
911#define WM8904_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */
912#define WM8904_DCS_TRIG_DAC_WR_3 0x0008 /* DCS_TRIG_DAC_WR_3 */
913#define WM8904_DCS_TRIG_DAC_WR_3_MASK 0x0008 /* DCS_TRIG_DAC_WR_3 */
914#define WM8904_DCS_TRIG_DAC_WR_3_SHIFT 3 /* DCS_TRIG_DAC_WR_3 */
915#define WM8904_DCS_TRIG_DAC_WR_3_WIDTH 1 /* DCS_TRIG_DAC_WR_3 */
916#define WM8904_DCS_TRIG_DAC_WR_2 0x0004 /* DCS_TRIG_DAC_WR_2 */
917#define WM8904_DCS_TRIG_DAC_WR_2_MASK 0x0004 /* DCS_TRIG_DAC_WR_2 */
918#define WM8904_DCS_TRIG_DAC_WR_2_SHIFT 2 /* DCS_TRIG_DAC_WR_2 */
919#define WM8904_DCS_TRIG_DAC_WR_2_WIDTH 1 /* DCS_TRIG_DAC_WR_2 */
920#define WM8904_DCS_TRIG_DAC_WR_1 0x0002 /* DCS_TRIG_DAC_WR_1 */
921#define WM8904_DCS_TRIG_DAC_WR_1_MASK 0x0002 /* DCS_TRIG_DAC_WR_1 */
922#define WM8904_DCS_TRIG_DAC_WR_1_SHIFT 1 /* DCS_TRIG_DAC_WR_1 */
923#define WM8904_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */
924#define WM8904_DCS_TRIG_DAC_WR_0 0x0001 /* DCS_TRIG_DAC_WR_0 */
925#define WM8904_DCS_TRIG_DAC_WR_0_MASK 0x0001 /* DCS_TRIG_DAC_WR_0 */
926#define WM8904_DCS_TRIG_DAC_WR_0_SHIFT 0 /* DCS_TRIG_DAC_WR_0 */
927#define WM8904_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */
928
929/*
930 * R69 (0x45) - DC Servo 2
931 */
932#define WM8904_DCS_TIMER_PERIOD_23_MASK 0x0F00 /* DCS_TIMER_PERIOD_23 - [11:8] */
933#define WM8904_DCS_TIMER_PERIOD_23_SHIFT 8 /* DCS_TIMER_PERIOD_23 - [11:8] */
934#define WM8904_DCS_TIMER_PERIOD_23_WIDTH 4 /* DCS_TIMER_PERIOD_23 - [11:8] */
935#define WM8904_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */
936#define WM8904_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */
937#define WM8904_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */
938
939/*
940 * R71 (0x47) - DC Servo 4
941 */
942#define WM8904_DCS_SERIES_NO_23_MASK 0x007F /* DCS_SERIES_NO_23 - [6:0] */
943#define WM8904_DCS_SERIES_NO_23_SHIFT 0 /* DCS_SERIES_NO_23 - [6:0] */
944#define WM8904_DCS_SERIES_NO_23_WIDTH 7 /* DCS_SERIES_NO_23 - [6:0] */
945
946/*
947 * R72 (0x48) - DC Servo 5
948 */
949#define WM8904_DCS_SERIES_NO_01_MASK 0x007F /* DCS_SERIES_NO_01 - [6:0] */
950#define WM8904_DCS_SERIES_NO_01_SHIFT 0 /* DCS_SERIES_NO_01 - [6:0] */
951#define WM8904_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [6:0] */
952
953/*
954 * R73 (0x49) - DC Servo 6
955 */
956#define WM8904_DCS_DAC_WR_VAL_3_MASK 0x00FF /* DCS_DAC_WR_VAL_3 - [7:0] */
957#define WM8904_DCS_DAC_WR_VAL_3_SHIFT 0 /* DCS_DAC_WR_VAL_3 - [7:0] */
958#define WM8904_DCS_DAC_WR_VAL_3_WIDTH 8 /* DCS_DAC_WR_VAL_3 - [7:0] */
959
960/*
961 * R74 (0x4A) - DC Servo 7
962 */
963#define WM8904_DCS_DAC_WR_VAL_2_MASK 0x00FF /* DCS_DAC_WR_VAL_2 - [7:0] */
964#define WM8904_DCS_DAC_WR_VAL_2_SHIFT 0 /* DCS_DAC_WR_VAL_2 - [7:0] */
965#define WM8904_DCS_DAC_WR_VAL_2_WIDTH 8 /* DCS_DAC_WR_VAL_2 - [7:0] */
966
967/*
968 * R75 (0x4B) - DC Servo 8
969 */
970#define WM8904_DCS_DAC_WR_VAL_1_MASK 0x00FF /* DCS_DAC_WR_VAL_1 - [7:0] */
971#define WM8904_DCS_DAC_WR_VAL_1_SHIFT 0 /* DCS_DAC_WR_VAL_1 - [7:0] */
972#define WM8904_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [7:0] */
973
974/*
975 * R76 (0x4C) - DC Servo 9
976 */
977#define WM8904_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */
978#define WM8904_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */
979#define WM8904_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */
980
981/*
982 * R77 (0x4D) - DC Servo Readback 0
983 */
984#define WM8904_DCS_CAL_COMPLETE_MASK 0x0F00 /* DCS_CAL_COMPLETE - [11:8] */
985#define WM8904_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [11:8] */
986#define WM8904_DCS_CAL_COMPLETE_WIDTH 4 /* DCS_CAL_COMPLETE - [11:8] */
987#define WM8904_DCS_DAC_WR_COMPLETE_MASK 0x00F0 /* DCS_DAC_WR_COMPLETE - [7:4] */
988#define WM8904_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [7:4] */
989#define WM8904_DCS_DAC_WR_COMPLETE_WIDTH 4 /* DCS_DAC_WR_COMPLETE - [7:4] */
990#define WM8904_DCS_STARTUP_COMPLETE_MASK 0x000F /* DCS_STARTUP_COMPLETE - [3:0] */
991#define WM8904_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [3:0] */
992#define WM8904_DCS_STARTUP_COMPLETE_WIDTH 4 /* DCS_STARTUP_COMPLETE - [3:0] */
993
994/*
995 * R90 (0x5A) - Analogue HP 0
996 */
997#define WM8904_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */
998#define WM8904_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */
999#define WM8904_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */
1000#define WM8904_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */
1001#define WM8904_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */
1002#define WM8904_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */
1003#define WM8904_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */
1004#define WM8904_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */
1005#define WM8904_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */
1006#define WM8904_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */
1007#define WM8904_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */
1008#define WM8904_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */
1009#define WM8904_HPL_ENA 0x0010 /* HPL_ENA */
1010#define WM8904_HPL_ENA_MASK 0x0010 /* HPL_ENA */
1011#define WM8904_HPL_ENA_SHIFT 4 /* HPL_ENA */
1012#define WM8904_HPL_ENA_WIDTH 1 /* HPL_ENA */
1013#define WM8904_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */
1014#define WM8904_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */
1015#define WM8904_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */
1016#define WM8904_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */
1017#define WM8904_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */
1018#define WM8904_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */
1019#define WM8904_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */
1020#define WM8904_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */
1021#define WM8904_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */
1022#define WM8904_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */
1023#define WM8904_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */
1024#define WM8904_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */
1025#define WM8904_HPR_ENA 0x0001 /* HPR_ENA */
1026#define WM8904_HPR_ENA_MASK 0x0001 /* HPR_ENA */
1027#define WM8904_HPR_ENA_SHIFT 0 /* HPR_ENA */
1028#define WM8904_HPR_ENA_WIDTH 1 /* HPR_ENA */
1029
1030/*
1031 * R94 (0x5E) - Analogue Lineout 0
1032 */
1033#define WM8904_LINEOUTL_RMV_SHORT 0x0080 /* LINEOUTL_RMV_SHORT */
1034#define WM8904_LINEOUTL_RMV_SHORT_MASK 0x0080 /* LINEOUTL_RMV_SHORT */
1035#define WM8904_LINEOUTL_RMV_SHORT_SHIFT 7 /* LINEOUTL_RMV_SHORT */
1036#define WM8904_LINEOUTL_RMV_SHORT_WIDTH 1 /* LINEOUTL_RMV_SHORT */
1037#define WM8904_LINEOUTL_ENA_OUTP 0x0040 /* LINEOUTL_ENA_OUTP */
1038#define WM8904_LINEOUTL_ENA_OUTP_MASK 0x0040 /* LINEOUTL_ENA_OUTP */
1039#define WM8904_LINEOUTL_ENA_OUTP_SHIFT 6 /* LINEOUTL_ENA_OUTP */
1040#define WM8904_LINEOUTL_ENA_OUTP_WIDTH 1 /* LINEOUTL_ENA_OUTP */
1041#define WM8904_LINEOUTL_ENA_DLY 0x0020 /* LINEOUTL_ENA_DLY */
1042#define WM8904_LINEOUTL_ENA_DLY_MASK 0x0020 /* LINEOUTL_ENA_DLY */
1043#define WM8904_LINEOUTL_ENA_DLY_SHIFT 5 /* LINEOUTL_ENA_DLY */
1044#define WM8904_LINEOUTL_ENA_DLY_WIDTH 1 /* LINEOUTL_ENA_DLY */
1045#define WM8904_LINEOUTL_ENA 0x0010 /* LINEOUTL_ENA */
1046#define WM8904_LINEOUTL_ENA_MASK 0x0010 /* LINEOUTL_ENA */
1047#define WM8904_LINEOUTL_ENA_SHIFT 4 /* LINEOUTL_ENA */
1048#define WM8904_LINEOUTL_ENA_WIDTH 1 /* LINEOUTL_ENA */
1049#define WM8904_LINEOUTR_RMV_SHORT 0x0008 /* LINEOUTR_RMV_SHORT */
1050#define WM8904_LINEOUTR_RMV_SHORT_MASK 0x0008 /* LINEOUTR_RMV_SHORT */
1051#define WM8904_LINEOUTR_RMV_SHORT_SHIFT 3 /* LINEOUTR_RMV_SHORT */
1052#define WM8904_LINEOUTR_RMV_SHORT_WIDTH 1 /* LINEOUTR_RMV_SHORT */
1053#define WM8904_LINEOUTR_ENA_OUTP 0x0004 /* LINEOUTR_ENA_OUTP */
1054#define WM8904_LINEOUTR_ENA_OUTP_MASK 0x0004 /* LINEOUTR_ENA_OUTP */
1055#define WM8904_LINEOUTR_ENA_OUTP_SHIFT 2 /* LINEOUTR_ENA_OUTP */
1056#define WM8904_LINEOUTR_ENA_OUTP_WIDTH 1 /* LINEOUTR_ENA_OUTP */
1057#define WM8904_LINEOUTR_ENA_DLY 0x0002 /* LINEOUTR_ENA_DLY */
1058#define WM8904_LINEOUTR_ENA_DLY_MASK 0x0002 /* LINEOUTR_ENA_DLY */
1059#define WM8904_LINEOUTR_ENA_DLY_SHIFT 1 /* LINEOUTR_ENA_DLY */
1060#define WM8904_LINEOUTR_ENA_DLY_WIDTH 1 /* LINEOUTR_ENA_DLY */
1061#define WM8904_LINEOUTR_ENA 0x0001 /* LINEOUTR_ENA */
1062#define WM8904_LINEOUTR_ENA_MASK 0x0001 /* LINEOUTR_ENA */
1063#define WM8904_LINEOUTR_ENA_SHIFT 0 /* LINEOUTR_ENA */
1064#define WM8904_LINEOUTR_ENA_WIDTH 1 /* LINEOUTR_ENA */
1065
1066/*
1067 * R98 (0x62) - Charge Pump 0
1068 */
1069#define WM8904_CP_ENA 0x0001 /* CP_ENA */
1070#define WM8904_CP_ENA_MASK 0x0001 /* CP_ENA */
1071#define WM8904_CP_ENA_SHIFT 0 /* CP_ENA */
1072#define WM8904_CP_ENA_WIDTH 1 /* CP_ENA */
1073
1074/*
1075 * R104 (0x68) - Class W 0
1076 */
1077#define WM8904_CP_DYN_PWR 0x0001 /* CP_DYN_PWR */
1078#define WM8904_CP_DYN_PWR_MASK 0x0001 /* CP_DYN_PWR */
1079#define WM8904_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR */
1080#define WM8904_CP_DYN_PWR_WIDTH 1 /* CP_DYN_PWR */
1081
1082/*
1083 * R108 (0x6C) - Write Sequencer 0
1084 */
1085#define WM8904_WSEQ_ENA 0x0100 /* WSEQ_ENA */
1086#define WM8904_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */
1087#define WM8904_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */
1088#define WM8904_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
1089#define WM8904_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */
1090#define WM8904_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */
1091#define WM8904_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */
1092
1093/*
1094 * R109 (0x6D) - Write Sequencer 1
1095 */
1096#define WM8904_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */
1097#define WM8904_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */
1098#define WM8904_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */
1099#define WM8904_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */
1100#define WM8904_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */
1101#define WM8904_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */
1102#define WM8904_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */
1103#define WM8904_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */
1104#define WM8904_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */
1105
1106/*
1107 * R110 (0x6E) - Write Sequencer 2
1108 */
1109#define WM8904_WSEQ_EOS 0x4000 /* WSEQ_EOS */
1110#define WM8904_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */
1111#define WM8904_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */
1112#define WM8904_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */
1113#define WM8904_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */
1114#define WM8904_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */
1115#define WM8904_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */
1116#define WM8904_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */
1117#define WM8904_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */
1118#define WM8904_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */
1119
1120/*
1121 * R111 (0x6F) - Write Sequencer 3
1122 */
1123#define WM8904_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */
1124#define WM8904_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */
1125#define WM8904_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */
1126#define WM8904_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
1127#define WM8904_WSEQ_START 0x0100 /* WSEQ_START */
1128#define WM8904_WSEQ_START_MASK 0x0100 /* WSEQ_START */
1129#define WM8904_WSEQ_START_SHIFT 8 /* WSEQ_START */
1130#define WM8904_WSEQ_START_WIDTH 1 /* WSEQ_START */
1131#define WM8904_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */
1132#define WM8904_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */
1133#define WM8904_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */
1134
1135/*
1136 * R112 (0x70) - Write Sequencer 4
1137 */
1138#define WM8904_WSEQ_CURRENT_INDEX_MASK 0x03F0 /* WSEQ_CURRENT_INDEX - [9:4] */
1139#define WM8904_WSEQ_CURRENT_INDEX_SHIFT 4 /* WSEQ_CURRENT_INDEX - [9:4] */
1140#define WM8904_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [9:4] */
1141#define WM8904_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
1142#define WM8904_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
1143#define WM8904_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
1144#define WM8904_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
1145
1146/*
1147 * R116 (0x74) - FLL Control 1
1148 */
1149#define WM8904_FLL_FRACN_ENA 0x0004 /* FLL_FRACN_ENA */
1150#define WM8904_FLL_FRACN_ENA_MASK 0x0004 /* FLL_FRACN_ENA */
1151#define WM8904_FLL_FRACN_ENA_SHIFT 2 /* FLL_FRACN_ENA */
1152#define WM8904_FLL_FRACN_ENA_WIDTH 1 /* FLL_FRACN_ENA */
1153#define WM8904_FLL_OSC_ENA 0x0002 /* FLL_OSC_ENA */
1154#define WM8904_FLL_OSC_ENA_MASK 0x0002 /* FLL_OSC_ENA */
1155#define WM8904_FLL_OSC_ENA_SHIFT 1 /* FLL_OSC_ENA */
1156#define WM8904_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */
1157#define WM8904_FLL_ENA 0x0001 /* FLL_ENA */
1158#define WM8904_FLL_ENA_MASK 0x0001 /* FLL_ENA */
1159#define WM8904_FLL_ENA_SHIFT 0 /* FLL_ENA */
1160#define WM8904_FLL_ENA_WIDTH 1 /* FLL_ENA */
1161
1162/*
1163 * R117 (0x75) - FLL Control 2
1164 */
1165#define WM8904_FLL_OUTDIV_MASK 0x3F00 /* FLL_OUTDIV - [13:8] */
1166#define WM8904_FLL_OUTDIV_SHIFT 8 /* FLL_OUTDIV - [13:8] */
1167#define WM8904_FLL_OUTDIV_WIDTH 6 /* FLL_OUTDIV - [13:8] */
1168#define WM8904_FLL_CTRL_RATE_MASK 0x0070 /* FLL_CTRL_RATE - [6:4] */
1169#define WM8904_FLL_CTRL_RATE_SHIFT 4 /* FLL_CTRL_RATE - [6:4] */
1170#define WM8904_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [6:4] */
1171#define WM8904_FLL_FRATIO_MASK 0x0007 /* FLL_FRATIO - [2:0] */
1172#define WM8904_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [2:0] */
1173#define WM8904_FLL_FRATIO_WIDTH 3 /* FLL_FRATIO - [2:0] */
1174
1175/*
1176 * R118 (0x76) - FLL Control 3
1177 */
1178#define WM8904_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */
1179#define WM8904_FLL_K_SHIFT 0 /* FLL_K - [15:0] */
1180#define WM8904_FLL_K_WIDTH 16 /* FLL_K - [15:0] */
1181
1182/*
1183 * R119 (0x77) - FLL Control 4
1184 */
1185#define WM8904_FLL_N_MASK 0x7FE0 /* FLL_N - [14:5] */
1186#define WM8904_FLL_N_SHIFT 5 /* FLL_N - [14:5] */
1187#define WM8904_FLL_N_WIDTH 10 /* FLL_N - [14:5] */
1188#define WM8904_FLL_GAIN_MASK 0x000F /* FLL_GAIN - [3:0] */
1189#define WM8904_FLL_GAIN_SHIFT 0 /* FLL_GAIN - [3:0] */
1190#define WM8904_FLL_GAIN_WIDTH 4 /* FLL_GAIN - [3:0] */
1191
1192/*
1193 * R120 (0x78) - FLL Control 5
1194 */
1195#define WM8904_FLL_CLK_REF_DIV_MASK 0x0018 /* FLL_CLK_REF_DIV - [4:3] */
1196#define WM8904_FLL_CLK_REF_DIV_SHIFT 3 /* FLL_CLK_REF_DIV - [4:3] */
1197#define WM8904_FLL_CLK_REF_DIV_WIDTH 2 /* FLL_CLK_REF_DIV - [4:3] */
1198#define WM8904_FLL_CLK_REF_SRC_MASK 0x0003 /* FLL_CLK_REF_SRC - [1:0] */
1199#define WM8904_FLL_CLK_REF_SRC_SHIFT 0 /* FLL_CLK_REF_SRC - [1:0] */
1200#define WM8904_FLL_CLK_REF_SRC_WIDTH 2 /* FLL_CLK_REF_SRC - [1:0] */
1201
1202/*
1203 * R121 (0x79) - GPIO Control 1
1204 */
1205#define WM8904_GPIO1_PU 0x0020 /* GPIO1_PU */
1206#define WM8904_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */
1207#define WM8904_GPIO1_PU_SHIFT 5 /* GPIO1_PU */
1208#define WM8904_GPIO1_PU_WIDTH 1 /* GPIO1_PU */
1209#define WM8904_GPIO1_PD 0x0010 /* GPIO1_PD */
1210#define WM8904_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */
1211#define WM8904_GPIO1_PD_SHIFT 4 /* GPIO1_PD */
1212#define WM8904_GPIO1_PD_WIDTH 1 /* GPIO1_PD */
1213#define WM8904_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */
1214#define WM8904_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */
1215#define WM8904_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */
1216
1217/*
1218 * R122 (0x7A) - GPIO Control 2
1219 */
1220#define WM8904_GPIO2_PU 0x0020 /* GPIO2_PU */
1221#define WM8904_GPIO2_PU_MASK 0x0020 /* GPIO2_PU */
1222#define WM8904_GPIO2_PU_SHIFT 5 /* GPIO2_PU */
1223#define WM8904_GPIO2_PU_WIDTH 1 /* GPIO2_PU */
1224#define WM8904_GPIO2_PD 0x0010 /* GPIO2_PD */
1225#define WM8904_GPIO2_PD_MASK 0x0010 /* GPIO2_PD */
1226#define WM8904_GPIO2_PD_SHIFT 4 /* GPIO2_PD */
1227#define WM8904_GPIO2_PD_WIDTH 1 /* GPIO2_PD */
1228#define WM8904_GPIO2_SEL_MASK 0x000F /* GPIO2_SEL - [3:0] */
1229#define WM8904_GPIO2_SEL_SHIFT 0 /* GPIO2_SEL - [3:0] */
1230#define WM8904_GPIO2_SEL_WIDTH 4 /* GPIO2_SEL - [3:0] */
1231
1232/*
1233 * R123 (0x7B) - GPIO Control 3
1234 */
1235#define WM8904_GPIO3_PU 0x0020 /* GPIO3_PU */
1236#define WM8904_GPIO3_PU_MASK 0x0020 /* GPIO3_PU */
1237#define WM8904_GPIO3_PU_SHIFT 5 /* GPIO3_PU */
1238#define WM8904_GPIO3_PU_WIDTH 1 /* GPIO3_PU */
1239#define WM8904_GPIO3_PD 0x0010 /* GPIO3_PD */
1240#define WM8904_GPIO3_PD_MASK 0x0010 /* GPIO3_PD */
1241#define WM8904_GPIO3_PD_SHIFT 4 /* GPIO3_PD */
1242#define WM8904_GPIO3_PD_WIDTH 1 /* GPIO3_PD */
1243#define WM8904_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */
1244#define WM8904_GPIO3_SEL_SHIFT 0 /* GPIO3_SEL - [3:0] */
1245#define WM8904_GPIO3_SEL_WIDTH 4 /* GPIO3_SEL - [3:0] */
1246
1247/*
1248 * R124 (0x7C) - GPIO Control 4
1249 */
1250#define WM8904_GPI7_ENA 0x0200 /* GPI7_ENA */
1251#define WM8904_GPI7_ENA_MASK 0x0200 /* GPI7_ENA */
1252#define WM8904_GPI7_ENA_SHIFT 9 /* GPI7_ENA */
1253#define WM8904_GPI7_ENA_WIDTH 1 /* GPI7_ENA */
1254#define WM8904_GPI8_ENA 0x0100 /* GPI8_ENA */
1255#define WM8904_GPI8_ENA_MASK 0x0100 /* GPI8_ENA */
1256#define WM8904_GPI8_ENA_SHIFT 8 /* GPI8_ENA */
1257#define WM8904_GPI8_ENA_WIDTH 1 /* GPI8_ENA */
1258#define WM8904_GPIO_BCLK_MODE_ENA 0x0080 /* GPIO_BCLK_MODE_ENA */
1259#define WM8904_GPIO_BCLK_MODE_ENA_MASK 0x0080 /* GPIO_BCLK_MODE_ENA */
1260#define WM8904_GPIO_BCLK_MODE_ENA_SHIFT 7 /* GPIO_BCLK_MODE_ENA */
1261#define WM8904_GPIO_BCLK_MODE_ENA_WIDTH 1 /* GPIO_BCLK_MODE_ENA */
1262#define WM8904_GPIO_BCLK_SEL_MASK 0x000F /* GPIO_BCLK_SEL - [3:0] */
1263#define WM8904_GPIO_BCLK_SEL_SHIFT 0 /* GPIO_BCLK_SEL - [3:0] */
1264#define WM8904_GPIO_BCLK_SEL_WIDTH 4 /* GPIO_BCLK_SEL - [3:0] */
1265
1266/*
1267 * R126 (0x7E) - Digital Pulls
1268 */
1269#define WM8904_MCLK_PU 0x0080 /* MCLK_PU */
1270#define WM8904_MCLK_PU_MASK 0x0080 /* MCLK_PU */
1271#define WM8904_MCLK_PU_SHIFT 7 /* MCLK_PU */
1272#define WM8904_MCLK_PU_WIDTH 1 /* MCLK_PU */
1273#define WM8904_MCLK_PD 0x0040 /* MCLK_PD */
1274#define WM8904_MCLK_PD_MASK 0x0040 /* MCLK_PD */
1275#define WM8904_MCLK_PD_SHIFT 6 /* MCLK_PD */
1276#define WM8904_MCLK_PD_WIDTH 1 /* MCLK_PD */
1277#define WM8904_DACDAT_PU 0x0020 /* DACDAT_PU */
1278#define WM8904_DACDAT_PU_MASK 0x0020 /* DACDAT_PU */
1279#define WM8904_DACDAT_PU_SHIFT 5 /* DACDAT_PU */
1280#define WM8904_DACDAT_PU_WIDTH 1 /* DACDAT_PU */
1281#define WM8904_DACDAT_PD 0x0010 /* DACDAT_PD */
1282#define WM8904_DACDAT_PD_MASK 0x0010 /* DACDAT_PD */
1283#define WM8904_DACDAT_PD_SHIFT 4 /* DACDAT_PD */
1284#define WM8904_DACDAT_PD_WIDTH 1 /* DACDAT_PD */
1285#define WM8904_LRCLK_PU 0x0008 /* LRCLK_PU */
1286#define WM8904_LRCLK_PU_MASK 0x0008 /* LRCLK_PU */
1287#define WM8904_LRCLK_PU_SHIFT 3 /* LRCLK_PU */
1288#define WM8904_LRCLK_PU_WIDTH 1 /* LRCLK_PU */
1289#define WM8904_LRCLK_PD 0x0004 /* LRCLK_PD */
1290#define WM8904_LRCLK_PD_MASK 0x0004 /* LRCLK_PD */
1291#define WM8904_LRCLK_PD_SHIFT 2 /* LRCLK_PD */
1292#define WM8904_LRCLK_PD_WIDTH 1 /* LRCLK_PD */
1293#define WM8904_BCLK_PU 0x0002 /* BCLK_PU */
1294#define WM8904_BCLK_PU_MASK 0x0002 /* BCLK_PU */
1295#define WM8904_BCLK_PU_SHIFT 1 /* BCLK_PU */
1296#define WM8904_BCLK_PU_WIDTH 1 /* BCLK_PU */
1297#define WM8904_BCLK_PD 0x0001 /* BCLK_PD */
1298#define WM8904_BCLK_PD_MASK 0x0001 /* BCLK_PD */
1299#define WM8904_BCLK_PD_SHIFT 0 /* BCLK_PD */
1300#define WM8904_BCLK_PD_WIDTH 1 /* BCLK_PD */
1301
1302/*
1303 * R127 (0x7F) - Interrupt Status
1304 */
1305#define WM8904_IRQ 0x0400 /* IRQ */
1306#define WM8904_IRQ_MASK 0x0400 /* IRQ */
1307#define WM8904_IRQ_SHIFT 10 /* IRQ */
1308#define WM8904_IRQ_WIDTH 1 /* IRQ */
1309#define WM8904_GPIO_BCLK_EINT 0x0200 /* GPIO_BCLK_EINT */
1310#define WM8904_GPIO_BCLK_EINT_MASK 0x0200 /* GPIO_BCLK_EINT */
1311#define WM8904_GPIO_BCLK_EINT_SHIFT 9 /* GPIO_BCLK_EINT */
1312#define WM8904_GPIO_BCLK_EINT_WIDTH 1 /* GPIO_BCLK_EINT */
1313#define WM8904_WSEQ_EINT 0x0100 /* WSEQ_EINT */
1314#define WM8904_WSEQ_EINT_MASK 0x0100 /* WSEQ_EINT */
1315#define WM8904_WSEQ_EINT_SHIFT 8 /* WSEQ_EINT */
1316#define WM8904_WSEQ_EINT_WIDTH 1 /* WSEQ_EINT */
1317#define WM8904_GPIO3_EINT 0x0080 /* GPIO3_EINT */
1318#define WM8904_GPIO3_EINT_MASK 0x0080 /* GPIO3_EINT */
1319#define WM8904_GPIO3_EINT_SHIFT 7 /* GPIO3_EINT */
1320#define WM8904_GPIO3_EINT_WIDTH 1 /* GPIO3_EINT */
1321#define WM8904_GPIO2_EINT 0x0040 /* GPIO2_EINT */
1322#define WM8904_GPIO2_EINT_MASK 0x0040 /* GPIO2_EINT */
1323#define WM8904_GPIO2_EINT_SHIFT 6 /* GPIO2_EINT */
1324#define WM8904_GPIO2_EINT_WIDTH 1 /* GPIO2_EINT */
1325#define WM8904_GPIO1_EINT 0x0020 /* GPIO1_EINT */
1326#define WM8904_GPIO1_EINT_MASK 0x0020 /* GPIO1_EINT */
1327#define WM8904_GPIO1_EINT_SHIFT 5 /* GPIO1_EINT */
1328#define WM8904_GPIO1_EINT_WIDTH 1 /* GPIO1_EINT */
1329#define WM8904_GPI8_EINT 0x0010 /* GPI8_EINT */
1330#define WM8904_GPI8_EINT_MASK 0x0010 /* GPI8_EINT */
1331#define WM8904_GPI8_EINT_SHIFT 4 /* GPI8_EINT */
1332#define WM8904_GPI8_EINT_WIDTH 1 /* GPI8_EINT */
1333#define WM8904_GPI7_EINT 0x0008 /* GPI7_EINT */
1334#define WM8904_GPI7_EINT_MASK 0x0008 /* GPI7_EINT */
1335#define WM8904_GPI7_EINT_SHIFT 3 /* GPI7_EINT */
1336#define WM8904_GPI7_EINT_WIDTH 1 /* GPI7_EINT */
1337#define WM8904_FLL_LOCK_EINT 0x0004 /* FLL_LOCK_EINT */
1338#define WM8904_FLL_LOCK_EINT_MASK 0x0004 /* FLL_LOCK_EINT */
1339#define WM8904_FLL_LOCK_EINT_SHIFT 2 /* FLL_LOCK_EINT */
1340#define WM8904_FLL_LOCK_EINT_WIDTH 1 /* FLL_LOCK_EINT */
1341#define WM8904_MIC_SHRT_EINT 0x0002 /* MIC_SHRT_EINT */
1342#define WM8904_MIC_SHRT_EINT_MASK 0x0002 /* MIC_SHRT_EINT */
1343#define WM8904_MIC_SHRT_EINT_SHIFT 1 /* MIC_SHRT_EINT */
1344#define WM8904_MIC_SHRT_EINT_WIDTH 1 /* MIC_SHRT_EINT */
1345#define WM8904_MIC_DET_EINT 0x0001 /* MIC_DET_EINT */
1346#define WM8904_MIC_DET_EINT_MASK 0x0001 /* MIC_DET_EINT */
1347#define WM8904_MIC_DET_EINT_SHIFT 0 /* MIC_DET_EINT */
1348#define WM8904_MIC_DET_EINT_WIDTH 1 /* MIC_DET_EINT */
1349
1350/*
1351 * R128 (0x80) - Interrupt Status Mask
1352 */
1353#define WM8904_IM_GPIO_BCLK_EINT 0x0200 /* IM_GPIO_BCLK_EINT */
1354#define WM8904_IM_GPIO_BCLK_EINT_MASK 0x0200 /* IM_GPIO_BCLK_EINT */
1355#define WM8904_IM_GPIO_BCLK_EINT_SHIFT 9 /* IM_GPIO_BCLK_EINT */
1356#define WM8904_IM_GPIO_BCLK_EINT_WIDTH 1 /* IM_GPIO_BCLK_EINT */
1357#define WM8904_IM_WSEQ_EINT 0x0100 /* IM_WSEQ_EINT */
1358#define WM8904_IM_WSEQ_EINT_MASK 0x0100 /* IM_WSEQ_EINT */
1359#define WM8904_IM_WSEQ_EINT_SHIFT 8 /* IM_WSEQ_EINT */
1360#define WM8904_IM_WSEQ_EINT_WIDTH 1 /* IM_WSEQ_EINT */
1361#define WM8904_IM_GPIO3_EINT 0x0080 /* IM_GPIO3_EINT */
1362#define WM8904_IM_GPIO3_EINT_MASK 0x0080 /* IM_GPIO3_EINT */
1363#define WM8904_IM_GPIO3_EINT_SHIFT 7 /* IM_GPIO3_EINT */
1364#define WM8904_IM_GPIO3_EINT_WIDTH 1 /* IM_GPIO3_EINT */
1365#define WM8904_IM_GPIO2_EINT 0x0040 /* IM_GPIO2_EINT */
1366#define WM8904_IM_GPIO2_EINT_MASK 0x0040 /* IM_GPIO2_EINT */
1367#define WM8904_IM_GPIO2_EINT_SHIFT 6 /* IM_GPIO2_EINT */
1368#define WM8904_IM_GPIO2_EINT_WIDTH 1 /* IM_GPIO2_EINT */
1369#define WM8904_IM_GPIO1_EINT 0x0020 /* IM_GPIO1_EINT */
1370#define WM8904_IM_GPIO1_EINT_MASK 0x0020 /* IM_GPIO1_EINT */
1371#define WM8904_IM_GPIO1_EINT_SHIFT 5 /* IM_GPIO1_EINT */
1372#define WM8904_IM_GPIO1_EINT_WIDTH 1 /* IM_GPIO1_EINT */
1373#define WM8904_IM_GPI8_EINT 0x0010 /* IM_GPI8_EINT */
1374#define WM8904_IM_GPI8_EINT_MASK 0x0010 /* IM_GPI8_EINT */
1375#define WM8904_IM_GPI8_EINT_SHIFT 4 /* IM_GPI8_EINT */
1376#define WM8904_IM_GPI8_EINT_WIDTH 1 /* IM_GPI8_EINT */
1377#define WM8904_IM_GPI7_EINT 0x0008 /* IM_GPI7_EINT */
1378#define WM8904_IM_GPI7_EINT_MASK 0x0008 /* IM_GPI7_EINT */
1379#define WM8904_IM_GPI7_EINT_SHIFT 3 /* IM_GPI7_EINT */
1380#define WM8904_IM_GPI7_EINT_WIDTH 1 /* IM_GPI7_EINT */
1381#define WM8904_IM_FLL_LOCK_EINT 0x0004 /* IM_FLL_LOCK_EINT */
1382#define WM8904_IM_FLL_LOCK_EINT_MASK 0x0004 /* IM_FLL_LOCK_EINT */
1383#define WM8904_IM_FLL_LOCK_EINT_SHIFT 2 /* IM_FLL_LOCK_EINT */
1384#define WM8904_IM_FLL_LOCK_EINT_WIDTH 1 /* IM_FLL_LOCK_EINT */
1385#define WM8904_IM_MIC_SHRT_EINT 0x0002 /* IM_MIC_SHRT_EINT */
1386#define WM8904_IM_MIC_SHRT_EINT_MASK 0x0002 /* IM_MIC_SHRT_EINT */
1387#define WM8904_IM_MIC_SHRT_EINT_SHIFT 1 /* IM_MIC_SHRT_EINT */
1388#define WM8904_IM_MIC_SHRT_EINT_WIDTH 1 /* IM_MIC_SHRT_EINT */
1389#define WM8904_IM_MIC_DET_EINT 0x0001 /* IM_MIC_DET_EINT */
1390#define WM8904_IM_MIC_DET_EINT_MASK 0x0001 /* IM_MIC_DET_EINT */
1391#define WM8904_IM_MIC_DET_EINT_SHIFT 0 /* IM_MIC_DET_EINT */
1392#define WM8904_IM_MIC_DET_EINT_WIDTH 1 /* IM_MIC_DET_EINT */
1393
1394/*
1395 * R129 (0x81) - Interrupt Polarity
1396 */
1397#define WM8904_GPIO_BCLK_EINT_POL 0x0200 /* GPIO_BCLK_EINT_POL */
1398#define WM8904_GPIO_BCLK_EINT_POL_MASK 0x0200 /* GPIO_BCLK_EINT_POL */
1399#define WM8904_GPIO_BCLK_EINT_POL_SHIFT 9 /* GPIO_BCLK_EINT_POL */
1400#define WM8904_GPIO_BCLK_EINT_POL_WIDTH 1 /* GPIO_BCLK_EINT_POL */
1401#define WM8904_WSEQ_EINT_POL 0x0100 /* WSEQ_EINT_POL */
1402#define WM8904_WSEQ_EINT_POL_MASK 0x0100 /* WSEQ_EINT_POL */
1403#define WM8904_WSEQ_EINT_POL_SHIFT 8 /* WSEQ_EINT_POL */
1404#define WM8904_WSEQ_EINT_POL_WIDTH 1 /* WSEQ_EINT_POL */
1405#define WM8904_GPIO3_EINT_POL 0x0080 /* GPIO3_EINT_POL */
1406#define WM8904_GPIO3_EINT_POL_MASK 0x0080 /* GPIO3_EINT_POL */
1407#define WM8904_GPIO3_EINT_POL_SHIFT 7 /* GPIO3_EINT_POL */
1408#define WM8904_GPIO3_EINT_POL_WIDTH 1 /* GPIO3_EINT_POL */
1409#define WM8904_GPIO2_EINT_POL 0x0040 /* GPIO2_EINT_POL */
1410#define WM8904_GPIO2_EINT_POL_MASK 0x0040 /* GPIO2_EINT_POL */
1411#define WM8904_GPIO2_EINT_POL_SHIFT 6 /* GPIO2_EINT_POL */
1412#define WM8904_GPIO2_EINT_POL_WIDTH 1 /* GPIO2_EINT_POL */
1413#define WM8904_GPIO1_EINT_POL 0x0020 /* GPIO1_EINT_POL */
1414#define WM8904_GPIO1_EINT_POL_MASK 0x0020 /* GPIO1_EINT_POL */
1415#define WM8904_GPIO1_EINT_POL_SHIFT 5 /* GPIO1_EINT_POL */
1416#define WM8904_GPIO1_EINT_POL_WIDTH 1 /* GPIO1_EINT_POL */
1417#define WM8904_GPI8_EINT_POL 0x0010 /* GPI8_EINT_POL */
1418#define WM8904_GPI8_EINT_POL_MASK 0x0010 /* GPI8_EINT_POL */
1419#define WM8904_GPI8_EINT_POL_SHIFT 4 /* GPI8_EINT_POL */
1420#define WM8904_GPI8_EINT_POL_WIDTH 1 /* GPI8_EINT_POL */
1421#define WM8904_GPI7_EINT_POL 0x0008 /* GPI7_EINT_POL */
1422#define WM8904_GPI7_EINT_POL_MASK 0x0008 /* GPI7_EINT_POL */
1423#define WM8904_GPI7_EINT_POL_SHIFT 3 /* GPI7_EINT_POL */
1424#define WM8904_GPI7_EINT_POL_WIDTH 1 /* GPI7_EINT_POL */
1425#define WM8904_FLL_LOCK_EINT_POL 0x0004 /* FLL_LOCK_EINT_POL */
1426#define WM8904_FLL_LOCK_EINT_POL_MASK 0x0004 /* FLL_LOCK_EINT_POL */
1427#define WM8904_FLL_LOCK_EINT_POL_SHIFT 2 /* FLL_LOCK_EINT_POL */
1428#define WM8904_FLL_LOCK_EINT_POL_WIDTH 1 /* FLL_LOCK_EINT_POL */
1429#define WM8904_MIC_SHRT_EINT_POL 0x0002 /* MIC_SHRT_EINT_POL */
1430#define WM8904_MIC_SHRT_EINT_POL_MASK 0x0002 /* MIC_SHRT_EINT_POL */
1431#define WM8904_MIC_SHRT_EINT_POL_SHIFT 1 /* MIC_SHRT_EINT_POL */
1432#define WM8904_MIC_SHRT_EINT_POL_WIDTH 1 /* MIC_SHRT_EINT_POL */
1433#define WM8904_MIC_DET_EINT_POL 0x0001 /* MIC_DET_EINT_POL */
1434#define WM8904_MIC_DET_EINT_POL_MASK 0x0001 /* MIC_DET_EINT_POL */
1435#define WM8904_MIC_DET_EINT_POL_SHIFT 0 /* MIC_DET_EINT_POL */
1436#define WM8904_MIC_DET_EINT_POL_WIDTH 1 /* MIC_DET_EINT_POL */
1437
1438/*
1439 * R130 (0x82) - Interrupt Debounce
1440 */
1441#define WM8904_GPIO_BCLK_EINT_DB 0x0200 /* GPIO_BCLK_EINT_DB */
1442#define WM8904_GPIO_BCLK_EINT_DB_MASK 0x0200 /* GPIO_BCLK_EINT_DB */
1443#define WM8904_GPIO_BCLK_EINT_DB_SHIFT 9 /* GPIO_BCLK_EINT_DB */
1444#define WM8904_GPIO_BCLK_EINT_DB_WIDTH 1 /* GPIO_BCLK_EINT_DB */
1445#define WM8904_WSEQ_EINT_DB 0x0100 /* WSEQ_EINT_DB */
1446#define WM8904_WSEQ_EINT_DB_MASK 0x0100 /* WSEQ_EINT_DB */
1447#define WM8904_WSEQ_EINT_DB_SHIFT 8 /* WSEQ_EINT_DB */
1448#define WM8904_WSEQ_EINT_DB_WIDTH 1 /* WSEQ_EINT_DB */
1449#define WM8904_GPIO3_EINT_DB 0x0080 /* GPIO3_EINT_DB */
1450#define WM8904_GPIO3_EINT_DB_MASK 0x0080 /* GPIO3_EINT_DB */
1451#define WM8904_GPIO3_EINT_DB_SHIFT 7 /* GPIO3_EINT_DB */
1452#define WM8904_GPIO3_EINT_DB_WIDTH 1 /* GPIO3_EINT_DB */
1453#define WM8904_GPIO2_EINT_DB 0x0040 /* GPIO2_EINT_DB */
1454#define WM8904_GPIO2_EINT_DB_MASK 0x0040 /* GPIO2_EINT_DB */
1455#define WM8904_GPIO2_EINT_DB_SHIFT 6 /* GPIO2_EINT_DB */
1456#define WM8904_GPIO2_EINT_DB_WIDTH 1 /* GPIO2_EINT_DB */
1457#define WM8904_GPIO1_EINT_DB 0x0020 /* GPIO1_EINT_DB */
1458#define WM8904_GPIO1_EINT_DB_MASK 0x0020 /* GPIO1_EINT_DB */
1459#define WM8904_GPIO1_EINT_DB_SHIFT 5 /* GPIO1_EINT_DB */
1460#define WM8904_GPIO1_EINT_DB_WIDTH 1 /* GPIO1_EINT_DB */
1461#define WM8904_GPI8_EINT_DB 0x0010 /* GPI8_EINT_DB */
1462#define WM8904_GPI8_EINT_DB_MASK 0x0010 /* GPI8_EINT_DB */
1463#define WM8904_GPI8_EINT_DB_SHIFT 4 /* GPI8_EINT_DB */
1464#define WM8904_GPI8_EINT_DB_WIDTH 1 /* GPI8_EINT_DB */
1465#define WM8904_GPI7_EINT_DB 0x0008 /* GPI7_EINT_DB */
1466#define WM8904_GPI7_EINT_DB_MASK 0x0008 /* GPI7_EINT_DB */
1467#define WM8904_GPI7_EINT_DB_SHIFT 3 /* GPI7_EINT_DB */
1468#define WM8904_GPI7_EINT_DB_WIDTH 1 /* GPI7_EINT_DB */
1469#define WM8904_FLL_LOCK_EINT_DB 0x0004 /* FLL_LOCK_EINT_DB */
1470#define WM8904_FLL_LOCK_EINT_DB_MASK 0x0004 /* FLL_LOCK_EINT_DB */
1471#define WM8904_FLL_LOCK_EINT_DB_SHIFT 2 /* FLL_LOCK_EINT_DB */
1472#define WM8904_FLL_LOCK_EINT_DB_WIDTH 1 /* FLL_LOCK_EINT_DB */
1473#define WM8904_MIC_SHRT_EINT_DB 0x0002 /* MIC_SHRT_EINT_DB */
1474#define WM8904_MIC_SHRT_EINT_DB_MASK 0x0002 /* MIC_SHRT_EINT_DB */
1475#define WM8904_MIC_SHRT_EINT_DB_SHIFT 1 /* MIC_SHRT_EINT_DB */
1476#define WM8904_MIC_SHRT_EINT_DB_WIDTH 1 /* MIC_SHRT_EINT_DB */
1477#define WM8904_MIC_DET_EINT_DB 0x0001 /* MIC_DET_EINT_DB */
1478#define WM8904_MIC_DET_EINT_DB_MASK 0x0001 /* MIC_DET_EINT_DB */
1479#define WM8904_MIC_DET_EINT_DB_SHIFT 0 /* MIC_DET_EINT_DB */
1480#define WM8904_MIC_DET_EINT_DB_WIDTH 1 /* MIC_DET_EINT_DB */
1481
1482/*
1483 * R134 (0x86) - EQ1
1484 */
1485#define WM8904_EQ_ENA 0x0001 /* EQ_ENA */
1486#define WM8904_EQ_ENA_MASK 0x0001 /* EQ_ENA */
1487#define WM8904_EQ_ENA_SHIFT 0 /* EQ_ENA */
1488#define WM8904_EQ_ENA_WIDTH 1 /* EQ_ENA */
1489
1490/*
1491 * R135 (0x87) - EQ2
1492 */
1493#define WM8904_EQ_B1_GAIN_MASK 0x001F /* EQ_B1_GAIN - [4:0] */
1494#define WM8904_EQ_B1_GAIN_SHIFT 0 /* EQ_B1_GAIN - [4:0] */
1495#define WM8904_EQ_B1_GAIN_WIDTH 5 /* EQ_B1_GAIN - [4:0] */
1496
1497/*
1498 * R136 (0x88) - EQ3
1499 */
1500#define WM8904_EQ_B2_GAIN_MASK 0x001F /* EQ_B2_GAIN - [4:0] */
1501#define WM8904_EQ_B2_GAIN_SHIFT 0 /* EQ_B2_GAIN - [4:0] */
1502#define WM8904_EQ_B2_GAIN_WIDTH 5 /* EQ_B2_GAIN - [4:0] */
1503
1504/*
1505 * R137 (0x89) - EQ4
1506 */
1507#define WM8904_EQ_B3_GAIN_MASK 0x001F /* EQ_B3_GAIN - [4:0] */
1508#define WM8904_EQ_B3_GAIN_SHIFT 0 /* EQ_B3_GAIN - [4:0] */
1509#define WM8904_EQ_B3_GAIN_WIDTH 5 /* EQ_B3_GAIN - [4:0] */
1510
1511/*
1512 * R138 (0x8A) - EQ5
1513 */
1514#define WM8904_EQ_B4_GAIN_MASK 0x001F /* EQ_B4_GAIN - [4:0] */
1515#define WM8904_EQ_B4_GAIN_SHIFT 0 /* EQ_B4_GAIN - [4:0] */
1516#define WM8904_EQ_B4_GAIN_WIDTH 5 /* EQ_B4_GAIN - [4:0] */
1517
1518/*
1519 * R139 (0x8B) - EQ6
1520 */
1521#define WM8904_EQ_B5_GAIN_MASK 0x001F /* EQ_B5_GAIN - [4:0] */
1522#define WM8904_EQ_B5_GAIN_SHIFT 0 /* EQ_B5_GAIN - [4:0] */
1523#define WM8904_EQ_B5_GAIN_WIDTH 5 /* EQ_B5_GAIN - [4:0] */
1524
1525/*
1526 * R140 (0x8C) - EQ7
1527 */
1528#define WM8904_EQ_B1_A_MASK 0xFFFF /* EQ_B1_A - [15:0] */
1529#define WM8904_EQ_B1_A_SHIFT 0 /* EQ_B1_A - [15:0] */
1530#define WM8904_EQ_B1_A_WIDTH 16 /* EQ_B1_A - [15:0] */
1531
1532/*
1533 * R141 (0x8D) - EQ8
1534 */
1535#define WM8904_EQ_B1_B_MASK 0xFFFF /* EQ_B1_B - [15:0] */
1536#define WM8904_EQ_B1_B_SHIFT 0 /* EQ_B1_B - [15:0] */
1537#define WM8904_EQ_B1_B_WIDTH 16 /* EQ_B1_B - [15:0] */
1538
1539/*
1540 * R142 (0x8E) - EQ9
1541 */
1542#define WM8904_EQ_B1_PG_MASK 0xFFFF /* EQ_B1_PG - [15:0] */
1543#define WM8904_EQ_B1_PG_SHIFT 0 /* EQ_B1_PG - [15:0] */
1544#define WM8904_EQ_B1_PG_WIDTH 16 /* EQ_B1_PG - [15:0] */
1545
1546/*
1547 * R143 (0x8F) - EQ10
1548 */
1549#define WM8904_EQ_B2_A_MASK 0xFFFF /* EQ_B2_A - [15:0] */
1550#define WM8904_EQ_B2_A_SHIFT 0 /* EQ_B2_A - [15:0] */
1551#define WM8904_EQ_B2_A_WIDTH 16 /* EQ_B2_A - [15:0] */
1552
1553/*
1554 * R144 (0x90) - EQ11
1555 */
1556#define WM8904_EQ_B2_B_MASK 0xFFFF /* EQ_B2_B - [15:0] */
1557#define WM8904_EQ_B2_B_SHIFT 0 /* EQ_B2_B - [15:0] */
1558#define WM8904_EQ_B2_B_WIDTH 16 /* EQ_B2_B - [15:0] */
1559
1560/*
1561 * R145 (0x91) - EQ12
1562 */
1563#define WM8904_EQ_B2_C_MASK 0xFFFF /* EQ_B2_C - [15:0] */
1564#define WM8904_EQ_B2_C_SHIFT 0 /* EQ_B2_C - [15:0] */
1565#define WM8904_EQ_B2_C_WIDTH 16 /* EQ_B2_C - [15:0] */
1566
1567/*
1568 * R146 (0x92) - EQ13
1569 */
1570#define WM8904_EQ_B2_PG_MASK 0xFFFF /* EQ_B2_PG - [15:0] */
1571#define WM8904_EQ_B2_PG_SHIFT 0 /* EQ_B2_PG - [15:0] */
1572#define WM8904_EQ_B2_PG_WIDTH 16 /* EQ_B2_PG - [15:0] */
1573
1574/*
1575 * R147 (0x93) - EQ14
1576 */
1577#define WM8904_EQ_B3_A_MASK 0xFFFF /* EQ_B3_A - [15:0] */
1578#define WM8904_EQ_B3_A_SHIFT 0 /* EQ_B3_A - [15:0] */
1579#define WM8904_EQ_B3_A_WIDTH 16 /* EQ_B3_A - [15:0] */
1580
1581/*
1582 * R148 (0x94) - EQ15
1583 */
1584#define WM8904_EQ_B3_B_MASK 0xFFFF /* EQ_B3_B - [15:0] */
1585#define WM8904_EQ_B3_B_SHIFT 0 /* EQ_B3_B - [15:0] */
1586#define WM8904_EQ_B3_B_WIDTH 16 /* EQ_B3_B - [15:0] */
1587
1588/*
1589 * R149 (0x95) - EQ16
1590 */
1591#define WM8904_EQ_B3_C_MASK 0xFFFF /* EQ_B3_C - [15:0] */
1592#define WM8904_EQ_B3_C_SHIFT 0 /* EQ_B3_C - [15:0] */
1593#define WM8904_EQ_B3_C_WIDTH 16 /* EQ_B3_C - [15:0] */
1594
1595/*
1596 * R150 (0x96) - EQ17
1597 */
1598#define WM8904_EQ_B3_PG_MASK 0xFFFF /* EQ_B3_PG - [15:0] */
1599#define WM8904_EQ_B3_PG_SHIFT 0 /* EQ_B3_PG - [15:0] */
1600#define WM8904_EQ_B3_PG_WIDTH 16 /* EQ_B3_PG - [15:0] */
1601
1602/*
1603 * R151 (0x97) - EQ18
1604 */
1605#define WM8904_EQ_B4_A_MASK 0xFFFF /* EQ_B4_A - [15:0] */
1606#define WM8904_EQ_B4_A_SHIFT 0 /* EQ_B4_A - [15:0] */
1607#define WM8904_EQ_B4_A_WIDTH 16 /* EQ_B4_A - [15:0] */
1608
1609/*
1610 * R152 (0x98) - EQ19
1611 */
1612#define WM8904_EQ_B4_B_MASK 0xFFFF /* EQ_B4_B - [15:0] */
1613#define WM8904_EQ_B4_B_SHIFT 0 /* EQ_B4_B - [15:0] */
1614#define WM8904_EQ_B4_B_WIDTH 16 /* EQ_B4_B - [15:0] */
1615
1616/*
1617 * R153 (0x99) - EQ20
1618 */
1619#define WM8904_EQ_B4_C_MASK 0xFFFF /* EQ_B4_C - [15:0] */
1620#define WM8904_EQ_B4_C_SHIFT 0 /* EQ_B4_C - [15:0] */
1621#define WM8904_EQ_B4_C_WIDTH 16 /* EQ_B4_C - [15:0] */
1622
1623/*
1624 * R154 (0x9A) - EQ21
1625 */
1626#define WM8904_EQ_B4_PG_MASK 0xFFFF /* EQ_B4_PG - [15:0] */
1627#define WM8904_EQ_B4_PG_SHIFT 0 /* EQ_B4_PG - [15:0] */
1628#define WM8904_EQ_B4_PG_WIDTH 16 /* EQ_B4_PG - [15:0] */
1629
1630/*
1631 * R155 (0x9B) - EQ22
1632 */
1633#define WM8904_EQ_B5_A_MASK 0xFFFF /* EQ_B5_A - [15:0] */
1634#define WM8904_EQ_B5_A_SHIFT 0 /* EQ_B5_A - [15:0] */
1635#define WM8904_EQ_B5_A_WIDTH 16 /* EQ_B5_A - [15:0] */
1636
1637/*
1638 * R156 (0x9C) - EQ23
1639 */
1640#define WM8904_EQ_B5_B_MASK 0xFFFF /* EQ_B5_B - [15:0] */
1641#define WM8904_EQ_B5_B_SHIFT 0 /* EQ_B5_B - [15:0] */
1642#define WM8904_EQ_B5_B_WIDTH 16 /* EQ_B5_B - [15:0] */
1643
1644/*
1645 * R157 (0x9D) - EQ24
1646 */
1647#define WM8904_EQ_B5_PG_MASK 0xFFFF /* EQ_B5_PG - [15:0] */
1648#define WM8904_EQ_B5_PG_SHIFT 0 /* EQ_B5_PG - [15:0] */
1649#define WM8904_EQ_B5_PG_WIDTH 16 /* EQ_B5_PG - [15:0] */
1650
1651/*
1652 * R161 (0xA1) - Control Interface Test 1
1653 */
1654#define WM8904_USER_KEY 0x0002 /* USER_KEY */
1655#define WM8904_USER_KEY_MASK 0x0002 /* USER_KEY */
1656#define WM8904_USER_KEY_SHIFT 1 /* USER_KEY */
1657#define WM8904_USER_KEY_WIDTH 1 /* USER_KEY */
1658
1659/*
1660 * R204 (0xCC) - Analogue Output Bias 0
1661 */
1662#define WM8904_PGA_BIAS_MASK 0x0070 /* PGA_BIAS - [6:4] */
1663#define WM8904_PGA_BIAS_SHIFT 4 /* PGA_BIAS - [6:4] */
1664#define WM8904_PGA_BIAS_WIDTH 3 /* PGA_BIAS - [6:4] */
1665
1666/*
1667 * R247 (0xF7) - FLL NCO Test 0
1668 */
1669#define WM8904_FLL_FRC_NCO 0x0001 /* FLL_FRC_NCO */
1670#define WM8904_FLL_FRC_NCO_MASK 0x0001 /* FLL_FRC_NCO */
1671#define WM8904_FLL_FRC_NCO_SHIFT 0 /* FLL_FRC_NCO */
1672#define WM8904_FLL_FRC_NCO_WIDTH 1 /* FLL_FRC_NCO */
1673
1674/*
1675 * R248 (0xF8) - FLL NCO Test 1
1676 */
1677#define WM8904_FLL_FRC_NCO_VAL_MASK 0x003F /* FLL_FRC_NCO_VAL - [5:0] */
1678#define WM8904_FLL_FRC_NCO_VAL_SHIFT 0 /* FLL_FRC_NCO_VAL - [5:0] */
1679#define WM8904_FLL_FRC_NCO_VAL_WIDTH 6 /* FLL_FRC_NCO_VAL - [5:0] */
1680
1681#endif
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
new file mode 100644
index 00000000000..615dab2b62e
--- /dev/null
+++ b/sound/soc/codecs/wm8955.c
@@ -0,0 +1,1151 @@
1/*
2 * wm8955.c -- WM8955 ALSA SoC Audio driver
3 *
4 * Copyright 2009 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/pm.h>
18#include <linux/i2c.h>
19#include <linux/platform_device.h>
20#include <linux/regulator/consumer.h>
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26#include <sound/initval.h>
27#include <sound/tlv.h>
28#include <sound/wm8955.h>
29
30#include "wm8955.h"
31
32static struct snd_soc_codec *wm8955_codec;
33struct snd_soc_codec_device soc_codec_dev_wm8955;
34
35#define WM8955_NUM_SUPPLIES 4
36static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = {
37 "DCVDD",
38 "DBVDD",
39 "HPVDD",
40 "AVDD",
41};
42
43/* codec private data */
44struct wm8955_priv {
45 struct snd_soc_codec codec;
46 u16 reg_cache[WM8955_MAX_REGISTER + 1];
47
48 unsigned int mclk_rate;
49
50 int deemph;
51 int fs;
52
53 struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES];
54
55 struct wm8955_pdata *pdata;
56};
57
58static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = {
59 0x0000, /* R0 */
60 0x0000, /* R1 */
61 0x0079, /* R2 - LOUT1 volume */
62 0x0079, /* R3 - ROUT1 volume */
63 0x0000, /* R4 */
64 0x0008, /* R5 - DAC Control */
65 0x0000, /* R6 */
66 0x000A, /* R7 - Audio Interface */
67 0x0000, /* R8 - Sample Rate */
68 0x0000, /* R9 */
69 0x00FF, /* R10 - Left DAC volume */
70 0x00FF, /* R11 - Right DAC volume */
71 0x000F, /* R12 - Bass control */
72 0x000F, /* R13 - Treble control */
73 0x0000, /* R14 */
74 0x0000, /* R15 - Reset */
75 0x0000, /* R16 */
76 0x0000, /* R17 */
77 0x0000, /* R18 */
78 0x0000, /* R19 */
79 0x0000, /* R20 */
80 0x0000, /* R21 */
81 0x0000, /* R22 */
82 0x00C1, /* R23 - Additional control (1) */
83 0x0000, /* R24 - Additional control (2) */
84 0x0000, /* R25 - Power Management (1) */
85 0x0000, /* R26 - Power Management (2) */
86 0x0000, /* R27 - Additional Control (3) */
87 0x0000, /* R28 */
88 0x0000, /* R29 */
89 0x0000, /* R30 */
90 0x0000, /* R31 */
91 0x0000, /* R32 */
92 0x0000, /* R33 */
93 0x0050, /* R34 - Left out Mix (1) */
94 0x0050, /* R35 - Left out Mix (2) */
95 0x0050, /* R36 - Right out Mix (1) */
96 0x0050, /* R37 - Right Out Mix (2) */
97 0x0050, /* R38 - Mono out Mix (1) */
98 0x0050, /* R39 - Mono out Mix (2) */
99 0x0079, /* R40 - LOUT2 volume */
100 0x0079, /* R41 - ROUT2 volume */
101 0x0079, /* R42 - MONOOUT volume */
102 0x0000, /* R43 - Clocking / PLL */
103 0x0103, /* R44 - PLL Control 1 */
104 0x0024, /* R45 - PLL Control 2 */
105 0x01BA, /* R46 - PLL Control 3 */
106 0x0000, /* R47 */
107 0x0000, /* R48 */
108 0x0000, /* R49 */
109 0x0000, /* R50 */
110 0x0000, /* R51 */
111 0x0000, /* R52 */
112 0x0000, /* R53 */
113 0x0000, /* R54 */
114 0x0000, /* R55 */
115 0x0000, /* R56 */
116 0x0000, /* R57 */
117 0x0000, /* R58 */
118 0x0000, /* R59 - PLL Control 4 */
119};
120
121static int wm8955_reset(struct snd_soc_codec *codec)
122{
123 return snd_soc_write(codec, WM8955_RESET, 0);
124}
125
126struct pll_factors {
127 int n;
128 int k;
129 int outdiv;
130};
131
132/* The size in bits of the FLL divide multiplied by 10
133 * to allow rounding later */
134#define FIXED_FLL_SIZE ((1 << 22) * 10)
135
136static int wm8995_pll_factors(struct device *dev,
137 int Fref, int Fout, struct pll_factors *pll)
138{
139 u64 Kpart;
140 unsigned int K, Ndiv, Nmod, target;
141
142 dev_dbg(dev, "Fref=%u Fout=%u\n", Fref, Fout);
143
144 /* The oscilator should run at should be 90-100MHz, and
145 * there's a divide by 4 plus an optional divide by 2 in the
146 * output path to generate the system clock. The clock table
147 * is sortd so we should always generate a suitable target. */
148 target = Fout * 4;
149 if (target < 90000000) {
150 pll->outdiv = 1;
151 target *= 2;
152 } else {
153 pll->outdiv = 0;
154 }
155
156 WARN_ON(target < 90000000 || target > 100000000);
157
158 dev_dbg(dev, "Fvco=%dHz\n", target);
159
160 /* Now, calculate N.K */
161 Ndiv = target / Fref;
162
163 pll->n = Ndiv;
164 Nmod = target % Fref;
165 dev_dbg(dev, "Nmod=%d\n", Nmod);
166
167 /* Calculate fractional part - scale up so we can round. */
168 Kpart = FIXED_FLL_SIZE * (long long)Nmod;
169
170 do_div(Kpart, Fref);
171
172 K = Kpart & 0xFFFFFFFF;
173
174 if ((K % 10) >= 5)
175 K += 5;
176
177 /* Move down to proper range now rounding is done */
178 pll->k = K / 10;
179
180 dev_dbg(dev, "N=%x K=%x OUTDIV=%x\n", pll->n, pll->k, pll->outdiv);
181
182 return 0;
183}
184
185/* Lookup table specifiying SRATE (table 25 in datasheet); some of the
186 * output frequencies have been rounded to the standard frequencies
187 * they are intended to match where the error is slight. */
188static struct {
189 int mclk;
190 int fs;
191 int usb;
192 int sr;
193} clock_cfgs[] = {
194 { 18432000, 8000, 0, 3, },
195 { 18432000, 12000, 0, 9, },
196 { 18432000, 16000, 0, 11, },
197 { 18432000, 24000, 0, 29, },
198 { 18432000, 32000, 0, 13, },
199 { 18432000, 48000, 0, 1, },
200 { 18432000, 96000, 0, 15, },
201
202 { 16934400, 8018, 0, 19, },
203 { 16934400, 11025, 0, 25, },
204 { 16934400, 22050, 0, 27, },
205 { 16934400, 44100, 0, 17, },
206 { 16934400, 88200, 0, 31, },
207
208 { 12000000, 8000, 1, 2, },
209 { 12000000, 11025, 1, 25, },
210 { 12000000, 12000, 1, 8, },
211 { 12000000, 16000, 1, 10, },
212 { 12000000, 22050, 1, 27, },
213 { 12000000, 24000, 1, 28, },
214 { 12000000, 32000, 1, 12, },
215 { 12000000, 44100, 1, 17, },
216 { 12000000, 48000, 1, 0, },
217 { 12000000, 88200, 1, 31, },
218 { 12000000, 96000, 1, 14, },
219
220 { 12288000, 8000, 0, 2, },
221 { 12288000, 12000, 0, 8, },
222 { 12288000, 16000, 0, 10, },
223 { 12288000, 24000, 0, 28, },
224 { 12288000, 32000, 0, 12, },
225 { 12288000, 48000, 0, 0, },
226 { 12288000, 96000, 0, 14, },
227
228 { 12289600, 8018, 0, 18, },
229 { 12289600, 11025, 0, 24, },
230 { 12289600, 22050, 0, 26, },
231 { 11289600, 44100, 0, 16, },
232 { 11289600, 88200, 0, 31, },
233};
234
235static int wm8955_configure_clocking(struct snd_soc_codec *codec)
236{
237 struct wm8955_priv *wm8955 = codec->private_data;
238 int i, ret, val;
239 int clocking = 0;
240 int srate = 0;
241 int sr = -1;
242 struct pll_factors pll;
243
244 /* If we're not running a sample rate currently just pick one */
245 if (wm8955->fs == 0)
246 wm8955->fs = 8000;
247
248 /* Can we generate an exact output? */
249 for (i = 0; i < ARRAY_SIZE(clock_cfgs); i++) {
250 if (wm8955->fs != clock_cfgs[i].fs)
251 continue;
252 sr = i;
253
254 if (wm8955->mclk_rate == clock_cfgs[i].mclk)
255 break;
256 }
257
258 /* We should never get here with an unsupported sample rate */
259 if (sr == -1) {
260 dev_err(codec->dev, "Sample rate %dHz unsupported\n",
261 wm8955->fs);
262 WARN_ON(sr == -1);
263 return -EINVAL;
264 }
265
266 if (i == ARRAY_SIZE(clock_cfgs)) {
267 /* If we can't generate the right clock from MCLK then
268 * we should configure the PLL to supply us with an
269 * appropriate clock.
270 */
271 clocking |= WM8955_MCLKSEL;
272
273 /* Use the last divider configuration we saw for the
274 * sample rate. */
275 ret = wm8995_pll_factors(codec->dev, wm8955->mclk_rate,
276 clock_cfgs[sr].mclk, &pll);
277 if (ret != 0) {
278 dev_err(codec->dev,
279 "Unable to generate %dHz from %dHz MCLK\n",
280 wm8955->fs, wm8955->mclk_rate);
281 return -EINVAL;
282 }
283
284 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_1,
285 WM8955_N_MASK | WM8955_K_21_18_MASK,
286 (pll.n << WM8955_N_SHIFT) |
287 pll.k >> 18);
288 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
289 WM8955_K_17_9_MASK,
290 (pll.k >> 9) & WM8955_K_17_9_MASK);
291 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
292 WM8955_K_8_0_MASK,
293 pll.k & WM8955_K_8_0_MASK);
294 if (pll.k)
295 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
296 WM8955_KEN, WM8955_KEN);
297 else
298 snd_soc_update_bits(codec, WM8955_PLL_CONTROL_4,
299 WM8955_KEN, 0);
300
301 if (pll.outdiv)
302 val = WM8955_PLL_RB | WM8955_PLLOUTDIV2;
303 else
304 val = WM8955_PLL_RB;
305
306 /* Now start the PLL running */
307 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
308 WM8955_PLL_RB | WM8955_PLLOUTDIV2, val);
309 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
310 WM8955_PLLEN, WM8955_PLLEN);
311 }
312
313 srate = clock_cfgs[sr].usb | (clock_cfgs[sr].sr << WM8955_SR_SHIFT);
314
315 snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
316 WM8955_USB | WM8955_SR_MASK, srate);
317 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
318 WM8955_MCLKSEL, clocking);
319
320 return 0;
321}
322
323static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
324 struct snd_kcontrol *kcontrol, int event)
325{
326 struct snd_soc_codec *codec = w->codec;
327 int ret = 0;
328
329 /* Always disable the clocks - if we're doing reconfiguration this
330 * avoids misclocking.
331 */
332 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
333 WM8955_DIGENB, 0);
334 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
335 WM8955_PLL_RB | WM8955_PLLEN, 0);
336
337 switch (event) {
338 case SND_SOC_DAPM_POST_PMD:
339 break;
340 case SND_SOC_DAPM_PRE_PMU:
341 ret = wm8955_configure_clocking(codec);
342 break;
343 default:
344 ret = -EINVAL;
345 break;
346 }
347
348 return ret;
349}
350
351static int deemph_settings[] = { 0, 32000, 44100, 48000 };
352
353static int wm8955_set_deemph(struct snd_soc_codec *codec)
354{
355 struct wm8955_priv *wm8955 = codec->private_data;
356 int val, i, best;
357
358 /* If we're using deemphasis select the nearest available sample
359 * rate.
360 */
361 if (wm8955->deemph) {
362 best = 1;
363 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
364 if (abs(deemph_settings[i] - wm8955->fs) <
365 abs(deemph_settings[best] - wm8955->fs))
366 best = i;
367 }
368
369 val = best << WM8955_DEEMPH_SHIFT;
370 } else {
371 val = 0;
372 }
373
374 dev_dbg(codec->dev, "Set deemphasis %d\n", val);
375
376 return snd_soc_update_bits(codec, WM8955_DAC_CONTROL,
377 WM8955_DEEMPH_MASK, val);
378}
379
380static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
381 struct snd_ctl_elem_value *ucontrol)
382{
383 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
384 struct wm8955_priv *wm8955 = codec->private_data;
385
386 return wm8955->deemph;
387}
388
389static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
390 struct snd_ctl_elem_value *ucontrol)
391{
392 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
393 struct wm8955_priv *wm8955 = codec->private_data;
394 int deemph = ucontrol->value.enumerated.item[0];
395
396 if (deemph > 1)
397 return -EINVAL;
398
399 wm8955->deemph = deemph;
400
401 return wm8955_set_deemph(codec);
402}
403
404static const char *bass_mode_text[] = {
405 "Linear", "Adaptive",
406};
407
408static const struct soc_enum bass_mode =
409 SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text);
410
411static const char *bass_cutoff_text[] = {
412 "Low", "High"
413};
414
415static const struct soc_enum bass_cutoff =
416 SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text);
417
418static const char *treble_cutoff_text[] = {
419 "High", "Low"
420};
421
422static const struct soc_enum treble_cutoff =
423 SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text);
424
425static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
426static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0);
427static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
428static const DECLARE_TLV_DB_SCALE(mono_tlv, -2100, 300, 0);
429static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
430static const DECLARE_TLV_DB_SCALE(treble_tlv, -1200, 150, 1);
431
432static const struct snd_kcontrol_new wm8955_snd_controls[] = {
433SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8955_LEFT_DAC_VOLUME,
434 WM8955_RIGHT_DAC_VOLUME, 0, 255, 0, digital_tlv),
435SOC_SINGLE_TLV("Playback Attenuation Volume", WM8955_DAC_CONTROL, 7, 1, 1,
436 atten_tlv),
437SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
438 wm8955_get_deemph, wm8955_put_deemph),
439
440SOC_ENUM("Bass Mode", bass_mode),
441SOC_ENUM("Bass Cutoff", bass_cutoff),
442SOC_SINGLE("Bass Volume", WM8955_BASS_CONTROL, 0, 15, 1),
443
444SOC_ENUM("Treble Cutoff", treble_cutoff),
445SOC_SINGLE_TLV("Treble Volume", WM8955_TREBLE_CONTROL, 0, 14, 1, treble_tlv),
446
447SOC_SINGLE_TLV("Left Bypass Volume", WM8955_LEFT_OUT_MIX_1, 4, 7, 1,
448 bypass_tlv),
449SOC_SINGLE_TLV("Left Mono Volume", WM8955_LEFT_OUT_MIX_2, 4, 7, 1,
450 bypass_tlv),
451
452SOC_SINGLE_TLV("Right Mono Volume", WM8955_RIGHT_OUT_MIX_1, 4, 7, 1,
453 bypass_tlv),
454SOC_SINGLE_TLV("Right Bypass Volume", WM8955_RIGHT_OUT_MIX_2, 4, 7, 1,
455 bypass_tlv),
456
457/* Not a stereo pair so they line up with the DAPM switches */
458SOC_SINGLE_TLV("Mono Left Bypass Volume", WM8955_MONO_OUT_MIX_1, 4, 7, 1,
459 mono_tlv),
460SOC_SINGLE_TLV("Mono Right Bypass Volume", WM8955_MONO_OUT_MIX_2, 4, 7, 1,
461 mono_tlv),
462
463SOC_DOUBLE_R_TLV("Headphone Volume", WM8955_LOUT1_VOLUME,
464 WM8955_ROUT1_VOLUME, 0, 127, 0, out_tlv),
465SOC_DOUBLE_R("Headphone ZC Switch", WM8955_LOUT1_VOLUME,
466 WM8955_ROUT1_VOLUME, 7, 1, 0),
467
468SOC_DOUBLE_R_TLV("Speaker Volume", WM8955_LOUT2_VOLUME,
469 WM8955_ROUT2_VOLUME, 0, 127, 0, out_tlv),
470SOC_DOUBLE_R("Speaker ZC Switch", WM8955_LOUT2_VOLUME,
471 WM8955_ROUT2_VOLUME, 7, 1, 0),
472
473SOC_SINGLE_TLV("Mono Volume", WM8955_MONOOUT_VOLUME, 0, 127, 0, out_tlv),
474SOC_SINGLE("Mono ZC Switch", WM8955_MONOOUT_VOLUME, 7, 1, 0),
475};
476
477static const struct snd_kcontrol_new lmixer[] = {
478SOC_DAPM_SINGLE("Playback Switch", WM8955_LEFT_OUT_MIX_1, 8, 1, 0),
479SOC_DAPM_SINGLE("Bypass Switch", WM8955_LEFT_OUT_MIX_1, 7, 1, 0),
480SOC_DAPM_SINGLE("Right Playback Switch", WM8955_LEFT_OUT_MIX_2, 8, 1, 0),
481SOC_DAPM_SINGLE("Mono Switch", WM8955_LEFT_OUT_MIX_2, 7, 1, 0),
482};
483
484static const struct snd_kcontrol_new rmixer[] = {
485SOC_DAPM_SINGLE("Left Playback Switch", WM8955_RIGHT_OUT_MIX_1, 8, 1, 0),
486SOC_DAPM_SINGLE("Mono Switch", WM8955_RIGHT_OUT_MIX_1, 7, 1, 0),
487SOC_DAPM_SINGLE("Playback Switch", WM8955_RIGHT_OUT_MIX_2, 8, 1, 0),
488SOC_DAPM_SINGLE("Bypass Switch", WM8955_RIGHT_OUT_MIX_2, 7, 1, 0),
489};
490
491static const struct snd_kcontrol_new mmixer[] = {
492SOC_DAPM_SINGLE("Left Playback Switch", WM8955_MONO_OUT_MIX_1, 8, 1, 0),
493SOC_DAPM_SINGLE("Left Bypass Switch", WM8955_MONO_OUT_MIX_1, 7, 1, 0),
494SOC_DAPM_SINGLE("Right Playback Switch", WM8955_MONO_OUT_MIX_2, 8, 1, 0),
495SOC_DAPM_SINGLE("Right Bypass Switch", WM8955_MONO_OUT_MIX_2, 7, 1, 0),
496};
497
498static const struct snd_soc_dapm_widget wm8955_dapm_widgets[] = {
499SND_SOC_DAPM_INPUT("MONOIN-"),
500SND_SOC_DAPM_INPUT("MONOIN+"),
501SND_SOC_DAPM_INPUT("LINEINR"),
502SND_SOC_DAPM_INPUT("LINEINL"),
503
504SND_SOC_DAPM_PGA("Mono Input", SND_SOC_NOPM, 0, 0, NULL, 0),
505
506SND_SOC_DAPM_SUPPLY("SYSCLK", WM8955_POWER_MANAGEMENT_1, 0, 1, wm8955_sysclk,
507 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
508SND_SOC_DAPM_SUPPLY("TSDEN", WM8955_ADDITIONAL_CONTROL_1, 8, 0, NULL, 0),
509
510SND_SOC_DAPM_DAC("DACL", "Playback", WM8955_POWER_MANAGEMENT_2, 8, 0),
511SND_SOC_DAPM_DAC("DACR", "Playback", WM8955_POWER_MANAGEMENT_2, 7, 0),
512
513SND_SOC_DAPM_PGA("LOUT1 PGA", WM8955_POWER_MANAGEMENT_2, 6, 0, NULL, 0),
514SND_SOC_DAPM_PGA("ROUT1 PGA", WM8955_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
515SND_SOC_DAPM_PGA("LOUT2 PGA", WM8955_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
516SND_SOC_DAPM_PGA("ROUT2 PGA", WM8955_POWER_MANAGEMENT_2, 3, 0, NULL, 0),
517SND_SOC_DAPM_PGA("MOUT PGA", WM8955_POWER_MANAGEMENT_2, 2, 0, NULL, 0),
518SND_SOC_DAPM_PGA("OUT3 PGA", WM8955_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
519
520/* The names are chosen to make the control names nice */
521SND_SOC_DAPM_MIXER("Left", SND_SOC_NOPM, 0, 0,
522 lmixer, ARRAY_SIZE(lmixer)),
523SND_SOC_DAPM_MIXER("Right", SND_SOC_NOPM, 0, 0,
524 rmixer, ARRAY_SIZE(rmixer)),
525SND_SOC_DAPM_MIXER("Mono", SND_SOC_NOPM, 0, 0,
526 mmixer, ARRAY_SIZE(mmixer)),
527
528SND_SOC_DAPM_OUTPUT("LOUT1"),
529SND_SOC_DAPM_OUTPUT("ROUT1"),
530SND_SOC_DAPM_OUTPUT("LOUT2"),
531SND_SOC_DAPM_OUTPUT("ROUT2"),
532SND_SOC_DAPM_OUTPUT("MONOOUT"),
533SND_SOC_DAPM_OUTPUT("OUT3"),
534};
535
536static const struct snd_soc_dapm_route wm8955_intercon[] = {
537 { "DACL", NULL, "SYSCLK" },
538 { "DACR", NULL, "SYSCLK" },
539
540 { "Mono Input", NULL, "MONOIN-" },
541 { "Mono Input", NULL, "MONOIN+" },
542
543 { "Left", "Playback Switch", "DACL" },
544 { "Left", "Right Playback Switch", "DACR" },
545 { "Left", "Bypass Switch", "LINEINL" },
546 { "Left", "Mono Switch", "Mono Input" },
547
548 { "Right", "Playback Switch", "DACR" },
549 { "Right", "Left Playback Switch", "DACL" },
550 { "Right", "Bypass Switch", "LINEINR" },
551 { "Right", "Mono Switch", "Mono Input" },
552
553 { "Mono", "Left Playback Switch", "DACL" },
554 { "Mono", "Right Playback Switch", "DACR" },
555 { "Mono", "Left Bypass Switch", "LINEINL" },
556 { "Mono", "Right Bypass Switch", "LINEINR" },
557
558 { "LOUT1 PGA", NULL, "Left" },
559 { "LOUT1", NULL, "TSDEN" },
560 { "LOUT1", NULL, "LOUT1 PGA" },
561
562 { "ROUT1 PGA", NULL, "Right" },
563 { "ROUT1", NULL, "TSDEN" },
564 { "ROUT1", NULL, "ROUT1 PGA" },
565
566 { "LOUT2 PGA", NULL, "Left" },
567 { "LOUT2", NULL, "TSDEN" },
568 { "LOUT2", NULL, "LOUT2 PGA" },
569
570 { "ROUT2 PGA", NULL, "Right" },
571 { "ROUT2", NULL, "TSDEN" },
572 { "ROUT2", NULL, "ROUT2 PGA" },
573
574 { "MOUT PGA", NULL, "Mono" },
575 { "MONOOUT", NULL, "MOUT PGA" },
576
577 /* OUT3 not currently implemented */
578 { "OUT3", NULL, "OUT3 PGA" },
579};
580
581static int wm8955_add_widgets(struct snd_soc_codec *codec)
582{
583 snd_soc_add_controls(codec, wm8955_snd_controls,
584 ARRAY_SIZE(wm8955_snd_controls));
585
586 snd_soc_dapm_new_controls(codec, wm8955_dapm_widgets,
587 ARRAY_SIZE(wm8955_dapm_widgets));
588
589 snd_soc_dapm_add_routes(codec, wm8955_intercon,
590 ARRAY_SIZE(wm8955_intercon));
591
592 return 0;
593}
594
595static int wm8955_hw_params(struct snd_pcm_substream *substream,
596 struct snd_pcm_hw_params *params,
597 struct snd_soc_dai *dai)
598{
599 struct snd_soc_codec *codec = dai->codec;
600 struct wm8955_priv *wm8955 = codec->private_data;
601 int ret;
602 int wl;
603
604 switch (params_format(params)) {
605 case SNDRV_PCM_FORMAT_S16_LE:
606 wl = 0;
607 break;
608 case SNDRV_PCM_FORMAT_S20_3LE:
609 wl = 0x4;
610 break;
611 case SNDRV_PCM_FORMAT_S24_LE:
612 wl = 0x8;
613 break;
614 case SNDRV_PCM_FORMAT_S32_LE:
615 wl = 0xc;
616 break;
617 default:
618 return -EINVAL;
619 }
620 snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
621 WM8955_WL_MASK, wl);
622
623 wm8955->fs = params_rate(params);
624 wm8955_set_deemph(codec);
625
626 /* If the chip is clocked then disable the clocks and force a
627 * reconfiguration, otherwise DAPM will power up the
628 * clocks for us later. */
629 ret = snd_soc_read(codec, WM8955_POWER_MANAGEMENT_1);
630 if (ret < 0)
631 return ret;
632 if (ret & WM8955_DIGENB) {
633 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
634 WM8955_DIGENB, 0);
635 snd_soc_update_bits(codec, WM8955_CLOCKING_PLL,
636 WM8955_PLL_RB | WM8955_PLLEN, 0);
637
638 wm8955_configure_clocking(codec);
639 }
640
641 return 0;
642}
643
644
645static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
646 unsigned int freq, int dir)
647{
648 struct snd_soc_codec *codec = dai->codec;
649 struct wm8955_priv *priv = codec->private_data;
650 int div;
651
652 switch (clk_id) {
653 case WM8955_CLK_MCLK:
654 if (freq > 15000000) {
655 priv->mclk_rate = freq /= 2;
656 div = WM8955_MCLKDIV2;
657 } else {
658 priv->mclk_rate = freq;
659 div = 0;
660 }
661
662 snd_soc_update_bits(codec, WM8955_SAMPLE_RATE,
663 WM8955_MCLKDIV2, div);
664 break;
665
666 default:
667 return -EINVAL;
668 }
669
670 dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
671
672 return 0;
673}
674
675static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
676{
677 struct snd_soc_codec *codec = dai->codec;
678 u16 aif = 0;
679
680 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
681 case SND_SOC_DAIFMT_CBS_CFS:
682 break;
683 case SND_SOC_DAIFMT_CBM_CFM:
684 aif |= WM8955_MS;
685 break;
686 default:
687 return -EINVAL;
688 }
689
690 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
691 case SND_SOC_DAIFMT_DSP_B:
692 aif |= WM8955_LRP;
693 case SND_SOC_DAIFMT_DSP_A:
694 aif |= 0x3;
695 break;
696 case SND_SOC_DAIFMT_I2S:
697 aif |= 0x2;
698 break;
699 case SND_SOC_DAIFMT_RIGHT_J:
700 break;
701 case SND_SOC_DAIFMT_LEFT_J:
702 aif |= 0x1;
703 break;
704 default:
705 return -EINVAL;
706 }
707
708 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
709 case SND_SOC_DAIFMT_DSP_A:
710 case SND_SOC_DAIFMT_DSP_B:
711 /* frame inversion not valid for DSP modes */
712 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
713 case SND_SOC_DAIFMT_NB_NF:
714 break;
715 case SND_SOC_DAIFMT_IB_NF:
716 aif |= WM8955_BCLKINV;
717 break;
718 default:
719 return -EINVAL;
720 }
721 break;
722
723 case SND_SOC_DAIFMT_I2S:
724 case SND_SOC_DAIFMT_RIGHT_J:
725 case SND_SOC_DAIFMT_LEFT_J:
726 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
727 case SND_SOC_DAIFMT_NB_NF:
728 break;
729 case SND_SOC_DAIFMT_IB_IF:
730 aif |= WM8955_BCLKINV | WM8955_LRP;
731 break;
732 case SND_SOC_DAIFMT_IB_NF:
733 aif |= WM8955_BCLKINV;
734 break;
735 case SND_SOC_DAIFMT_NB_IF:
736 aif |= WM8955_LRP;
737 break;
738 default:
739 return -EINVAL;
740 }
741 break;
742 default:
743 return -EINVAL;
744 }
745
746 snd_soc_update_bits(codec, WM8955_AUDIO_INTERFACE,
747 WM8955_MS | WM8955_FORMAT_MASK | WM8955_BCLKINV |
748 WM8955_LRP, aif);
749
750 return 0;
751}
752
753
754static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute)
755{
756 struct snd_soc_codec *codec = codec_dai->codec;
757 int val;
758
759 if (mute)
760 val = WM8955_DACMU;
761 else
762 val = 0;
763
764 snd_soc_update_bits(codec, WM8955_DAC_CONTROL, WM8955_DACMU, val);
765
766 return 0;
767}
768
769static int wm8955_set_bias_level(struct snd_soc_codec *codec,
770 enum snd_soc_bias_level level)
771{
772 struct wm8955_priv *wm8955 = codec->private_data;
773 int ret, i;
774
775 switch (level) {
776 case SND_SOC_BIAS_ON:
777 break;
778
779 case SND_SOC_BIAS_PREPARE:
780 /* VMID resistance 2*50k */
781 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
782 WM8955_VMIDSEL_MASK,
783 0x1 << WM8955_VMIDSEL_SHIFT);
784
785 /* Default bias current */
786 snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
787 WM8955_VSEL_MASK,
788 0x2 << WM8955_VSEL_SHIFT);
789 break;
790
791 case SND_SOC_BIAS_STANDBY:
792 if (codec->bias_level == SND_SOC_BIAS_OFF) {
793 ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
794 wm8955->supplies);
795 if (ret != 0) {
796 dev_err(codec->dev,
797 "Failed to enable supplies: %d\n",
798 ret);
799 return ret;
800 }
801
802 /* Sync back cached values if they're
803 * different from the hardware default.
804 */
805 for (i = 0; i < ARRAY_SIZE(wm8955->reg_cache); i++) {
806 if (i == WM8955_RESET)
807 continue;
808
809 if (wm8955->reg_cache[i] == wm8955_reg[i])
810 continue;
811
812 snd_soc_write(codec, i, wm8955->reg_cache[i]);
813 }
814
815 /* Enable VREF and VMID */
816 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
817 WM8955_VREF |
818 WM8955_VMIDSEL_MASK,
819 WM8955_VREF |
820 0x3 << WM8955_VREF_SHIFT);
821
822 /* Let VMID ramp */
823 msleep(500);
824
825 /* High resistance VROI to maintain outputs */
826 snd_soc_update_bits(codec,
827 WM8955_ADDITIONAL_CONTROL_3,
828 WM8955_VROI, WM8955_VROI);
829 }
830
831 /* Maintain VMID with 2*250k */
832 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
833 WM8955_VMIDSEL_MASK,
834 0x2 << WM8955_VMIDSEL_SHIFT);
835
836 /* Minimum bias current */
837 snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_1,
838 WM8955_VSEL_MASK, 0);
839 break;
840
841 case SND_SOC_BIAS_OFF:
842 /* Low resistance VROI to help discharge */
843 snd_soc_update_bits(codec,
844 WM8955_ADDITIONAL_CONTROL_3,
845 WM8955_VROI, 0);
846
847 /* Turn off VMID and VREF */
848 snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1,
849 WM8955_VREF |
850 WM8955_VMIDSEL_MASK, 0);
851
852 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies),
853 wm8955->supplies);
854 break;
855 }
856 codec->bias_level = level;
857 return 0;
858}
859
860#define WM8955_RATES SNDRV_PCM_RATE_8000_96000
861
862#define WM8955_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
863 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
864
865static struct snd_soc_dai_ops wm8955_dai_ops = {
866 .set_sysclk = wm8955_set_sysclk,
867 .set_fmt = wm8955_set_fmt,
868 .hw_params = wm8955_hw_params,
869 .digital_mute = wm8955_digital_mute,
870};
871
872struct snd_soc_dai wm8955_dai = {
873 .name = "WM8955",
874 .playback = {
875 .stream_name = "Playback",
876 .channels_min = 2,
877 .channels_max = 2,
878 .rates = WM8955_RATES,
879 .formats = WM8955_FORMATS,
880 },
881 .ops = &wm8955_dai_ops,
882};
883EXPORT_SYMBOL_GPL(wm8955_dai);
884
885#ifdef CONFIG_PM
886static int wm8955_suspend(struct platform_device *pdev, pm_message_t state)
887{
888 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
889 struct snd_soc_codec *codec = socdev->card->codec;
890
891 wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
892
893 return 0;
894}
895
896static int wm8955_resume(struct platform_device *pdev)
897{
898 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
899 struct snd_soc_codec *codec = socdev->card->codec;
900
901 wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
902
903 return 0;
904}
905#else
906#define wm8955_suspend NULL
907#define wm8955_resume NULL
908#endif
909
910static int wm8955_probe(struct platform_device *pdev)
911{
912 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
913 struct snd_soc_codec *codec;
914 int ret = 0;
915
916 if (wm8955_codec == NULL) {
917 dev_err(&pdev->dev, "Codec device not registered\n");
918 return -ENODEV;
919 }
920
921 socdev->card->codec = wm8955_codec;
922 codec = wm8955_codec;
923
924 /* register pcms */
925 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
926 if (ret < 0) {
927 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
928 goto pcm_err;
929 }
930
931 wm8955_add_widgets(codec);
932
933 return ret;
934
935pcm_err:
936 return ret;
937}
938
939static int wm8955_remove(struct platform_device *pdev)
940{
941 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
942
943 snd_soc_free_pcms(socdev);
944 snd_soc_dapm_free(socdev);
945
946 return 0;
947}
948
949struct snd_soc_codec_device soc_codec_dev_wm8955 = {
950 .probe = wm8955_probe,
951 .remove = wm8955_remove,
952 .suspend = wm8955_suspend,
953 .resume = wm8955_resume,
954};
955EXPORT_SYMBOL_GPL(soc_codec_dev_wm8955);
956
957static int wm8955_register(struct wm8955_priv *wm8955,
958 enum snd_soc_control_type control)
959{
960 int ret;
961 struct snd_soc_codec *codec = &wm8955->codec;
962 int i;
963
964 if (wm8955_codec) {
965 dev_err(codec->dev, "Another WM8955 is registered\n");
966 return -EINVAL;
967 }
968
969 mutex_init(&codec->mutex);
970 INIT_LIST_HEAD(&codec->dapm_widgets);
971 INIT_LIST_HEAD(&codec->dapm_paths);
972
973 codec->private_data = wm8955;
974 codec->name = "WM8955";
975 codec->owner = THIS_MODULE;
976 codec->bias_level = SND_SOC_BIAS_OFF;
977 codec->set_bias_level = wm8955_set_bias_level;
978 codec->dai = &wm8955_dai;
979 codec->num_dai = 1;
980 codec->reg_cache_size = WM8955_MAX_REGISTER;
981 codec->reg_cache = &wm8955->reg_cache;
982
983 memcpy(codec->reg_cache, wm8955_reg, sizeof(wm8955_reg));
984
985 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
986 if (ret != 0) {
987 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
988 goto err;
989 }
990
991 for (i = 0; i < ARRAY_SIZE(wm8955->supplies); i++)
992 wm8955->supplies[i].supply = wm8955_supply_names[i];
993
994 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8955->supplies),
995 wm8955->supplies);
996 if (ret != 0) {
997 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
998 goto err;
999 }
1000
1001 ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
1002 wm8955->supplies);
1003 if (ret != 0) {
1004 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
1005 goto err_get;
1006 }
1007
1008 ret = wm8955_reset(codec);
1009 if (ret < 0) {
1010 dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
1011 goto err_enable;
1012 }
1013
1014 wm8955_dai.dev = codec->dev;
1015
1016 /* Change some default settings - latch VU and enable ZC */
1017 wm8955->reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU;
1018 wm8955->reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU;
1019 wm8955->reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC;
1020 wm8955->reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC;
1021 wm8955->reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC;
1022 wm8955->reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC;
1023 wm8955->reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC;
1024
1025 /* Also enable adaptive bass boost by default */
1026 wm8955->reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB;
1027
1028 /* Set platform data values */
1029 if (wm8955->pdata) {
1030 if (wm8955->pdata->out2_speaker)
1031 wm8955->reg_cache[WM8955_ADDITIONAL_CONTROL_2]
1032 |= WM8955_ROUT2INV;
1033
1034 if (wm8955->pdata->monoin_diff)
1035 wm8955->reg_cache[WM8955_MONO_OUT_MIX_1]
1036 |= WM8955_DMEN;
1037 }
1038
1039 wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1040
1041 /* Bias level configuration will have done an extra enable */
1042 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1043
1044 wm8955_codec = codec;
1045
1046 ret = snd_soc_register_codec(codec);
1047 if (ret != 0) {
1048 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
1049 return ret;
1050 }
1051
1052 ret = snd_soc_register_dai(&wm8955_dai);
1053 if (ret != 0) {
1054 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
1055 snd_soc_unregister_codec(codec);
1056 return ret;
1057 }
1058
1059 return 0;
1060
1061err_enable:
1062 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1063err_get:
1064 regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1065err:
1066 kfree(wm8955);
1067 return ret;
1068}
1069
1070static void wm8955_unregister(struct wm8955_priv *wm8955)
1071{
1072 wm8955_set_bias_level(&wm8955->codec, SND_SOC_BIAS_OFF);
1073 regulator_bulk_free(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1074 snd_soc_unregister_dai(&wm8955_dai);
1075 snd_soc_unregister_codec(&wm8955->codec);
1076 kfree(wm8955);
1077 wm8955_codec = NULL;
1078}
1079
1080#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1081static __devinit int wm8955_i2c_probe(struct i2c_client *i2c,
1082 const struct i2c_device_id *id)
1083{
1084 struct wm8955_priv *wm8955;
1085 struct snd_soc_codec *codec;
1086
1087 wm8955 = kzalloc(sizeof(struct wm8955_priv), GFP_KERNEL);
1088 if (wm8955 == NULL)
1089 return -ENOMEM;
1090
1091 codec = &wm8955->codec;
1092 codec->hw_write = (hw_write_t)i2c_master_send;
1093
1094 i2c_set_clientdata(i2c, wm8955);
1095 codec->control_data = i2c;
1096 wm8955->pdata = i2c->dev.platform_data;
1097
1098 codec->dev = &i2c->dev;
1099
1100 return wm8955_register(wm8955, SND_SOC_I2C);
1101}
1102
1103static __devexit int wm8955_i2c_remove(struct i2c_client *client)
1104{
1105 struct wm8955_priv *wm8955 = i2c_get_clientdata(client);
1106 wm8955_unregister(wm8955);
1107 return 0;
1108}
1109
1110static const struct i2c_device_id wm8955_i2c_id[] = {
1111 { "wm8955", 0 },
1112 { }
1113};
1114MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id);
1115
1116static struct i2c_driver wm8955_i2c_driver = {
1117 .driver = {
1118 .name = "wm8955",
1119 .owner = THIS_MODULE,
1120 },
1121 .probe = wm8955_i2c_probe,
1122 .remove = __devexit_p(wm8955_i2c_remove),
1123 .id_table = wm8955_i2c_id,
1124};
1125#endif
1126
1127static int __init wm8955_modinit(void)
1128{
1129 int ret;
1130#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1131 ret = i2c_add_driver(&wm8955_i2c_driver);
1132 if (ret != 0) {
1133 printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n",
1134 ret);
1135 }
1136#endif
1137 return 0;
1138}
1139module_init(wm8955_modinit);
1140
1141static void __exit wm8955_exit(void)
1142{
1143#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1144 i2c_del_driver(&wm8955_i2c_driver);
1145#endif
1146}
1147module_exit(wm8955_exit);
1148
1149MODULE_DESCRIPTION("ASoC WM8955 driver");
1150MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
1151MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8955.h b/sound/soc/codecs/wm8955.h
new file mode 100644
index 00000000000..ae349c8531f
--- /dev/null
+++ b/sound/soc/codecs/wm8955.h
@@ -0,0 +1,489 @@
1/*
2 * wm8955.h -- WM8904 ASoC driver
3 *
4 * Copyright 2009 Wolfson Microelectronics, plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef _WM8955_H
14#define _WM8955_H
15
16#define WM8955_CLK_MCLK 1
17
18extern struct snd_soc_dai wm8955_dai;
19extern struct snd_soc_codec_device soc_codec_dev_wm8955;
20
21/*
22 * Register values.
23 */
24#define WM8955_LOUT1_VOLUME 0x02
25#define WM8955_ROUT1_VOLUME 0x03
26#define WM8955_DAC_CONTROL 0x05
27#define WM8955_AUDIO_INTERFACE 0x07
28#define WM8955_SAMPLE_RATE 0x08
29#define WM8955_LEFT_DAC_VOLUME 0x0A
30#define WM8955_RIGHT_DAC_VOLUME 0x0B
31#define WM8955_BASS_CONTROL 0x0C
32#define WM8955_TREBLE_CONTROL 0x0D
33#define WM8955_RESET 0x0F
34#define WM8955_ADDITIONAL_CONTROL_1 0x17
35#define WM8955_ADDITIONAL_CONTROL_2 0x18
36#define WM8955_POWER_MANAGEMENT_1 0x19
37#define WM8955_POWER_MANAGEMENT_2 0x1A
38#define WM8955_ADDITIONAL_CONTROL_3 0x1B
39#define WM8955_LEFT_OUT_MIX_1 0x22
40#define WM8955_LEFT_OUT_MIX_2 0x23
41#define WM8955_RIGHT_OUT_MIX_1 0x24
42#define WM8955_RIGHT_OUT_MIX_2 0x25
43#define WM8955_MONO_OUT_MIX_1 0x26
44#define WM8955_MONO_OUT_MIX_2 0x27
45#define WM8955_LOUT2_VOLUME 0x28
46#define WM8955_ROUT2_VOLUME 0x29
47#define WM8955_MONOOUT_VOLUME 0x2A
48#define WM8955_CLOCKING_PLL 0x2B
49#define WM8955_PLL_CONTROL_1 0x2C
50#define WM8955_PLL_CONTROL_2 0x2D
51#define WM8955_PLL_CONTROL_3 0x2E
52#define WM8955_PLL_CONTROL_4 0x3B
53
54#define WM8955_REGISTER_COUNT 29
55#define WM8955_MAX_REGISTER 0x3B
56
57/*
58 * Field Definitions.
59 */
60
61/*
62 * R2 (0x02) - LOUT1 volume
63 */
64#define WM8955_LO1VU 0x0100 /* LO1VU */
65#define WM8955_LO1VU_MASK 0x0100 /* LO1VU */
66#define WM8955_LO1VU_SHIFT 8 /* LO1VU */
67#define WM8955_LO1VU_WIDTH 1 /* LO1VU */
68#define WM8955_LO1ZC 0x0080 /* LO1ZC */
69#define WM8955_LO1ZC_MASK 0x0080 /* LO1ZC */
70#define WM8955_LO1ZC_SHIFT 7 /* LO1ZC */
71#define WM8955_LO1ZC_WIDTH 1 /* LO1ZC */
72#define WM8955_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */
73#define WM8955_LOUTVOL_SHIFT 0 /* LOUTVOL - [6:0] */
74#define WM8955_LOUTVOL_WIDTH 7 /* LOUTVOL - [6:0] */
75
76/*
77 * R3 (0x03) - ROUT1 volume
78 */
79#define WM8955_RO1VU 0x0100 /* RO1VU */
80#define WM8955_RO1VU_MASK 0x0100 /* RO1VU */
81#define WM8955_RO1VU_SHIFT 8 /* RO1VU */
82#define WM8955_RO1VU_WIDTH 1 /* RO1VU */
83#define WM8955_RO1ZC 0x0080 /* RO1ZC */
84#define WM8955_RO1ZC_MASK 0x0080 /* RO1ZC */
85#define WM8955_RO1ZC_SHIFT 7 /* RO1ZC */
86#define WM8955_RO1ZC_WIDTH 1 /* RO1ZC */
87#define WM8955_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */
88#define WM8955_ROUTVOL_SHIFT 0 /* ROUTVOL - [6:0] */
89#define WM8955_ROUTVOL_WIDTH 7 /* ROUTVOL - [6:0] */
90
91/*
92 * R5 (0x05) - DAC Control
93 */
94#define WM8955_DAT 0x0080 /* DAT */
95#define WM8955_DAT_MASK 0x0080 /* DAT */
96#define WM8955_DAT_SHIFT 7 /* DAT */
97#define WM8955_DAT_WIDTH 1 /* DAT */
98#define WM8955_DACMU 0x0008 /* DACMU */
99#define WM8955_DACMU_MASK 0x0008 /* DACMU */
100#define WM8955_DACMU_SHIFT 3 /* DACMU */
101#define WM8955_DACMU_WIDTH 1 /* DACMU */
102#define WM8955_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */
103#define WM8955_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */
104#define WM8955_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */
105
106/*
107 * R7 (0x07) - Audio Interface
108 */
109#define WM8955_BCLKINV 0x0080 /* BCLKINV */
110#define WM8955_BCLKINV_MASK 0x0080 /* BCLKINV */
111#define WM8955_BCLKINV_SHIFT 7 /* BCLKINV */
112#define WM8955_BCLKINV_WIDTH 1 /* BCLKINV */
113#define WM8955_MS 0x0040 /* MS */
114#define WM8955_MS_MASK 0x0040 /* MS */
115#define WM8955_MS_SHIFT 6 /* MS */
116#define WM8955_MS_WIDTH 1 /* MS */
117#define WM8955_LRSWAP 0x0020 /* LRSWAP */
118#define WM8955_LRSWAP_MASK 0x0020 /* LRSWAP */
119#define WM8955_LRSWAP_SHIFT 5 /* LRSWAP */
120#define WM8955_LRSWAP_WIDTH 1 /* LRSWAP */
121#define WM8955_LRP 0x0010 /* LRP */
122#define WM8955_LRP_MASK 0x0010 /* LRP */
123#define WM8955_LRP_SHIFT 4 /* LRP */
124#define WM8955_LRP_WIDTH 1 /* LRP */
125#define WM8955_WL_MASK 0x000C /* WL - [3:2] */
126#define WM8955_WL_SHIFT 2 /* WL - [3:2] */
127#define WM8955_WL_WIDTH 2 /* WL - [3:2] */
128#define WM8955_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */
129#define WM8955_FORMAT_SHIFT 0 /* FORMAT - [1:0] */
130#define WM8955_FORMAT_WIDTH 2 /* FORMAT - [1:0] */
131
132/*
133 * R8 (0x08) - Sample Rate
134 */
135#define WM8955_BCLKDIV2 0x0080 /* BCLKDIV2 */
136#define WM8955_BCLKDIV2_MASK 0x0080 /* BCLKDIV2 */
137#define WM8955_BCLKDIV2_SHIFT 7 /* BCLKDIV2 */
138#define WM8955_BCLKDIV2_WIDTH 1 /* BCLKDIV2 */
139#define WM8955_MCLKDIV2 0x0040 /* MCLKDIV2 */
140#define WM8955_MCLKDIV2_MASK 0x0040 /* MCLKDIV2 */
141#define WM8955_MCLKDIV2_SHIFT 6 /* MCLKDIV2 */
142#define WM8955_MCLKDIV2_WIDTH 1 /* MCLKDIV2 */
143#define WM8955_SR_MASK 0x003E /* SR - [5:1] */
144#define WM8955_SR_SHIFT 1 /* SR - [5:1] */
145#define WM8955_SR_WIDTH 5 /* SR - [5:1] */
146#define WM8955_USB 0x0001 /* USB */
147#define WM8955_USB_MASK 0x0001 /* USB */
148#define WM8955_USB_SHIFT 0 /* USB */
149#define WM8955_USB_WIDTH 1 /* USB */
150
151/*
152 * R10 (0x0A) - Left DAC volume
153 */
154#define WM8955_LDVU 0x0100 /* LDVU */
155#define WM8955_LDVU_MASK 0x0100 /* LDVU */
156#define WM8955_LDVU_SHIFT 8 /* LDVU */
157#define WM8955_LDVU_WIDTH 1 /* LDVU */
158#define WM8955_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */
159#define WM8955_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */
160#define WM8955_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */
161
162/*
163 * R11 (0x0B) - Right DAC volume
164 */
165#define WM8955_RDVU 0x0100 /* RDVU */
166#define WM8955_RDVU_MASK 0x0100 /* RDVU */
167#define WM8955_RDVU_SHIFT 8 /* RDVU */
168#define WM8955_RDVU_WIDTH 1 /* RDVU */
169#define WM8955_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */
170#define WM8955_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */
171#define WM8955_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */
172
173/*
174 * R12 (0x0C) - Bass control
175 */
176#define WM8955_BB 0x0080 /* BB */
177#define WM8955_BB_MASK 0x0080 /* BB */
178#define WM8955_BB_SHIFT 7 /* BB */
179#define WM8955_BB_WIDTH 1 /* BB */
180#define WM8955_BC 0x0040 /* BC */
181#define WM8955_BC_MASK 0x0040 /* BC */
182#define WM8955_BC_SHIFT 6 /* BC */
183#define WM8955_BC_WIDTH 1 /* BC */
184#define WM8955_BASS_MASK 0x000F /* BASS - [3:0] */
185#define WM8955_BASS_SHIFT 0 /* BASS - [3:0] */
186#define WM8955_BASS_WIDTH 4 /* BASS - [3:0] */
187
188/*
189 * R13 (0x0D) - Treble control
190 */
191#define WM8955_TC 0x0040 /* TC */
192#define WM8955_TC_MASK 0x0040 /* TC */
193#define WM8955_TC_SHIFT 6 /* TC */
194#define WM8955_TC_WIDTH 1 /* TC */
195#define WM8955_TRBL_MASK 0x000F /* TRBL - [3:0] */
196#define WM8955_TRBL_SHIFT 0 /* TRBL - [3:0] */
197#define WM8955_TRBL_WIDTH 4 /* TRBL - [3:0] */
198
199/*
200 * R15 (0x0F) - Reset
201 */
202#define WM8955_RESET_MASK 0x01FF /* RESET - [8:0] */
203#define WM8955_RESET_SHIFT 0 /* RESET - [8:0] */
204#define WM8955_RESET_WIDTH 9 /* RESET - [8:0] */
205
206/*
207 * R23 (0x17) - Additional control (1)
208 */
209#define WM8955_TSDEN 0x0100 /* TSDEN */
210#define WM8955_TSDEN_MASK 0x0100 /* TSDEN */
211#define WM8955_TSDEN_SHIFT 8 /* TSDEN */
212#define WM8955_TSDEN_WIDTH 1 /* TSDEN */
213#define WM8955_VSEL_MASK 0x00C0 /* VSEL - [7:6] */
214#define WM8955_VSEL_SHIFT 6 /* VSEL - [7:6] */
215#define WM8955_VSEL_WIDTH 2 /* VSEL - [7:6] */
216#define WM8955_DMONOMIX_MASK 0x0030 /* DMONOMIX - [5:4] */
217#define WM8955_DMONOMIX_SHIFT 4 /* DMONOMIX - [5:4] */
218#define WM8955_DMONOMIX_WIDTH 2 /* DMONOMIX - [5:4] */
219#define WM8955_DACINV 0x0002 /* DACINV */
220#define WM8955_DACINV_MASK 0x0002 /* DACINV */
221#define WM8955_DACINV_SHIFT 1 /* DACINV */
222#define WM8955_DACINV_WIDTH 1 /* DACINV */
223#define WM8955_TOEN 0x0001 /* TOEN */
224#define WM8955_TOEN_MASK 0x0001 /* TOEN */
225#define WM8955_TOEN_SHIFT 0 /* TOEN */
226#define WM8955_TOEN_WIDTH 1 /* TOEN */
227
228/*
229 * R24 (0x18) - Additional control (2)
230 */
231#define WM8955_OUT3SW_MASK 0x0180 /* OUT3SW - [8:7] */
232#define WM8955_OUT3SW_SHIFT 7 /* OUT3SW - [8:7] */
233#define WM8955_OUT3SW_WIDTH 2 /* OUT3SW - [8:7] */
234#define WM8955_ROUT2INV 0x0010 /* ROUT2INV */
235#define WM8955_ROUT2INV_MASK 0x0010 /* ROUT2INV */
236#define WM8955_ROUT2INV_SHIFT 4 /* ROUT2INV */
237#define WM8955_ROUT2INV_WIDTH 1 /* ROUT2INV */
238#define WM8955_DACOSR 0x0001 /* DACOSR */
239#define WM8955_DACOSR_MASK 0x0001 /* DACOSR */
240#define WM8955_DACOSR_SHIFT 0 /* DACOSR */
241#define WM8955_DACOSR_WIDTH 1 /* DACOSR */
242
243/*
244 * R25 (0x19) - Power Management (1)
245 */
246#define WM8955_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */
247#define WM8955_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */
248#define WM8955_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */
249#define WM8955_VREF 0x0040 /* VREF */
250#define WM8955_VREF_MASK 0x0040 /* VREF */
251#define WM8955_VREF_SHIFT 6 /* VREF */
252#define WM8955_VREF_WIDTH 1 /* VREF */
253#define WM8955_DIGENB 0x0001 /* DIGENB */
254#define WM8955_DIGENB_MASK 0x0001 /* DIGENB */
255#define WM8955_DIGENB_SHIFT 0 /* DIGENB */
256#define WM8955_DIGENB_WIDTH 1 /* DIGENB */
257
258/*
259 * R26 (0x1A) - Power Management (2)
260 */
261#define WM8955_DACL 0x0100 /* DACL */
262#define WM8955_DACL_MASK 0x0100 /* DACL */
263#define WM8955_DACL_SHIFT 8 /* DACL */
264#define WM8955_DACL_WIDTH 1 /* DACL */
265#define WM8955_DACR 0x0080 /* DACR */
266#define WM8955_DACR_MASK 0x0080 /* DACR */
267#define WM8955_DACR_SHIFT 7 /* DACR */
268#define WM8955_DACR_WIDTH 1 /* DACR */
269#define WM8955_LOUT1 0x0040 /* LOUT1 */
270#define WM8955_LOUT1_MASK 0x0040 /* LOUT1 */
271#define WM8955_LOUT1_SHIFT 6 /* LOUT1 */
272#define WM8955_LOUT1_WIDTH 1 /* LOUT1 */
273#define WM8955_ROUT1 0x0020 /* ROUT1 */
274#define WM8955_ROUT1_MASK 0x0020 /* ROUT1 */
275#define WM8955_ROUT1_SHIFT 5 /* ROUT1 */
276#define WM8955_ROUT1_WIDTH 1 /* ROUT1 */
277#define WM8955_LOUT2 0x0010 /* LOUT2 */
278#define WM8955_LOUT2_MASK 0x0010 /* LOUT2 */
279#define WM8955_LOUT2_SHIFT 4 /* LOUT2 */
280#define WM8955_LOUT2_WIDTH 1 /* LOUT2 */
281#define WM8955_ROUT2 0x0008 /* ROUT2 */
282#define WM8955_ROUT2_MASK 0x0008 /* ROUT2 */
283#define WM8955_ROUT2_SHIFT 3 /* ROUT2 */
284#define WM8955_ROUT2_WIDTH 1 /* ROUT2 */
285#define WM8955_MONO 0x0004 /* MONO */
286#define WM8955_MONO_MASK 0x0004 /* MONO */
287#define WM8955_MONO_SHIFT 2 /* MONO */
288#define WM8955_MONO_WIDTH 1 /* MONO */
289#define WM8955_OUT3 0x0002 /* OUT3 */
290#define WM8955_OUT3_MASK 0x0002 /* OUT3 */
291#define WM8955_OUT3_SHIFT 1 /* OUT3 */
292#define WM8955_OUT3_WIDTH 1 /* OUT3 */
293
294/*
295 * R27 (0x1B) - Additional Control (3)
296 */
297#define WM8955_VROI 0x0040 /* VROI */
298#define WM8955_VROI_MASK 0x0040 /* VROI */
299#define WM8955_VROI_SHIFT 6 /* VROI */
300#define WM8955_VROI_WIDTH 1 /* VROI */
301
302/*
303 * R34 (0x22) - Left out Mix (1)
304 */
305#define WM8955_LD2LO 0x0100 /* LD2LO */
306#define WM8955_LD2LO_MASK 0x0100 /* LD2LO */
307#define WM8955_LD2LO_SHIFT 8 /* LD2LO */
308#define WM8955_LD2LO_WIDTH 1 /* LD2LO */
309#define WM8955_LI2LO 0x0080 /* LI2LO */
310#define WM8955_LI2LO_MASK 0x0080 /* LI2LO */
311#define WM8955_LI2LO_SHIFT 7 /* LI2LO */
312#define WM8955_LI2LO_WIDTH 1 /* LI2LO */
313#define WM8955_LI2LOVOL_MASK 0x0070 /* LI2LOVOL - [6:4] */
314#define WM8955_LI2LOVOL_SHIFT 4 /* LI2LOVOL - [6:4] */
315#define WM8955_LI2LOVOL_WIDTH 3 /* LI2LOVOL - [6:4] */
316
317/*
318 * R35 (0x23) - Left out Mix (2)
319 */
320#define WM8955_RD2LO 0x0100 /* RD2LO */
321#define WM8955_RD2LO_MASK 0x0100 /* RD2LO */
322#define WM8955_RD2LO_SHIFT 8 /* RD2LO */
323#define WM8955_RD2LO_WIDTH 1 /* RD2LO */
324#define WM8955_RI2LO 0x0080 /* RI2LO */
325#define WM8955_RI2LO_MASK 0x0080 /* RI2LO */
326#define WM8955_RI2LO_SHIFT 7 /* RI2LO */
327#define WM8955_RI2LO_WIDTH 1 /* RI2LO */
328#define WM8955_RI2LOVOL_MASK 0x0070 /* RI2LOVOL - [6:4] */
329#define WM8955_RI2LOVOL_SHIFT 4 /* RI2LOVOL - [6:4] */
330#define WM8955_RI2LOVOL_WIDTH 3 /* RI2LOVOL - [6:4] */
331
332/*
333 * R36 (0x24) - Right out Mix (1)
334 */
335#define WM8955_LD2RO 0x0100 /* LD2RO */
336#define WM8955_LD2RO_MASK 0x0100 /* LD2RO */
337#define WM8955_LD2RO_SHIFT 8 /* LD2RO */
338#define WM8955_LD2RO_WIDTH 1 /* LD2RO */
339#define WM8955_LI2RO 0x0080 /* LI2RO */
340#define WM8955_LI2RO_MASK 0x0080 /* LI2RO */
341#define WM8955_LI2RO_SHIFT 7 /* LI2RO */
342#define WM8955_LI2RO_WIDTH 1 /* LI2RO */
343#define WM8955_LI2ROVOL_MASK 0x0070 /* LI2ROVOL - [6:4] */
344#define WM8955_LI2ROVOL_SHIFT 4 /* LI2ROVOL - [6:4] */
345#define WM8955_LI2ROVOL_WIDTH 3 /* LI2ROVOL - [6:4] */
346
347/*
348 * R37 (0x25) - Right Out Mix (2)
349 */
350#define WM8955_RD2RO 0x0100 /* RD2RO */
351#define WM8955_RD2RO_MASK 0x0100 /* RD2RO */
352#define WM8955_RD2RO_SHIFT 8 /* RD2RO */
353#define WM8955_RD2RO_WIDTH 1 /* RD2RO */
354#define WM8955_RI2RO 0x0080 /* RI2RO */
355#define WM8955_RI2RO_MASK 0x0080 /* RI2RO */
356#define WM8955_RI2RO_SHIFT 7 /* RI2RO */
357#define WM8955_RI2RO_WIDTH 1 /* RI2RO */
358#define WM8955_RI2ROVOL_MASK 0x0070 /* RI2ROVOL - [6:4] */
359#define WM8955_RI2ROVOL_SHIFT 4 /* RI2ROVOL - [6:4] */
360#define WM8955_RI2ROVOL_WIDTH 3 /* RI2ROVOL - [6:4] */
361
362/*
363 * R38 (0x26) - Mono out Mix (1)
364 */
365#define WM8955_LD2MO 0x0100 /* LD2MO */
366#define WM8955_LD2MO_MASK 0x0100 /* LD2MO */
367#define WM8955_LD2MO_SHIFT 8 /* LD2MO */
368#define WM8955_LD2MO_WIDTH 1 /* LD2MO */
369#define WM8955_LI2MO 0x0080 /* LI2MO */
370#define WM8955_LI2MO_MASK 0x0080 /* LI2MO */
371#define WM8955_LI2MO_SHIFT 7 /* LI2MO */
372#define WM8955_LI2MO_WIDTH 1 /* LI2MO */
373#define WM8955_LI2MOVOL_MASK 0x0070 /* LI2MOVOL - [6:4] */
374#define WM8955_LI2MOVOL_SHIFT 4 /* LI2MOVOL - [6:4] */
375#define WM8955_LI2MOVOL_WIDTH 3 /* LI2MOVOL - [6:4] */
376#define WM8955_DMEN 0x0001 /* DMEN */
377#define WM8955_DMEN_MASK 0x0001 /* DMEN */
378#define WM8955_DMEN_SHIFT 0 /* DMEN */
379#define WM8955_DMEN_WIDTH 1 /* DMEN */
380
381/*
382 * R39 (0x27) - Mono out Mix (2)
383 */
384#define WM8955_RD2MO 0x0100 /* RD2MO */
385#define WM8955_RD2MO_MASK 0x0100 /* RD2MO */
386#define WM8955_RD2MO_SHIFT 8 /* RD2MO */
387#define WM8955_RD2MO_WIDTH 1 /* RD2MO */
388#define WM8955_RI2MO 0x0080 /* RI2MO */
389#define WM8955_RI2MO_MASK 0x0080 /* RI2MO */
390#define WM8955_RI2MO_SHIFT 7 /* RI2MO */
391#define WM8955_RI2MO_WIDTH 1 /* RI2MO */
392#define WM8955_RI2MOVOL_MASK 0x0070 /* RI2MOVOL - [6:4] */
393#define WM8955_RI2MOVOL_SHIFT 4 /* RI2MOVOL - [6:4] */
394#define WM8955_RI2MOVOL_WIDTH 3 /* RI2MOVOL - [6:4] */
395
396/*
397 * R40 (0x28) - LOUT2 volume
398 */
399#define WM8955_LO2VU 0x0100 /* LO2VU */
400#define WM8955_LO2VU_MASK 0x0100 /* LO2VU */
401#define WM8955_LO2VU_SHIFT 8 /* LO2VU */
402#define WM8955_LO2VU_WIDTH 1 /* LO2VU */
403#define WM8955_LO2ZC 0x0080 /* LO2ZC */
404#define WM8955_LO2ZC_MASK 0x0080 /* LO2ZC */
405#define WM8955_LO2ZC_SHIFT 7 /* LO2ZC */
406#define WM8955_LO2ZC_WIDTH 1 /* LO2ZC */
407#define WM8955_LOUT2VOL_MASK 0x007F /* LOUT2VOL - [6:0] */
408#define WM8955_LOUT2VOL_SHIFT 0 /* LOUT2VOL - [6:0] */
409#define WM8955_LOUT2VOL_WIDTH 7 /* LOUT2VOL - [6:0] */
410
411/*
412 * R41 (0x29) - ROUT2 volume
413 */
414#define WM8955_RO2VU 0x0100 /* RO2VU */
415#define WM8955_RO2VU_MASK 0x0100 /* RO2VU */
416#define WM8955_RO2VU_SHIFT 8 /* RO2VU */
417#define WM8955_RO2VU_WIDTH 1 /* RO2VU */
418#define WM8955_RO2ZC 0x0080 /* RO2ZC */
419#define WM8955_RO2ZC_MASK 0x0080 /* RO2ZC */
420#define WM8955_RO2ZC_SHIFT 7 /* RO2ZC */
421#define WM8955_RO2ZC_WIDTH 1 /* RO2ZC */
422#define WM8955_ROUT2VOL_MASK 0x007F /* ROUT2VOL - [6:0] */
423#define WM8955_ROUT2VOL_SHIFT 0 /* ROUT2VOL - [6:0] */
424#define WM8955_ROUT2VOL_WIDTH 7 /* ROUT2VOL - [6:0] */
425
426/*
427 * R42 (0x2A) - MONOOUT volume
428 */
429#define WM8955_MOZC 0x0080 /* MOZC */
430#define WM8955_MOZC_MASK 0x0080 /* MOZC */
431#define WM8955_MOZC_SHIFT 7 /* MOZC */
432#define WM8955_MOZC_WIDTH 1 /* MOZC */
433#define WM8955_MOUTVOL_MASK 0x007F /* MOUTVOL - [6:0] */
434#define WM8955_MOUTVOL_SHIFT 0 /* MOUTVOL - [6:0] */
435#define WM8955_MOUTVOL_WIDTH 7 /* MOUTVOL - [6:0] */
436
437/*
438 * R43 (0x2B) - Clocking / PLL
439 */
440#define WM8955_MCLKSEL 0x0100 /* MCLKSEL */
441#define WM8955_MCLKSEL_MASK 0x0100 /* MCLKSEL */
442#define WM8955_MCLKSEL_SHIFT 8 /* MCLKSEL */
443#define WM8955_MCLKSEL_WIDTH 1 /* MCLKSEL */
444#define WM8955_PLLOUTDIV2 0x0020 /* PLLOUTDIV2 */
445#define WM8955_PLLOUTDIV2_MASK 0x0020 /* PLLOUTDIV2 */
446#define WM8955_PLLOUTDIV2_SHIFT 5 /* PLLOUTDIV2 */
447#define WM8955_PLLOUTDIV2_WIDTH 1 /* PLLOUTDIV2 */
448#define WM8955_PLL_RB 0x0010 /* PLL_RB */
449#define WM8955_PLL_RB_MASK 0x0010 /* PLL_RB */
450#define WM8955_PLL_RB_SHIFT 4 /* PLL_RB */
451#define WM8955_PLL_RB_WIDTH 1 /* PLL_RB */
452#define WM8955_PLLEN 0x0008 /* PLLEN */
453#define WM8955_PLLEN_MASK 0x0008 /* PLLEN */
454#define WM8955_PLLEN_SHIFT 3 /* PLLEN */
455#define WM8955_PLLEN_WIDTH 1 /* PLLEN */
456
457/*
458 * R44 (0x2C) - PLL Control 1
459 */
460#define WM8955_N_MASK 0x01E0 /* N - [8:5] */
461#define WM8955_N_SHIFT 5 /* N - [8:5] */
462#define WM8955_N_WIDTH 4 /* N - [8:5] */
463#define WM8955_K_21_18_MASK 0x000F /* K(21:18) - [3:0] */
464#define WM8955_K_21_18_SHIFT 0 /* K(21:18) - [3:0] */
465#define WM8955_K_21_18_WIDTH 4 /* K(21:18) - [3:0] */
466
467/*
468 * R45 (0x2D) - PLL Control 2
469 */
470#define WM8955_K_17_9_MASK 0x01FF /* K(17:9) - [8:0] */
471#define WM8955_K_17_9_SHIFT 0 /* K(17:9) - [8:0] */
472#define WM8955_K_17_9_WIDTH 9 /* K(17:9) - [8:0] */
473
474/*
475 * R46 (0x2E) - PLL Control 3
476 */
477#define WM8955_K_8_0_MASK 0x01FF /* K(8:0) - [8:0] */
478#define WM8955_K_8_0_SHIFT 0 /* K(8:0) - [8:0] */
479#define WM8955_K_8_0_WIDTH 9 /* K(8:0) - [8:0] */
480
481/*
482 * R59 (0x3B) - PLL Control 4
483 */
484#define WM8955_KEN 0x0080 /* KEN */
485#define WM8955_KEN_MASK 0x0080 /* KEN */
486#define WM8955_KEN_SHIFT 7 /* KEN */
487#define WM8955_KEN_WIDTH 1 /* KEN */
488
489#endif
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index a8007d58813..d2342c5e042 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -1022,6 +1022,9 @@ static int wm8961_resume(struct platform_device *pdev)
1022 int i; 1022 int i;
1023 1023
1024 for (i = 0; i < codec->reg_cache_size; i++) { 1024 for (i = 0; i < codec->reg_cache_size; i++) {
1025 if (reg_cache[i] == wm8961_reg_defaults[i])
1026 continue;
1027
1025 if (i == WM8961_SOFTWARE_RESET) 1028 if (i == WM8961_SOFTWARE_RESET)
1026 continue; 1029 continue;
1027 1030
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 341481e0e83..a54dc77b7f3 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1319,10 +1319,6 @@ static int wm8990_suspend(struct platform_device *pdev, pm_message_t state)
1319 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1319 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1320 struct snd_soc_codec *codec = socdev->card->codec; 1320 struct snd_soc_codec *codec = socdev->card->codec;
1321 1321
1322 /* we only need to suspend if we are a valid card */
1323 if (!codec->card)
1324 return 0;
1325
1326 wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); 1322 wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
1327 return 0; 1323 return 0;
1328} 1324}
@@ -1335,10 +1331,6 @@ static int wm8990_resume(struct platform_device *pdev)
1335 u8 data[2]; 1331 u8 data[2];
1336 u16 *cache = codec->reg_cache; 1332 u16 *cache = codec->reg_cache;
1337 1333
1338 /* we only need to resume if we are a valid card */
1339 if (!codec->card)
1340 return 0;
1341
1342 /* Sync reg_cache with the hardware */ 1334 /* Sync reg_cache with the hardware */
1343 for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) { 1335 for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) {
1344 if (i + 1 == WM8990_RESET) 1336 if (i + 1 == WM8990_RESET)
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 2981afae842..828d8174d5b 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -227,6 +227,7 @@ struct wm8993_priv {
227 int class_w_users; 227 int class_w_users;
228 unsigned int fll_fref; 228 unsigned int fll_fref;
229 unsigned int fll_fout; 229 unsigned int fll_fout;
230 int fll_src;
230}; 231};
231 232
232static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg) 233static unsigned int wm8993_read_hw(struct snd_soc_codec *codec, u8 reg)
@@ -506,6 +507,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
506 507
507 wm8993->fll_fref = Fref; 508 wm8993->fll_fref = Fref;
508 wm8993->fll_fout = Fout; 509 wm8993->fll_fout = Fout;
510 wm8993->fll_src = source;
509 511
510 return 0; 512 return 0;
511} 513}
@@ -1480,9 +1482,74 @@ static int wm8993_remove(struct platform_device *pdev)
1480 return 0; 1482 return 0;
1481} 1483}
1482 1484
1485#ifdef CONFIG_PM
1486static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
1487{
1488 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1489 struct snd_soc_codec *codec = socdev->card->codec;
1490 struct wm8993_priv *wm8993 = codec->private_data;
1491 int fll_fout = wm8993->fll_fout;
1492 int fll_fref = wm8993->fll_fref;
1493 int ret;
1494
1495 /* Stop the FLL in an orderly fashion */
1496 ret = wm8993_set_fll(codec->dai, 0, 0, 0, 0);
1497 if (ret != 0) {
1498 dev_err(&pdev->dev, "Failed to stop FLL\n");
1499 return ret;
1500 }
1501
1502 wm8993->fll_fout = fll_fout;
1503 wm8993->fll_fref = fll_fref;
1504
1505 wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
1506
1507 return 0;
1508}
1509
1510static int wm8993_resume(struct platform_device *pdev)
1511{
1512 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1513 struct snd_soc_codec *codec = socdev->card->codec;
1514 struct wm8993_priv *wm8993 = codec->private_data;
1515 u16 *cache = wm8993->reg_cache;
1516 int i, ret;
1517
1518 /* Restore the register settings */
1519 for (i = 1; i < WM8993_MAX_REGISTER; i++) {
1520 if (cache[i] == wm8993_reg_defaults[i])
1521 continue;
1522 snd_soc_write(codec, i, cache[i]);
1523 }
1524
1525 wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1526
1527 /* Restart the FLL? */
1528 if (wm8993->fll_fout) {
1529 int fll_fout = wm8993->fll_fout;
1530 int fll_fref = wm8993->fll_fref;
1531
1532 wm8993->fll_fref = 0;
1533 wm8993->fll_fout = 0;
1534
1535 ret = wm8993_set_fll(codec->dai, 0, wm8993->fll_src,
1536 fll_fref, fll_fout);
1537 if (ret != 0)
1538 dev_err(codec->dev, "Failed to restart FLL\n");
1539 }
1540
1541 return 0;
1542}
1543#else
1544#define wm8993_suspend NULL
1545#define wm8993_resume NULL
1546#endif
1547
1483struct snd_soc_codec_device soc_codec_dev_wm8993 = { 1548struct snd_soc_codec_device soc_codec_dev_wm8993 = {
1484 .probe = wm8993_probe, 1549 .probe = wm8993_probe,
1485 .remove = wm8993_remove, 1550 .remove = wm8993_remove,
1551 .suspend = wm8993_suspend,
1552 .resume = wm8993_resume,
1486}; 1553};
1487EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993); 1554EXPORT_SYMBOL_GPL(soc_codec_dev_wm8993);
1488 1555
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index d73c30536a2..a67319d9ca7 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -753,6 +753,12 @@ int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
753 WM8993_LINEOUT2_MODE, 753 WM8993_LINEOUT2_MODE,
754 WM8993_LINEOUT2_MODE); 754 WM8993_LINEOUT2_MODE);
755 755
756 /* If the line outputs are differential then we aren't presenting
757 * VMID as an output and can disable it.
758 */
759 if (lineout1_diff && lineout2_diff)
760 codec->idle_bias_off = 1;
761
756 if (lineout1fb) 762 if (lineout1fb)
757 snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL, 763 snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
758 WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB); 764 WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 0a302e1080d..a613bbb0bc9 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -767,14 +767,27 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
767 int ret = 0; 767 int ret = 0;
768 768
769 switch (cmd) { 769 switch (cmd) {
770 case SNDRV_PCM_TRIGGER_START:
771 case SNDRV_PCM_TRIGGER_RESUME: 770 case SNDRV_PCM_TRIGGER_RESUME:
771 if (!dev->clk_active) {
772 clk_enable(dev->clk);
773 dev->clk_active = 1;
774 }
775 /* Fall through */
776 case SNDRV_PCM_TRIGGER_START:
772 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 777 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
773 davinci_mcasp_start(dev, substream->stream); 778 davinci_mcasp_start(dev, substream->stream);
774 break; 779 break;
775 780
776 case SNDRV_PCM_TRIGGER_STOP:
777 case SNDRV_PCM_TRIGGER_SUSPEND: 781 case SNDRV_PCM_TRIGGER_SUSPEND:
782 davinci_mcasp_stop(dev, substream->stream);
783 if (dev->clk_active) {
784 clk_disable(dev->clk);
785 dev->clk_active = 0;
786 }
787
788 break;
789
790 case SNDRV_PCM_TRIGGER_STOP:
778 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 791 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
779 davinci_mcasp_stop(dev, substream->stream); 792 davinci_mcasp_stop(dev, substream->stream);
780 break; 793 break;
@@ -866,6 +879,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
866 } 879 }
867 880
868 clk_enable(dev->clk); 881 clk_enable(dev->clk);
882 dev->clk_active = 1;
869 883
870 dev->base = (void __iomem *)IO_ADDRESS(mem->start); 884 dev->base = (void __iomem *)IO_ADDRESS(mem->start);
871 dev->op_mode = pdata->op_mode; 885 dev->op_mode = pdata->op_mode;
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index 582c9249ef0..e755b5121ec 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -44,6 +44,7 @@ struct davinci_audio_dev {
44 int sample_rate; 44 int sample_rate;
45 struct clk *clk; 45 struct clk *clk;
46 unsigned int codec_fmt; 46 unsigned int codec_fmt;
47 u8 clk_active;
47 48
48 /* McASP specific data */ 49 /* McASP specific data */
49 int tdm_slots; 50 int tdm_slots;
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index ad4d7f47a86..80c7fdf2f52 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -49,7 +49,7 @@ static void print_buf_info(int slot, char *name)
49static struct snd_pcm_hardware pcm_hardware_playback = { 49static struct snd_pcm_hardware pcm_hardware_playback = {
50 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 50 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
51 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 51 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
52 SNDRV_PCM_INFO_PAUSE), 52 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
53 .formats = (SNDRV_PCM_FMTBIT_S16_LE), 53 .formats = (SNDRV_PCM_FMTBIT_S16_LE),
54 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 54 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
55 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | 55 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index a700562e869..5f006f0d03d 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -1,21 +1,13 @@
1config SND_MX1_MX2_SOC 1config SND_IMX_SOC
2 tristate "SoC Audio for Freecale i.MX1x i.MX2x CPUs" 2 tristate "SoC Audio for Freecale i.MX CPUs"
3 depends on ARCH_MX2 || ARCH_MX1 3 depends on ARCH_MXC && BROKEN
4 select SND_PCM 4 select SND_PCM
5 select FIQ
6 select SND_SOC_AC97_BUS
5 help 7 help
6 Say Y or M if you want to add support for codecs attached to 8 Say Y or M if you want to add support for codecs attached to
7 the MX1 or MX2 SSI interface. 9 the i.MX SSI interface.
8 10
9config SND_MXC_SOC_SSI 11config SND_MXC_SOC_SSI
10 tristate 12 tristate
11 13
12config SND_SOC_MX27VIS_WM8974
13 tristate "SoC Audio support for MX27 - WM8974 Visstrim_sm10 board"
14 depends on SND_MX1_MX2_SOC && MACH_MX27 && MACH_IMX27_VISSTRIM_M10
15 select SND_MXC_SOC_SSI
16 select SND_SOC_WM8974
17 help
18 Say Y if you want to add support for SoC audio on Visstrim SM10
19 board with WM8974.
20
21
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index c2ffd2c8df5..d05cc95c5cc 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -1,10 +1,10 @@
1# i.MX Platform Support 1# i.MX Platform Support
2snd-soc-mx1_mx2-objs := mx1_mx2-pcm.o 2snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
3snd-soc-mxc-ssi-objs := mxc-ssi.o
4 3
5obj-$(CONFIG_SND_MX1_MX2_SOC) += snd-soc-mx1_mx2.o 4ifdef CONFIG_MACH_MX27
6obj-$(CONFIG_SND_MXC_SOC_SSI) += snd-soc-mxc-ssi.o 5snd-soc-imx-objs += imx-pcm-dma-mx2.o
6endif
7
8obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
7 9
8# i.MX Machine Support 10# i.MX Machine Support
9snd-soc-mx27vis-wm8974-objs := mx27vis_wm8974.o
10obj-$(CONFIG_SND_SOC_MX27VIS_WM8974) += snd-soc-mx27vis-wm8974.o
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
new file mode 100644
index 00000000000..19452e44afd
--- /dev/null
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -0,0 +1,313 @@
1/*
2 * imx-pcm-dma-mx2.c -- ALSA Soc Audio Layer
3 *
4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
5 *
6 * This code is based on code copyrighted by Freescale,
7 * Liam Girdwood, Javier Martin and probably others.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/device.h>
17#include <linux/dma-mapping.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22
23#include <sound/core.h>
24#include <sound/initval.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28
29#include <mach/dma-mx1-mx2.h>
30
31#include "imx-ssi.h"
32
33struct imx_pcm_runtime_data {
34 int sg_count;
35 struct scatterlist *sg_list;
36 int period;
37 int periods;
38 unsigned long dma_addr;
39 int dma;
40 struct snd_pcm_substream *substream;
41 unsigned long offset;
42 unsigned long size;
43 unsigned long period_cnt;
44 void *buf;
45 int period_time;
46};
47
48/* Called by the DMA framework when a period has elapsed */
49static void imx_ssi_dma_progression(int channel, void *data,
50 struct scatterlist *sg)
51{
52 struct snd_pcm_substream *substream = data;
53 struct snd_pcm_runtime *runtime = substream->runtime;
54 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
55
56 if (!sg)
57 return;
58
59 runtime = iprtd->substream->runtime;
60
61 iprtd->offset = sg->dma_address - runtime->dma_addr;
62
63 snd_pcm_period_elapsed(iprtd->substream);
64}
65
66static void imx_ssi_dma_callback(int channel, void *data)
67{
68 pr_err("%s shouldn't be called\n", __func__);
69}
70
71static void snd_imx_dma_err_callback(int channel, void *data, int err)
72{
73 pr_err("DMA error callback called\n");
74
75 pr_err("DMA timeout on channel %d -%s%s%s%s\n",
76 channel,
77 err & IMX_DMA_ERR_BURST ? " burst" : "",
78 err & IMX_DMA_ERR_REQUEST ? " request" : "",
79 err & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
80 err & IMX_DMA_ERR_BUFFER ? " buffer" : "");
81}
82
83static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
84{
85 struct snd_soc_pcm_runtime *rtd = substream->private_data;
86 struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
87 struct snd_pcm_runtime *runtime = substream->runtime;
88 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
89 int ret;
90
91 iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
92 if (iprtd->dma < 0) {
93 pr_err("Failed to claim the audio DMA\n");
94 return -ENODEV;
95 }
96
97 ret = imx_dma_setup_handlers(iprtd->dma,
98 imx_ssi_dma_callback,
99 snd_imx_dma_err_callback, substream);
100 if (ret)
101 goto out;
102
103 ret = imx_dma_setup_progression_handler(iprtd->dma,
104 imx_ssi_dma_progression);
105 if (ret) {
106 pr_err("Failed to setup the DMA handler\n");
107 goto out;
108 }
109
110 ret = imx_dma_config_channel(iprtd->dma,
111 IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
112 IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
113 dma_params->dma, 1);
114 if (ret < 0) {
115 pr_err("Cannot configure DMA channel: %d\n", ret);
116 goto out;
117 }
118
119 imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2);
120
121 return 0;
122out:
123 imx_dma_free(iprtd->dma);
124 return ret;
125}
126
127static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
128 struct snd_pcm_hw_params *params)
129{
130 struct snd_pcm_runtime *runtime = substream->runtime;
131 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
132 int i;
133 unsigned long dma_addr;
134
135 imx_ssi_dma_alloc(substream);
136
137 iprtd->size = params_buffer_bytes(params);
138 iprtd->periods = params_periods(params);
139 iprtd->period = params_period_bytes(params);
140 iprtd->offset = 0;
141 iprtd->period_time = HZ / (params_rate(params) /
142 params_period_size(params));
143
144 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
145
146 if (iprtd->sg_count != iprtd->periods) {
147 kfree(iprtd->sg_list);
148
149 iprtd->sg_list = kcalloc(iprtd->periods + 1,
150 sizeof(struct scatterlist), GFP_KERNEL);
151 if (!iprtd->sg_list)
152 return -ENOMEM;
153 iprtd->sg_count = iprtd->periods + 1;
154 }
155
156 sg_init_table(iprtd->sg_list, iprtd->sg_count);
157 dma_addr = runtime->dma_addr;
158
159 for (i = 0; i < iprtd->periods; i++) {
160 iprtd->sg_list[i].page_link = 0;
161 iprtd->sg_list[i].offset = 0;
162 iprtd->sg_list[i].dma_address = dma_addr;
163 iprtd->sg_list[i].length = iprtd->period;
164 dma_addr += iprtd->period;
165 }
166
167 /* close the loop */
168 iprtd->sg_list[iprtd->sg_count - 1].offset = 0;
169 iprtd->sg_list[iprtd->sg_count - 1].length = 0;
170 iprtd->sg_list[iprtd->sg_count - 1].page_link =
171 ((unsigned long) iprtd->sg_list | 0x01) & ~0x02;
172 return 0;
173}
174
175static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
176{
177 struct snd_pcm_runtime *runtime = substream->runtime;
178 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
179
180 if (iprtd->dma >= 0) {
181 imx_dma_free(iprtd->dma);
182 iprtd->dma = -EINVAL;
183 }
184
185 kfree(iprtd->sg_list);
186 iprtd->sg_list = NULL;
187
188 return 0;
189}
190
191static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
192{
193 struct snd_pcm_runtime *runtime = substream->runtime;
194 struct snd_soc_pcm_runtime *rtd = substream->private_data;
195 struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
196 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
197 int err;
198
199 iprtd->substream = substream;
200 iprtd->buf = (unsigned int *)substream->dma_buffer.area;
201 iprtd->period_cnt = 0;
202
203 pr_debug("%s: buf: %p period: %d periods: %d\n",
204 __func__, iprtd->buf, iprtd->period, iprtd->periods);
205
206 err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
207 IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
208 substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
209 DMA_MODE_WRITE : DMA_MODE_READ);
210 if (err)
211 return err;
212
213 return 0;
214}
215
216static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
217{
218 struct snd_pcm_runtime *runtime = substream->runtime;
219 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
220
221 switch (cmd) {
222 case SNDRV_PCM_TRIGGER_START:
223 case SNDRV_PCM_TRIGGER_RESUME:
224 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
225 imx_dma_enable(iprtd->dma);
226
227 break;
228
229 case SNDRV_PCM_TRIGGER_STOP:
230 case SNDRV_PCM_TRIGGER_SUSPEND:
231 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
232 imx_dma_disable(iprtd->dma);
233
234 break;
235 default:
236 return -EINVAL;
237 }
238
239 return 0;
240}
241
242static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
243{
244 struct snd_pcm_runtime *runtime = substream->runtime;
245 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
246
247 return bytes_to_frames(substream->runtime, iprtd->offset);
248}
249
250static struct snd_pcm_hardware snd_imx_hardware = {
251 .info = SNDRV_PCM_INFO_INTERLEAVED |
252 SNDRV_PCM_INFO_BLOCK_TRANSFER |
253 SNDRV_PCM_INFO_MMAP |
254 SNDRV_PCM_INFO_MMAP_VALID |
255 SNDRV_PCM_INFO_PAUSE |
256 SNDRV_PCM_INFO_RESUME,
257 .formats = SNDRV_PCM_FMTBIT_S16_LE,
258 .rate_min = 8000,
259 .channels_min = 2,
260 .channels_max = 2,
261 .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
262 .period_bytes_min = 128,
263 .period_bytes_max = 16 * 1024,
264 .periods_min = 2,
265 .periods_max = 255,
266 .fifo_size = 0,
267};
268
269static int snd_imx_open(struct snd_pcm_substream *substream)
270{
271 struct snd_pcm_runtime *runtime = substream->runtime;
272 struct imx_pcm_runtime_data *iprtd;
273 int ret;
274
275 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
276 runtime->private_data = iprtd;
277
278 ret = snd_pcm_hw_constraint_integer(substream->runtime,
279 SNDRV_PCM_HW_PARAM_PERIODS);
280 if (ret < 0)
281 return ret;
282
283 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
284 return 0;
285}
286
287static struct snd_pcm_ops imx_pcm_ops = {
288 .open = snd_imx_open,
289 .ioctl = snd_pcm_lib_ioctl,
290 .hw_params = snd_imx_pcm_hw_params,
291 .hw_free = snd_imx_pcm_hw_free,
292 .prepare = snd_imx_pcm_prepare,
293 .trigger = snd_imx_pcm_trigger,
294 .pointer = snd_imx_pcm_pointer,
295 .mmap = snd_imx_pcm_mmap,
296};
297
298static struct snd_soc_platform imx_soc_platform_dma = {
299 .name = "imx-audio",
300 .pcm_ops = &imx_pcm_ops,
301 .pcm_new = imx_pcm_new,
302 .pcm_free = imx_pcm_free,
303};
304
305struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
306 struct imx_ssi *ssi)
307{
308 ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
309 ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
310
311 return &imx_soc_platform_dma;
312}
313
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
new file mode 100644
index 00000000000..5532579ece4
--- /dev/null
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -0,0 +1,277 @@
1/*
2 * imx-pcm-fiq.c -- ALSA Soc Audio Layer
3 *
4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
5 *
6 * This code is based on code copyrighted by Freescale,
7 * Liam Girdwood, Javier Martin and probably others.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/device.h>
17#include <linux/dma-mapping.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22
23#include <sound/core.h>
24#include <sound/initval.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28
29#include <asm/fiq.h>
30
31#include <mach/ssi.h>
32
33#include "imx-ssi.h"
34
35struct imx_pcm_runtime_data {
36 int period;
37 int periods;
38 unsigned long dma_addr;
39 int dma;
40 unsigned long offset;
41 unsigned long size;
42 unsigned long period_cnt;
43 void *buf;
44 struct timer_list timer;
45 int period_time;
46};
47
48static void imx_ssi_timer_callback(unsigned long data)
49{
50 struct snd_pcm_substream *substream = (void *)data;
51 struct snd_pcm_runtime *runtime = substream->runtime;
52 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
53 struct pt_regs regs;
54
55 get_fiq_regs(&regs);
56
57 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
58 iprtd->offset = regs.ARM_r8 & 0xffff;
59 else
60 iprtd->offset = regs.ARM_r9 & 0xffff;
61
62 iprtd->timer.expires = jiffies + iprtd->period_time;
63 add_timer(&iprtd->timer);
64 snd_pcm_period_elapsed(substream);
65}
66
67static struct fiq_handler fh = {
68 .name = DRV_NAME,
69};
70
71static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
72 struct snd_pcm_hw_params *params)
73{
74 struct snd_pcm_runtime *runtime = substream->runtime;
75 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
76
77 iprtd->size = params_buffer_bytes(params);
78 iprtd->periods = params_periods(params);
79 iprtd->period = params_period_bytes(params);
80 iprtd->offset = 0;
81 iprtd->period_time = HZ / (params_rate(params) / params_period_size(params));
82
83 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
84
85 return 0;
86}
87
88static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
89{
90 struct snd_pcm_runtime *runtime = substream->runtime;
91 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
92 struct pt_regs regs;
93
94 get_fiq_regs(&regs);
95 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
96 regs.ARM_r8 = (iprtd->period * iprtd->periods - 1) << 16;
97 else
98 regs.ARM_r9 = (iprtd->period * iprtd->periods - 1) << 16;
99
100 set_fiq_regs(&regs);
101
102 return 0;
103}
104
105static int fiq_enable;
106static int imx_pcm_fiq;
107
108static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
109{
110 struct snd_pcm_runtime *runtime = substream->runtime;
111 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
112
113 switch (cmd) {
114 case SNDRV_PCM_TRIGGER_START:
115 case SNDRV_PCM_TRIGGER_RESUME:
116 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
117 iprtd->timer.expires = jiffies + iprtd->period_time;
118 add_timer(&iprtd->timer);
119 if (++fiq_enable == 1)
120 enable_fiq(imx_pcm_fiq);
121
122 break;
123
124 case SNDRV_PCM_TRIGGER_STOP:
125 case SNDRV_PCM_TRIGGER_SUSPEND:
126 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
127 del_timer(&iprtd->timer);
128 if (--fiq_enable == 0)
129 disable_fiq(imx_pcm_fiq);
130
131
132 break;
133 default:
134 return -EINVAL;
135 }
136
137 return 0;
138}
139
140static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
141{
142 struct snd_pcm_runtime *runtime = substream->runtime;
143 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
144
145 return bytes_to_frames(substream->runtime, iprtd->offset);
146}
147
148static struct snd_pcm_hardware snd_imx_hardware = {
149 .info = SNDRV_PCM_INFO_INTERLEAVED |
150 SNDRV_PCM_INFO_BLOCK_TRANSFER |
151 SNDRV_PCM_INFO_MMAP |
152 SNDRV_PCM_INFO_MMAP_VALID |
153 SNDRV_PCM_INFO_PAUSE |
154 SNDRV_PCM_INFO_RESUME,
155 .formats = SNDRV_PCM_FMTBIT_S16_LE,
156 .rate_min = 8000,
157 .channels_min = 2,
158 .channels_max = 2,
159 .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
160 .period_bytes_min = 128,
161 .period_bytes_max = 16 * 1024,
162 .periods_min = 2,
163 .periods_max = 255,
164 .fifo_size = 0,
165};
166
167static int snd_imx_open(struct snd_pcm_substream *substream)
168{
169 struct snd_pcm_runtime *runtime = substream->runtime;
170 struct imx_pcm_runtime_data *iprtd;
171 int ret;
172
173 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
174 runtime->private_data = iprtd;
175
176 init_timer(&iprtd->timer);
177 iprtd->timer.data = (unsigned long)substream;
178 iprtd->timer.function = imx_ssi_timer_callback;
179
180 ret = snd_pcm_hw_constraint_integer(substream->runtime,
181 SNDRV_PCM_HW_PARAM_PERIODS);
182 if (ret < 0)
183 return ret;
184
185 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
186 return 0;
187}
188
189static int snd_imx_close(struct snd_pcm_substream *substream)
190{
191 struct snd_pcm_runtime *runtime = substream->runtime;
192 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
193
194 del_timer_sync(&iprtd->timer);
195 kfree(iprtd);
196
197 return 0;
198}
199
200static struct snd_pcm_ops imx_pcm_ops = {
201 .open = snd_imx_open,
202 .close = snd_imx_close,
203 .ioctl = snd_pcm_lib_ioctl,
204 .hw_params = snd_imx_pcm_hw_params,
205 .prepare = snd_imx_pcm_prepare,
206 .trigger = snd_imx_pcm_trigger,
207 .pointer = snd_imx_pcm_pointer,
208 .mmap = snd_imx_pcm_mmap,
209};
210
211static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai,
212 struct snd_pcm *pcm)
213{
214 int ret;
215
216 ret = imx_pcm_new(card, dai, pcm);
217 if (ret)
218 return ret;
219
220 if (dai->playback.channels_min) {
221 struct snd_pcm_substream *substream =
222 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
223 struct snd_dma_buffer *buf = &substream->dma_buffer;
224
225 imx_ssi_fiq_tx_buffer = (unsigned long)buf->area;
226 }
227
228 if (dai->capture.channels_min) {
229 struct snd_pcm_substream *substream =
230 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
231 struct snd_dma_buffer *buf = &substream->dma_buffer;
232
233 imx_ssi_fiq_rx_buffer = (unsigned long)buf->area;
234 }
235
236 set_fiq_handler(&imx_ssi_fiq_start,
237 &imx_ssi_fiq_end - &imx_ssi_fiq_start);
238
239 return 0;
240}
241
242static struct snd_soc_platform imx_soc_platform_fiq = {
243 .pcm_ops = &imx_pcm_ops,
244 .pcm_new = imx_pcm_fiq_new,
245 .pcm_free = imx_pcm_free,
246};
247
248struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
249 struct imx_ssi *ssi)
250{
251 int ret = 0;
252
253 ret = claim_fiq(&fh);
254 if (ret) {
255 dev_err(&pdev->dev, "failed to claim fiq: %d", ret);
256 return ERR_PTR(ret);
257 }
258
259 mxc_set_irq_fiq(ssi->irq, 1);
260
261 imx_pcm_fiq = ssi->irq;
262
263 imx_ssi_fiq_base = (unsigned long)ssi->base;
264
265 ssi->dma_params_tx.burstsize = 4;
266 ssi->dma_params_rx.burstsize = 6;
267
268 return &imx_soc_platform_fiq;
269}
270
271void imx_ssi_fiq_exit(struct platform_device *pdev,
272 struct imx_ssi *ssi)
273{
274 mxc_set_irq_fiq(ssi->irq, 0);
275 release_fiq(&fh);
276}
277
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
new file mode 100644
index 00000000000..56f46a75d29
--- /dev/null
+++ b/sound/soc/imx/imx-ssi.c
@@ -0,0 +1,758 @@
1/*
2 * imx-ssi.c -- ALSA Soc Audio Layer
3 *
4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
5 *
6 * This code is based on code copyrighted by Freescale,
7 * Liam Girdwood, Javier Martin and probably others.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 *
15 * The i.MX SSI core has some nasty limitations in AC97 mode. While most
16 * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
17 * one FIFO which combines all valid receive slots. We cannot even select
18 * which slots we want to receive. The WM9712 with which this driver
19 * was developped with always sends GPIO status data in slot 12 which
20 * we receive in our (PCM-) data stream. The only chance we have is to
21 * manually skip this data in the FIQ handler. With sampling rates different
22 * from 48000Hz not every frame has valid receive data, so the ratio
23 * between pcm data and GPIO status data changes. Our FIQ handler is not
24 * able to handle this, hence this driver only works with 48000Hz sampling
25 * rate.
26 * Reading and writing AC97 registers is another challange. The core
27 * provides us status bits when the read register is updated with *another*
28 * value. When we read the same register two times (and the register still
29 * contains the same value) these status bits are not set. We work
30 * around this by not polling these bits but only wait a fixed delay.
31 *
32 */
33
34#include <linux/clk.h>
35#include <linux/delay.h>
36#include <linux/device.h>
37#include <linux/dma-mapping.h>
38#include <linux/init.h>
39#include <linux/interrupt.h>
40#include <linux/module.h>
41#include <linux/platform_device.h>
42
43#include <sound/core.h>
44#include <sound/initval.h>
45#include <sound/pcm.h>
46#include <sound/pcm_params.h>
47#include <sound/soc.h>
48
49#include <mach/ssi.h>
50#include <mach/hardware.h>
51
52#include "imx-ssi.h"
53
54#define SSI_SACNT_DEFAULT (SSI_SACNT_AC97EN | SSI_SACNT_FV)
55
56/*
57 * SSI Network Mode or TDM slots configuration.
58 * Should only be called when port is inactive (i.e. SSIEN = 0).
59 */
60static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
61 unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
62{
63 struct imx_ssi *ssi = cpu_dai->private_data;
64 u32 sccr;
65
66 sccr = readl(ssi->base + SSI_STCCR);
67 sccr &= ~SSI_STCCR_DC_MASK;
68 sccr |= SSI_STCCR_DC(slots - 1);
69 writel(sccr, ssi->base + SSI_STCCR);
70
71 sccr = readl(ssi->base + SSI_SRCCR);
72 sccr &= ~SSI_STCCR_DC_MASK;
73 sccr |= SSI_STCCR_DC(slots - 1);
74 writel(sccr, ssi->base + SSI_SRCCR);
75
76 writel(tx_mask, ssi->base + SSI_STMSK);
77 writel(rx_mask, ssi->base + SSI_SRMSK);
78
79 return 0;
80}
81
82/*
83 * SSI DAI format configuration.
84 * Should only be called when port is inactive (i.e. SSIEN = 0).
85 * Note: We don't use the I2S modes but instead manually configure the
86 * SSI for I2S because the I2S mode is only a register preset.
87 */
88static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
89{
90 struct imx_ssi *ssi = cpu_dai->private_data;
91 u32 strcr = 0, scr;
92
93 scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
94
95 /* DAI mode */
96 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
97 case SND_SOC_DAIFMT_I2S:
98 /* data on rising edge of bclk, frame low 1clk before data */
99 strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
100 scr |= SSI_SCR_NET;
101 break;
102 case SND_SOC_DAIFMT_LEFT_J:
103 /* data on rising edge of bclk, frame high with data */
104 strcr |= SSI_STCR_TXBIT0;
105 break;
106 case SND_SOC_DAIFMT_DSP_B:
107 /* data on rising edge of bclk, frame high with data */
108 strcr |= SSI_STCR_TFSL;
109 break;
110 case SND_SOC_DAIFMT_DSP_A:
111 /* data on rising edge of bclk, frame high 1clk before data */
112 strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
113 break;
114 }
115
116 /* DAI clock inversion */
117 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
118 case SND_SOC_DAIFMT_IB_IF:
119 strcr |= SSI_STCR_TFSI;
120 strcr &= ~SSI_STCR_TSCKP;
121 break;
122 case SND_SOC_DAIFMT_IB_NF:
123 strcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
124 break;
125 case SND_SOC_DAIFMT_NB_IF:
126 strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
127 break;
128 case SND_SOC_DAIFMT_NB_NF:
129 strcr &= ~SSI_STCR_TFSI;
130 strcr |= SSI_STCR_TSCKP;
131 break;
132 }
133
134 /* DAI clock master masks */
135 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
136 case SND_SOC_DAIFMT_CBM_CFM:
137 break;
138 default:
139 /* Master mode not implemented, needs handling of clocks. */
140 return -EINVAL;
141 }
142
143 strcr |= SSI_STCR_TFEN0;
144
145 writel(strcr, ssi->base + SSI_STCR);
146 writel(strcr, ssi->base + SSI_SRCR);
147 writel(scr, ssi->base + SSI_SCR);
148
149 return 0;
150}
151
152/*
153 * SSI system clock configuration.
154 * Should only be called when port is inactive (i.e. SSIEN = 0).
155 */
156static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
157 int clk_id, unsigned int freq, int dir)
158{
159 struct imx_ssi *ssi = cpu_dai->private_data;
160 u32 scr;
161
162 scr = readl(ssi->base + SSI_SCR);
163
164 switch (clk_id) {
165 case IMX_SSP_SYS_CLK:
166 if (dir == SND_SOC_CLOCK_OUT)
167 scr |= SSI_SCR_SYS_CLK_EN;
168 else
169 scr &= ~SSI_SCR_SYS_CLK_EN;
170 break;
171 default:
172 return -EINVAL;
173 }
174
175 writel(scr, ssi->base + SSI_SCR);
176
177 return 0;
178}
179
180/*
181 * SSI Clock dividers
182 * Should only be called when port is inactive (i.e. SSIEN = 0).
183 */
184static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
185 int div_id, int div)
186{
187 struct imx_ssi *ssi = cpu_dai->private_data;
188 u32 stccr, srccr;
189
190 stccr = readl(ssi->base + SSI_STCCR);
191 srccr = readl(ssi->base + SSI_SRCCR);
192
193 switch (div_id) {
194 case IMX_SSI_TX_DIV_2:
195 stccr &= ~SSI_STCCR_DIV2;
196 stccr |= div;
197 break;
198 case IMX_SSI_TX_DIV_PSR:
199 stccr &= ~SSI_STCCR_PSR;
200 stccr |= div;
201 break;
202 case IMX_SSI_TX_DIV_PM:
203 stccr &= ~0xff;
204 stccr |= SSI_STCCR_PM(div);
205 break;
206 case IMX_SSI_RX_DIV_2:
207 stccr &= ~SSI_STCCR_DIV2;
208 stccr |= div;
209 break;
210 case IMX_SSI_RX_DIV_PSR:
211 stccr &= ~SSI_STCCR_PSR;
212 stccr |= div;
213 break;
214 case IMX_SSI_RX_DIV_PM:
215 stccr &= ~0xff;
216 stccr |= SSI_STCCR_PM(div);
217 break;
218 default:
219 return -EINVAL;
220 }
221
222 writel(stccr, ssi->base + SSI_STCCR);
223 writel(srccr, ssi->base + SSI_SRCCR);
224
225 return 0;
226}
227
228/*
229 * Should only be called when port is inactive (i.e. SSIEN = 0),
230 * although can be called multiple times by upper layers.
231 */
232static int imx_ssi_hw_params(struct snd_pcm_substream *substream,
233 struct snd_pcm_hw_params *params,
234 struct snd_soc_dai *cpu_dai)
235{
236 struct imx_ssi *ssi = cpu_dai->private_data;
237 u32 reg, sccr;
238
239 /* Tx/Rx config */
240 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
241 reg = SSI_STCCR;
242 cpu_dai->dma_data = &ssi->dma_params_tx;
243 } else {
244 reg = SSI_SRCCR;
245 cpu_dai->dma_data = &ssi->dma_params_rx;
246 }
247
248 sccr = readl(ssi->base + reg) & ~SSI_STCCR_WL_MASK;
249
250 /* DAI data (word) size */
251 switch (params_format(params)) {
252 case SNDRV_PCM_FORMAT_S16_LE:
253 sccr |= SSI_SRCCR_WL(16);
254 break;
255 case SNDRV_PCM_FORMAT_S20_3LE:
256 sccr |= SSI_SRCCR_WL(20);
257 break;
258 case SNDRV_PCM_FORMAT_S24_LE:
259 sccr |= SSI_SRCCR_WL(24);
260 break;
261 }
262
263 writel(sccr, ssi->base + reg);
264
265 return 0;
266}
267
268static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
269 struct snd_soc_dai *dai)
270{
271 struct snd_soc_pcm_runtime *rtd = substream->private_data;
272 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
273 struct imx_ssi *ssi = cpu_dai->private_data;
274 unsigned int sier_bits, sier;
275 unsigned int scr;
276
277 scr = readl(ssi->base + SSI_SCR);
278 sier = readl(ssi->base + SSI_SIER);
279
280 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
281 if (ssi->flags & IMX_SSI_DMA)
282 sier_bits = SSI_SIER_TDMAE;
283 else
284 sier_bits = SSI_SIER_TIE | SSI_SIER_TFE0_EN;
285 } else {
286 if (ssi->flags & IMX_SSI_DMA)
287 sier_bits = SSI_SIER_RDMAE;
288 else
289 sier_bits = SSI_SIER_RIE | SSI_SIER_RFF0_EN;
290 }
291
292 switch (cmd) {
293 case SNDRV_PCM_TRIGGER_START:
294 case SNDRV_PCM_TRIGGER_RESUME:
295 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
296 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
297 scr |= SSI_SCR_TE;
298 else
299 scr |= SSI_SCR_RE;
300 sier |= sier_bits;
301
302 if (++ssi->enabled == 1)
303 scr |= SSI_SCR_SSIEN;
304
305 break;
306
307 case SNDRV_PCM_TRIGGER_STOP:
308 case SNDRV_PCM_TRIGGER_SUSPEND:
309 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
310 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
311 scr &= ~SSI_SCR_TE;
312 else
313 scr &= ~SSI_SCR_RE;
314 sier &= ~sier_bits;
315
316 if (--ssi->enabled == 0)
317 scr &= ~SSI_SCR_SSIEN;
318
319 break;
320 default:
321 return -EINVAL;
322 }
323
324 if (!(ssi->flags & IMX_SSI_USE_AC97))
325 /* rx/tx are always enabled to access ac97 registers */
326 writel(scr, ssi->base + SSI_SCR);
327
328 writel(sier, ssi->base + SSI_SIER);
329
330 return 0;
331}
332
333static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
334 .hw_params = imx_ssi_hw_params,
335 .set_fmt = imx_ssi_set_dai_fmt,
336 .set_clkdiv = imx_ssi_set_dai_clkdiv,
337 .set_sysclk = imx_ssi_set_dai_sysclk,
338 .set_tdm_slot = imx_ssi_set_dai_tdm_slot,
339 .trigger = imx_ssi_trigger,
340};
341
342static struct snd_soc_dai imx_ssi_dai = {
343 .playback = {
344 .channels_min = 2,
345 .channels_max = 2,
346 .rates = SNDRV_PCM_RATE_8000_96000,
347 .formats = SNDRV_PCM_FMTBIT_S16_LE,
348 },
349 .capture = {
350 .channels_min = 2,
351 .channels_max = 2,
352 .rates = SNDRV_PCM_RATE_8000_96000,
353 .formats = SNDRV_PCM_FMTBIT_S16_LE,
354 },
355 .ops = &imx_ssi_pcm_dai_ops,
356};
357
358int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
359 struct vm_area_struct *vma)
360{
361 struct snd_pcm_runtime *runtime = substream->runtime;
362 int ret;
363
364 ret = dma_mmap_coherent(NULL, vma, runtime->dma_area,
365 runtime->dma_addr, runtime->dma_bytes);
366
367 pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret,
368 runtime->dma_area,
369 runtime->dma_addr,
370 runtime->dma_bytes);
371 return ret;
372}
373
374static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
375{
376 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
377 struct snd_dma_buffer *buf = &substream->dma_buffer;
378 size_t size = IMX_SSI_DMABUF_SIZE;
379
380 buf->dev.type = SNDRV_DMA_TYPE_DEV;
381 buf->dev.dev = pcm->card->dev;
382 buf->private_data = NULL;
383 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
384 &buf->addr, GFP_KERNEL);
385 if (!buf->area)
386 return -ENOMEM;
387 buf->bytes = size;
388
389 return 0;
390}
391
392static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
393
394int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
395 struct snd_pcm *pcm)
396{
397
398 int ret = 0;
399
400 if (!card->dev->dma_mask)
401 card->dev->dma_mask = &imx_pcm_dmamask;
402 if (!card->dev->coherent_dma_mask)
403 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
404 if (dai->playback.channels_min) {
405 ret = imx_pcm_preallocate_dma_buffer(pcm,
406 SNDRV_PCM_STREAM_PLAYBACK);
407 if (ret)
408 goto out;
409 }
410
411 if (dai->capture.channels_min) {
412 ret = imx_pcm_preallocate_dma_buffer(pcm,
413 SNDRV_PCM_STREAM_CAPTURE);
414 if (ret)
415 goto out;
416 }
417
418out:
419 return ret;
420}
421
422void imx_pcm_free(struct snd_pcm *pcm)
423{
424 struct snd_pcm_substream *substream;
425 struct snd_dma_buffer *buf;
426 int stream;
427
428 for (stream = 0; stream < 2; stream++) {
429 substream = pcm->streams[stream].substream;
430 if (!substream)
431 continue;
432
433 buf = &substream->dma_buffer;
434 if (!buf->area)
435 continue;
436
437 dma_free_writecombine(pcm->card->dev, buf->bytes,
438 buf->area, buf->addr);
439 buf->area = NULL;
440 }
441}
442
443struct snd_soc_platform imx_soc_platform = {
444 .name = "imx-audio",
445};
446EXPORT_SYMBOL_GPL(imx_soc_platform);
447
448static struct snd_soc_dai imx_ac97_dai = {
449 .name = "AC97",
450 .ac97_control = 1,
451 .playback = {
452 .stream_name = "AC97 Playback",
453 .channels_min = 2,
454 .channels_max = 2,
455 .rates = SNDRV_PCM_RATE_48000,
456 .formats = SNDRV_PCM_FMTBIT_S16_LE,
457 },
458 .capture = {
459 .stream_name = "AC97 Capture",
460 .channels_min = 2,
461 .channels_max = 2,
462 .rates = SNDRV_PCM_RATE_48000,
463 .formats = SNDRV_PCM_FMTBIT_S16_LE,
464 },
465 .ops = &imx_ssi_pcm_dai_ops,
466};
467
468static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
469{
470 void __iomem *base = imx_ssi->base;
471
472 writel(0x0, base + SSI_SCR);
473 writel(0x0, base + SSI_STCR);
474 writel(0x0, base + SSI_SRCR);
475
476 writel(SSI_SCR_SYN | SSI_SCR_NET, base + SSI_SCR);
477
478 writel(SSI_SFCSR_RFWM0(8) |
479 SSI_SFCSR_TFWM0(8) |
480 SSI_SFCSR_RFWM1(8) |
481 SSI_SFCSR_TFWM1(8), base + SSI_SFCSR);
482
483 writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_STCCR);
484 writel(SSI_STCCR_WL(16) | SSI_STCCR_DC(12), base + SSI_SRCCR);
485
486 writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN, base + SSI_SCR);
487 writel(SSI_SOR_WAIT(3), base + SSI_SOR);
488
489 writel(SSI_SCR_SYN | SSI_SCR_NET | SSI_SCR_SSIEN |
490 SSI_SCR_TE | SSI_SCR_RE,
491 base + SSI_SCR);
492
493 writel(SSI_SACNT_DEFAULT, base + SSI_SACNT);
494 writel(0xff, base + SSI_SACCDIS);
495 writel(0x300, base + SSI_SACCEN);
496}
497
498static struct imx_ssi *ac97_ssi;
499
500static void imx_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
501 unsigned short val)
502{
503 struct imx_ssi *imx_ssi = ac97_ssi;
504 void __iomem *base = imx_ssi->base;
505 unsigned int lreg;
506 unsigned int lval;
507
508 if (reg > 0x7f)
509 return;
510
511 pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
512
513 lreg = reg << 12;
514 writel(lreg, base + SSI_SACADD);
515
516 lval = val << 4;
517 writel(lval , base + SSI_SACDAT);
518
519 writel(SSI_SACNT_DEFAULT | SSI_SACNT_WR, base + SSI_SACNT);
520 udelay(100);
521}
522
523static unsigned short imx_ssi_ac97_read(struct snd_ac97 *ac97,
524 unsigned short reg)
525{
526 struct imx_ssi *imx_ssi = ac97_ssi;
527 void __iomem *base = imx_ssi->base;
528
529 unsigned short val = -1;
530 unsigned int lreg;
531
532 lreg = (reg & 0x7f) << 12 ;
533 writel(lreg, base + SSI_SACADD);
534 writel(SSI_SACNT_DEFAULT | SSI_SACNT_RD, base + SSI_SACNT);
535
536 udelay(100);
537
538 val = (readl(base + SSI_SACDAT) >> 4) & 0xffff;
539
540 pr_debug("%s: 0x%02x 0x%04x\n", __func__, reg, val);
541
542 return val;
543}
544
545static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
546{
547 struct imx_ssi *imx_ssi = ac97_ssi;
548
549 if (imx_ssi->ac97_reset)
550 imx_ssi->ac97_reset(ac97);
551}
552
553static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
554{
555 struct imx_ssi *imx_ssi = ac97_ssi;
556
557 if (imx_ssi->ac97_warm_reset)
558 imx_ssi->ac97_warm_reset(ac97);
559}
560
561struct snd_ac97_bus_ops soc_ac97_ops = {
562 .read = imx_ssi_ac97_read,
563 .write = imx_ssi_ac97_write,
564 .reset = imx_ssi_ac97_reset,
565 .warm_reset = imx_ssi_ac97_warm_reset
566};
567EXPORT_SYMBOL_GPL(soc_ac97_ops);
568
569struct snd_soc_dai imx_ssi_pcm_dai[2];
570EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
571
572static int imx_ssi_probe(struct platform_device *pdev)
573{
574 struct resource *res;
575 struct imx_ssi *ssi;
576 struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
577 struct snd_soc_platform *platform;
578 int ret = 0;
579 unsigned int val;
580 struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
581
582 if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai))
583 return -EINVAL;
584
585 ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
586 if (!ssi)
587 return -ENOMEM;
588
589 if (pdata) {
590 ssi->ac97_reset = pdata->ac97_reset;
591 ssi->ac97_warm_reset = pdata->ac97_warm_reset;
592 ssi->flags = pdata->flags;
593 }
594
595 ssi->irq = platform_get_irq(pdev, 0);
596
597 ssi->clk = clk_get(&pdev->dev, NULL);
598 if (IS_ERR(ssi->clk)) {
599 ret = PTR_ERR(ssi->clk);
600 dev_err(&pdev->dev, "Cannot get the clock: %d\n",
601 ret);
602 goto failed_clk;
603 }
604 clk_enable(ssi->clk);
605
606 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
607 if (!res) {
608 ret = -ENODEV;
609 goto failed_get_resource;
610 }
611
612 if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
613 dev_err(&pdev->dev, "request_mem_region failed\n");
614 ret = -EBUSY;
615 goto failed_get_resource;
616 }
617
618 ssi->base = ioremap(res->start, resource_size(res));
619 if (!ssi->base) {
620 dev_err(&pdev->dev, "ioremap failed\n");
621 ret = -ENODEV;
622 goto failed_ioremap;
623 }
624
625 if (ssi->flags & IMX_SSI_USE_AC97) {
626 if (ac97_ssi) {
627 ret = -EBUSY;
628 goto failed_ac97;
629 }
630 ac97_ssi = ssi;
631 setup_channel_to_ac97(ssi);
632 memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
633 } else
634 memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
635
636 writel(0x0, ssi->base + SSI_SIER);
637
638 ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
639 ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
640
641 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
642 if (res)
643 ssi->dma_params_tx.dma = res->start;
644
645 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
646 if (res)
647 ssi->dma_params_rx.dma = res->start;
648
649 dai->id = pdev->id;
650 dai->dev = &pdev->dev;
651 dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
652 dai->private_data = ssi;
653
654 if ((cpu_is_mx27() || cpu_is_mx21()) &&
655 !(ssi->flags & IMX_SSI_USE_AC97)) {
656 ssi->flags |= IMX_SSI_DMA;
657 platform = imx_ssi_dma_mx2_init(pdev, ssi);
658 } else
659 platform = imx_ssi_fiq_init(pdev, ssi);
660
661 imx_soc_platform.pcm_ops = platform->pcm_ops;
662 imx_soc_platform.pcm_new = platform->pcm_new;
663 imx_soc_platform.pcm_free = platform->pcm_free;
664
665 val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
666 SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
667 writel(val, ssi->base + SSI_SFCSR);
668
669 ret = snd_soc_register_dai(dai);
670 if (ret) {
671 dev_err(&pdev->dev, "register DAI failed\n");
672 goto failed_register;
673 }
674
675 platform_set_drvdata(pdev, ssi);
676
677 return 0;
678
679failed_register:
680failed_ac97:
681 iounmap(ssi->base);
682failed_ioremap:
683 release_mem_region(res->start, resource_size(res));
684failed_get_resource:
685 clk_disable(ssi->clk);
686 clk_put(ssi->clk);
687failed_clk:
688 kfree(ssi);
689
690 return ret;
691}
692
693static int __devexit imx_ssi_remove(struct platform_device *pdev)
694{
695 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
696 struct imx_ssi *ssi = platform_get_drvdata(pdev);
697 struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
698
699 snd_soc_unregister_dai(dai);
700
701 if (ssi->flags & IMX_SSI_USE_AC97)
702 ac97_ssi = NULL;
703
704 if (!(ssi->flags & IMX_SSI_DMA))
705 imx_ssi_fiq_exit(pdev, ssi);
706
707 iounmap(ssi->base);
708 release_mem_region(res->start, resource_size(res));
709 clk_disable(ssi->clk);
710 clk_put(ssi->clk);
711 kfree(ssi);
712
713 return 0;
714}
715
716static struct platform_driver imx_ssi_driver = {
717 .probe = imx_ssi_probe,
718 .remove = __devexit_p(imx_ssi_remove),
719
720 .driver = {
721 .name = DRV_NAME,
722 .owner = THIS_MODULE,
723 },
724};
725
726static int __init imx_ssi_init(void)
727{
728 int ret;
729
730 ret = snd_soc_register_platform(&imx_soc_platform);
731 if (ret) {
732 pr_err("failed to register soc platform: %d\n", ret);
733 return ret;
734 }
735
736 ret = platform_driver_register(&imx_ssi_driver);
737 if (ret) {
738 snd_soc_unregister_platform(&imx_soc_platform);
739 return ret;
740 }
741
742 return 0;
743}
744
745static void __exit imx_ssi_exit(void)
746{
747 platform_driver_unregister(&imx_ssi_driver);
748 snd_soc_unregister_platform(&imx_soc_platform);
749}
750
751module_init(imx_ssi_init);
752module_exit(imx_ssi_exit);
753
754/* Module information */
755MODULE_AUTHOR("Sascha Hauer, <s.hauer@pengutronix.de>");
756MODULE_DESCRIPTION("i.MX I2S/ac97 SoC Interface");
757MODULE_LICENSE("GPL");
758
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h
new file mode 100644
index 00000000000..55f26ebcd8c
--- /dev/null
+++ b/sound/soc/imx/imx-ssi.h
@@ -0,0 +1,237 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 */
6
7#ifndef _IMX_SSI_H
8#define _IMX_SSI_H
9
10#define SSI_STX0 0x00
11#define SSI_STX1 0x04
12#define SSI_SRX0 0x08
13#define SSI_SRX1 0x0c
14
15#define SSI_SCR 0x10
16#define SSI_SCR_CLK_IST (1 << 9)
17#define SSI_SCR_CLK_IST_SHIFT 9
18#define SSI_SCR_TCH_EN (1 << 8)
19#define SSI_SCR_SYS_CLK_EN (1 << 7)
20#define SSI_SCR_I2S_MODE_NORM (0 << 5)
21#define SSI_SCR_I2S_MODE_MSTR (1 << 5)
22#define SSI_SCR_I2S_MODE_SLAVE (2 << 5)
23#define SSI_I2S_MODE_MASK (3 << 5)
24#define SSI_SCR_SYN (1 << 4)
25#define SSI_SCR_NET (1 << 3)
26#define SSI_SCR_RE (1 << 2)
27#define SSI_SCR_TE (1 << 1)
28#define SSI_SCR_SSIEN (1 << 0)
29
30#define SSI_SISR 0x14
31#define SSI_SISR_MASK ((1 << 19) - 1)
32#define SSI_SISR_CMDAU (1 << 18)
33#define SSI_SISR_CMDDU (1 << 17)
34#define SSI_SISR_RXT (1 << 16)
35#define SSI_SISR_RDR1 (1 << 15)
36#define SSI_SISR_RDR0 (1 << 14)
37#define SSI_SISR_TDE1 (1 << 13)
38#define SSI_SISR_TDE0 (1 << 12)
39#define SSI_SISR_ROE1 (1 << 11)
40#define SSI_SISR_ROE0 (1 << 10)
41#define SSI_SISR_TUE1 (1 << 9)
42#define SSI_SISR_TUE0 (1 << 8)
43#define SSI_SISR_TFS (1 << 7)
44#define SSI_SISR_RFS (1 << 6)
45#define SSI_SISR_TLS (1 << 5)
46#define SSI_SISR_RLS (1 << 4)
47#define SSI_SISR_RFF1 (1 << 3)
48#define SSI_SISR_RFF0 (1 << 2)
49#define SSI_SISR_TFE1 (1 << 1)
50#define SSI_SISR_TFE0 (1 << 0)
51
52#define SSI_SIER 0x18
53#define SSI_SIER_RDMAE (1 << 22)
54#define SSI_SIER_RIE (1 << 21)
55#define SSI_SIER_TDMAE (1 << 20)
56#define SSI_SIER_TIE (1 << 19)
57#define SSI_SIER_CMDAU_EN (1 << 18)
58#define SSI_SIER_CMDDU_EN (1 << 17)
59#define SSI_SIER_RXT_EN (1 << 16)
60#define SSI_SIER_RDR1_EN (1 << 15)
61#define SSI_SIER_RDR0_EN (1 << 14)
62#define SSI_SIER_TDE1_EN (1 << 13)
63#define SSI_SIER_TDE0_EN (1 << 12)
64#define SSI_SIER_ROE1_EN (1 << 11)
65#define SSI_SIER_ROE0_EN (1 << 10)
66#define SSI_SIER_TUE1_EN (1 << 9)
67#define SSI_SIER_TUE0_EN (1 << 8)
68#define SSI_SIER_TFS_EN (1 << 7)
69#define SSI_SIER_RFS_EN (1 << 6)
70#define SSI_SIER_TLS_EN (1 << 5)
71#define SSI_SIER_RLS_EN (1 << 4)
72#define SSI_SIER_RFF1_EN (1 << 3)
73#define SSI_SIER_RFF0_EN (1 << 2)
74#define SSI_SIER_TFE1_EN (1 << 1)
75#define SSI_SIER_TFE0_EN (1 << 0)
76
77#define SSI_STCR 0x1c
78#define SSI_STCR_TXBIT0 (1 << 9)
79#define SSI_STCR_TFEN1 (1 << 8)
80#define SSI_STCR_TFEN0 (1 << 7)
81#define SSI_FIFO_ENABLE_0_SHIFT 7
82#define SSI_STCR_TFDIR (1 << 6)
83#define SSI_STCR_TXDIR (1 << 5)
84#define SSI_STCR_TSHFD (1 << 4)
85#define SSI_STCR_TSCKP (1 << 3)
86#define SSI_STCR_TFSI (1 << 2)
87#define SSI_STCR_TFSL (1 << 1)
88#define SSI_STCR_TEFS (1 << 0)
89
90#define SSI_SRCR 0x20
91#define SSI_SRCR_RXBIT0 (1 << 9)
92#define SSI_SRCR_RFEN1 (1 << 8)
93#define SSI_SRCR_RFEN0 (1 << 7)
94#define SSI_FIFO_ENABLE_0_SHIFT 7
95#define SSI_SRCR_RFDIR (1 << 6)
96#define SSI_SRCR_RXDIR (1 << 5)
97#define SSI_SRCR_RSHFD (1 << 4)
98#define SSI_SRCR_RSCKP (1 << 3)
99#define SSI_SRCR_RFSI (1 << 2)
100#define SSI_SRCR_RFSL (1 << 1)
101#define SSI_SRCR_REFS (1 << 0)
102
103#define SSI_SRCCR 0x28
104#define SSI_SRCCR_DIV2 (1 << 18)
105#define SSI_SRCCR_PSR (1 << 17)
106#define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13)
107#define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8)
108#define SSI_SRCCR_PM(x) (((x) & 0xff) << 0)
109#define SSI_SRCCR_WL_MASK (0xf << 13)
110#define SSI_SRCCR_DC_MASK (0x1f << 8)
111#define SSI_SRCCR_PM_MASK (0xff << 0)
112
113#define SSI_STCCR 0x24
114#define SSI_STCCR_DIV2 (1 << 18)
115#define SSI_STCCR_PSR (1 << 17)
116#define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13)
117#define SSI_STCCR_DC(x) (((x) & 0x1f) << 8)
118#define SSI_STCCR_PM(x) (((x) & 0xff) << 0)
119#define SSI_STCCR_WL_MASK (0xf << 13)
120#define SSI_STCCR_DC_MASK (0x1f << 8)
121#define SSI_STCCR_PM_MASK (0xff << 0)
122
123#define SSI_SFCSR 0x2c
124#define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28)
125#define SSI_RX_FIFO_1_COUNT_SHIFT 28
126#define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24)
127#define SSI_TX_FIFO_1_COUNT_SHIFT 24
128#define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20)
129#define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16)
130#define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12)
131#define SSI_RX_FIFO_0_COUNT_SHIFT 12
132#define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) << 8)
133#define SSI_TX_FIFO_0_COUNT_SHIFT 8
134#define SSI_SFCSR_RFWM0(x) (((x) & 0xf) << 4)
135#define SSI_SFCSR_TFWM0(x) (((x) & 0xf) << 0)
136#define SSI_SFCSR_RFWM0_MASK (0xf << 4)
137#define SSI_SFCSR_TFWM0_MASK (0xf << 0)
138
139#define SSI_STR 0x30
140#define SSI_STR_TEST (1 << 15)
141#define SSI_STR_RCK2TCK (1 << 14)
142#define SSI_STR_RFS2TFS (1 << 13)
143#define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8)
144#define SSI_STR_TXD2RXD (1 << 7)
145#define SSI_STR_TCK2RCK (1 << 6)
146#define SSI_STR_TFS2RFS (1 << 5)
147#define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0)
148
149#define SSI_SOR 0x34
150#define SSI_SOR_CLKOFF (1 << 6)
151#define SSI_SOR_RX_CLR (1 << 5)
152#define SSI_SOR_TX_CLR (1 << 4)
153#define SSI_SOR_INIT (1 << 3)
154#define SSI_SOR_WAIT(x) (((x) & 0x3) << 1)
155#define SSI_SOR_WAIT_MASK (0x3 << 1)
156#define SSI_SOR_SYNRST (1 << 0)
157
158#define SSI_SACNT 0x38
159#define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5)
160#define SSI_SACNT_WR (1 << 4)
161#define SSI_SACNT_RD (1 << 3)
162#define SSI_SACNT_TIF (1 << 2)
163#define SSI_SACNT_FV (1 << 1)
164#define SSI_SACNT_AC97EN (1 << 0)
165
166#define SSI_SACADD 0x3c
167#define SSI_SACDAT 0x40
168#define SSI_SATAG 0x44
169#define SSI_STMSK 0x48
170#define SSI_SRMSK 0x4c
171#define SSI_SACCST 0x50
172#define SSI_SACCEN 0x54
173#define SSI_SACCDIS 0x58
174
175/* SSI clock sources */
176#define IMX_SSP_SYS_CLK 0
177
178/* SSI audio dividers */
179#define IMX_SSI_TX_DIV_2 0
180#define IMX_SSI_TX_DIV_PSR 1
181#define IMX_SSI_TX_DIV_PM 2
182#define IMX_SSI_RX_DIV_2 3
183#define IMX_SSI_RX_DIV_PSR 4
184#define IMX_SSI_RX_DIV_PM 5
185
186extern struct snd_soc_dai imx_ssi_pcm_dai[2];
187extern struct snd_soc_platform imx_soc_platform;
188
189#define DRV_NAME "imx-ssi"
190
191struct imx_pcm_dma_params {
192 int dma;
193 unsigned long dma_addr;
194 int burstsize;
195};
196
197struct imx_ssi {
198 struct platform_device *ac97_dev;
199
200 struct snd_soc_device imx_ac97;
201 struct clk *clk;
202 void __iomem *base;
203 int irq;
204 int fiq_enable;
205 unsigned int offset;
206
207 unsigned int flags;
208
209 void (*ac97_reset) (struct snd_ac97 *ac97);
210 void (*ac97_warm_reset)(struct snd_ac97 *ac97);
211
212 struct imx_pcm_dma_params dma_params_rx;
213 struct imx_pcm_dma_params dma_params_tx;
214
215 int enabled;
216};
217
218struct snd_soc_platform *imx_ssi_fiq_init(struct platform_device *pdev,
219 struct imx_ssi *ssi);
220void imx_ssi_fiq_exit(struct platform_device *pdev, struct imx_ssi *ssi);
221struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
222 struct imx_ssi *ssi);
223
224int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
225int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
226 struct snd_pcm *pcm);
227void imx_pcm_free(struct snd_pcm *pcm);
228
229/*
230 * Do not change this as the FIQ handler depends on this size
231 */
232#define IMX_SSI_DMABUF_SIZE (64 * 1024)
233
234#define DMA_RXFIFO_BURST 0x4
235#define DMA_TXFIFO_BURST 0x6
236
237#endif /* _IMX_SSI_H */
diff --git a/sound/soc/imx/mx1_mx2-pcm.c b/sound/soc/imx/mx1_mx2-pcm.c
deleted file mode 100644
index bffffcd5ff3..00000000000
--- a/sound/soc/imx/mx1_mx2-pcm.c
+++ /dev/null
@@ -1,488 +0,0 @@
1/*
2 * mx1_mx2-pcm.c -- ALSA SoC interface for Freescale i.MX1x, i.MX2x CPUs
3 *
4 * Copyright 2009 Vista Silicon S.L.
5 * Author: Javier Martin
6 * javier.martin@vista-silicon.com
7 *
8 * Based on mxc-pcm.c by Liam Girdwood.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/dma-mapping.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <asm/dma.h>
27#include <mach/hardware.h>
28#include <mach/dma-mx1-mx2.h>
29
30#include "mx1_mx2-pcm.h"
31
32
33static const struct snd_pcm_hardware mx1_mx2_pcm_hardware = {
34 .info = (SNDRV_PCM_INFO_INTERLEAVED |
35 SNDRV_PCM_INFO_BLOCK_TRANSFER |
36 SNDRV_PCM_INFO_MMAP |
37 SNDRV_PCM_INFO_MMAP_VALID),
38 .formats = SNDRV_PCM_FMTBIT_S16_LE,
39 .buffer_bytes_max = 32 * 1024,
40 .period_bytes_min = 64,
41 .period_bytes_max = 8 * 1024,
42 .periods_min = 2,
43 .periods_max = 255,
44 .fifo_size = 0,
45};
46
47struct mx1_mx2_runtime_data {
48 int dma_ch;
49 int active;
50 unsigned int period;
51 unsigned int periods;
52 int tx_spin;
53 spinlock_t dma_lock;
54 struct mx1_mx2_pcm_dma_params *dma_params;
55};
56
57
58/**
59 * This function stops the current dma transfer for playback
60 * and clears the dma pointers.
61 *
62 * @param substream pointer to the structure of the current stream.
63 *
64 */
65static int audio_stop_dma(struct snd_pcm_substream *substream)
66{
67 struct snd_pcm_runtime *runtime = substream->runtime;
68 struct mx1_mx2_runtime_data *prtd = runtime->private_data;
69 unsigned long flags;
70
71 spin_lock_irqsave(&prtd->dma_lock, flags);
72
73 pr_debug("%s\n", __func__);
74
75 prtd->active = 0;
76 prtd->period = 0;
77 prtd->periods = 0;
78
79 /* this stops the dma channel and clears the buffer ptrs */
80
81 imx_dma_disable(prtd->dma_ch);
82
83 spin_unlock_irqrestore(&prtd->dma_lock, flags);
84
85 return 0;
86}
87
88/**
89 * This function is called whenever a new audio block needs to be
90 * transferred to the codec. The function receives the address and the size
91 * of the new block and start a new DMA transfer.
92 *
93 * @param substream pointer to the structure of the current stream.
94 *
95 */
96static int dma_new_period(struct snd_pcm_substream *substream)
97{
98 struct snd_pcm_runtime *runtime = substream->runtime;
99 struct mx1_mx2_runtime_data *prtd = runtime->private_data;
100 unsigned int dma_size;
101 unsigned int offset;
102 int ret = 0;
103 dma_addr_t mem_addr;
104 unsigned int dev_addr;
105
106 if (prtd->active) {
107 dma_size = frames_to_bytes(runtime, runtime->period_size);
108 offset = dma_size * prtd->period;
109
110 pr_debug("%s: period (%d) out of (%d)\n", __func__,
111 prtd->period,
112 runtime->periods);
113 pr_debug("period_size %d frames\n offset %d bytes\n",
114 (unsigned int)runtime->period_size,
115 offset);
116 pr_debug("dma_size %d bytes\n", dma_size);
117
118 snd_BUG_ON(dma_size > mx1_mx2_pcm_hardware.period_bytes_max);
119
120 mem_addr = (dma_addr_t)(runtime->dma_addr + offset);
121 dev_addr = prtd->dma_params->per_address;
122 pr_debug("%s: mem_addr is %x\n dev_addr is %x\n",
123 __func__, mem_addr, dev_addr);
124
125 ret = imx_dma_setup_single(prtd->dma_ch, mem_addr,
126 dma_size, dev_addr,
127 prtd->dma_params->transfer_type);
128 if (ret < 0) {
129 printk(KERN_ERR "Error %d configuring DMA\n", ret);
130 return ret;
131 }
132 imx_dma_enable(prtd->dma_ch);
133
134 pr_debug("%s: transfer enabled\nmem_addr = %x\n",
135 __func__, (unsigned int) mem_addr);
136 pr_debug("dev_addr = %x\ndma_size = %d\n",
137 (unsigned int) dev_addr, dma_size);
138
139 prtd->tx_spin = 1; /* FGA little trick to retrieve DMA pos */
140 prtd->period++;
141 prtd->period %= runtime->periods;
142 }
143 return ret;
144}
145
146
147/**
148 * This is a callback which will be called
149 * when a TX transfer finishes. The call occurs
150 * in interrupt context.
151 *
152 * @param dat pointer to the structure of the current stream.
153 *
154 */
155static void audio_dma_irq(int channel, void *data)
156{
157 struct snd_pcm_substream *substream;
158 struct snd_pcm_runtime *runtime;
159 struct mx1_mx2_runtime_data *prtd;
160 unsigned int dma_size;
161 unsigned int previous_period;
162 unsigned int offset;
163
164 substream = data;
165 runtime = substream->runtime;
166 prtd = runtime->private_data;
167 previous_period = prtd->periods;
168 dma_size = frames_to_bytes(runtime, runtime->period_size);
169 offset = dma_size * previous_period;
170
171 prtd->tx_spin = 0;
172 prtd->periods++;
173 prtd->periods %= runtime->periods;
174
175 pr_debug("%s: irq per %d offset %x\n", __func__, prtd->periods, offset);
176
177 /*
178 * If we are getting a callback for an active stream then we inform
179 * the PCM middle layer we've finished a period
180 */
181 if (prtd->active)
182 snd_pcm_period_elapsed(substream);
183
184 /*
185 * Trig next DMA transfer
186 */
187 dma_new_period(substream);
188}
189
190/**
191 * This function configures the hardware to allow audio
192 * playback operations. It is called by ALSA framework.
193 *
194 * @param substream pointer to the structure of the current stream.
195 *
196 * @return 0 on success, -1 otherwise.
197 */
198static int
199snd_mx1_mx2_prepare(struct snd_pcm_substream *substream)
200{
201 struct snd_pcm_runtime *runtime = substream->runtime;
202 struct mx1_mx2_runtime_data *prtd = runtime->private_data;
203
204 prtd->period = 0;
205 prtd->periods = 0;
206
207 return 0;
208}
209
210static int mx1_mx2_pcm_hw_params(struct snd_pcm_substream *substream,
211 struct snd_pcm_hw_params *hw_params)
212{
213 struct snd_pcm_runtime *runtime = substream->runtime;
214 int ret;
215
216 ret = snd_pcm_lib_malloc_pages(substream,
217 params_buffer_bytes(hw_params));
218 if (ret < 0) {
219 printk(KERN_ERR "%s: Error %d failed to malloc pcm pages \n",
220 __func__, ret);
221 return ret;
222 }
223
224 pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_addr 0x(%x)\n",
225 __func__, (unsigned int)runtime->dma_addr);
226 pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_area 0x(%x)\n",
227 __func__, (unsigned int)runtime->dma_area);
228 pr_debug("%s: snd_imx1_mx2_audio_hw_params runtime->dma_bytes 0x(%x)\n",
229 __func__, (unsigned int)runtime->dma_bytes);
230
231 return ret;
232}
233
234static int mx1_mx2_pcm_hw_free(struct snd_pcm_substream *substream)
235{
236 struct snd_pcm_runtime *runtime = substream->runtime;
237 struct mx1_mx2_runtime_data *prtd = runtime->private_data;
238
239 imx_dma_free(prtd->dma_ch);
240
241 snd_pcm_lib_free_pages(substream);
242
243 return 0;
244}
245
246static int mx1_mx2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
247{
248 struct mx1_mx2_runtime_data *prtd = substream->runtime->private_data;
249 int ret = 0;
250
251 switch (cmd) {
252 case SNDRV_PCM_TRIGGER_START:
253 prtd->tx_spin = 0;
254 /* requested stream startup */
255 prtd->active = 1;
256 pr_debug("%s: starting dma_new_period\n", __func__);
257 ret = dma_new_period(substream);
258 break;
259 case SNDRV_PCM_TRIGGER_STOP:
260 /* requested stream shutdown */
261 pr_debug("%s: stopping dma transfer\n", __func__);
262 ret = audio_stop_dma(substream);
263 break;
264 default:
265 ret = -EINVAL;
266 break;
267 }
268
269 return ret;
270}
271
272static snd_pcm_uframes_t
273mx1_mx2_pcm_pointer(struct snd_pcm_substream *substream)
274{
275 struct snd_pcm_runtime *runtime = substream->runtime;
276 struct mx1_mx2_runtime_data *prtd = runtime->private_data;
277 unsigned int offset = 0;
278
279 /* tx_spin value is used here to check if a transfer is active */
280 if (prtd->tx_spin) {
281 offset = (runtime->period_size * (prtd->periods)) +
282 (runtime->period_size >> 1);
283 if (offset >= runtime->buffer_size)
284 offset = runtime->period_size >> 1;
285 } else {
286 offset = (runtime->period_size * (prtd->periods));
287 if (offset >= runtime->buffer_size)
288 offset = 0;
289 }
290 pr_debug("%s: pointer offset %x\n", __func__, offset);
291
292 return offset;
293}
294
295static int mx1_mx2_pcm_open(struct snd_pcm_substream *substream)
296{
297 struct snd_pcm_runtime *runtime = substream->runtime;
298 struct mx1_mx2_runtime_data *prtd;
299 struct snd_soc_pcm_runtime *rtd = substream->private_data;
300 struct mx1_mx2_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data;
301 int ret;
302
303 snd_soc_set_runtime_hwparams(substream, &mx1_mx2_pcm_hardware);
304
305 ret = snd_pcm_hw_constraint_integer(runtime,
306 SNDRV_PCM_HW_PARAM_PERIODS);
307 if (ret < 0)
308 return ret;
309
310 prtd = kzalloc(sizeof(struct mx1_mx2_runtime_data), GFP_KERNEL);
311 if (prtd == NULL) {
312 ret = -ENOMEM;
313 goto out;
314 }
315
316 runtime->private_data = prtd;
317
318 if (!dma_data)
319 return -ENODEV;
320
321 prtd->dma_params = dma_data;
322
323 pr_debug("%s: Requesting dma channel (%s)\n", __func__,
324 prtd->dma_params->name);
325 ret = imx_dma_request_by_prio(prtd->dma_params->name, DMA_PRIO_HIGH);
326 if (ret < 0) {
327 printk(KERN_ERR "Error %d requesting dma channel\n", ret);
328 return ret;
329 }
330 prtd->dma_ch = ret;
331 imx_dma_config_burstlen(prtd->dma_ch,
332 prtd->dma_params->watermark_level);
333
334 ret = imx_dma_config_channel(prtd->dma_ch,
335 prtd->dma_params->per_config,
336 prtd->dma_params->mem_config,
337 prtd->dma_params->event_id, 0);
338
339 if (ret) {
340 pr_debug(KERN_ERR "Error %d configuring dma channel %d\n",
341 ret, prtd->dma_ch);
342 return ret;
343 }
344
345 pr_debug("%s: Setting tx dma callback function\n", __func__);
346 ret = imx_dma_setup_handlers(prtd->dma_ch,
347 audio_dma_irq, NULL,
348 (void *)substream);
349 if (ret < 0) {
350 printk(KERN_ERR "Error %d setting dma callback function\n", ret);
351 return ret;
352 }
353 return 0;
354
355 out:
356 return ret;
357}
358
359static int mx1_mx2_pcm_close(struct snd_pcm_substream *substream)
360{
361 struct snd_pcm_runtime *runtime = substream->runtime;
362 struct mx1_mx2_runtime_data *prtd = runtime->private_data;
363
364 kfree(prtd);
365
366 return 0;
367}
368
369static int mx1_mx2_pcm_mmap(struct snd_pcm_substream *substream,
370 struct vm_area_struct *vma)
371{
372 struct snd_pcm_runtime *runtime = substream->runtime;
373 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
374 runtime->dma_area,
375 runtime->dma_addr,
376 runtime->dma_bytes);
377}
378
379static struct snd_pcm_ops mx1_mx2_pcm_ops = {
380 .open = mx1_mx2_pcm_open,
381 .close = mx1_mx2_pcm_close,
382 .ioctl = snd_pcm_lib_ioctl,
383 .hw_params = mx1_mx2_pcm_hw_params,
384 .hw_free = mx1_mx2_pcm_hw_free,
385 .prepare = snd_mx1_mx2_prepare,
386 .trigger = mx1_mx2_pcm_trigger,
387 .pointer = mx1_mx2_pcm_pointer,
388 .mmap = mx1_mx2_pcm_mmap,
389};
390
391static u64 mx1_mx2_pcm_dmamask = 0xffffffff;
392
393static int mx1_mx2_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
394{
395 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
396 struct snd_dma_buffer *buf = &substream->dma_buffer;
397 size_t size = mx1_mx2_pcm_hardware.buffer_bytes_max;
398 buf->dev.type = SNDRV_DMA_TYPE_DEV;
399 buf->dev.dev = pcm->card->dev;
400 buf->private_data = NULL;
401
402 /* Reserve uncached-buffered memory area for DMA */
403 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
404 &buf->addr, GFP_KERNEL);
405
406 pr_debug("%s: preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
407 __func__, (void *) buf->area, (void *) buf->addr, size);
408
409 if (!buf->area)
410 return -ENOMEM;
411
412 buf->bytes = size;
413 return 0;
414}
415
416static void mx1_mx2_pcm_free_dma_buffers(struct snd_pcm *pcm)
417{
418 struct snd_pcm_substream *substream;
419 struct snd_dma_buffer *buf;
420 int stream;
421
422 for (stream = 0; stream < 2; stream++) {
423 substream = pcm->streams[stream].substream;
424 if (!substream)
425 continue;
426
427 buf = &substream->dma_buffer;
428 if (!buf->area)
429 continue;
430
431 dma_free_writecombine(pcm->card->dev, buf->bytes,
432 buf->area, buf->addr);
433 buf->area = NULL;
434 }
435}
436
437static int mx1_mx2_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
438 struct snd_pcm *pcm)
439{
440 int ret = 0;
441
442 if (!card->dev->dma_mask)
443 card->dev->dma_mask = &mx1_mx2_pcm_dmamask;
444 if (!card->dev->coherent_dma_mask)
445 card->dev->coherent_dma_mask = 0xffffffff;
446
447 if (dai->playback.channels_min) {
448 ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm,
449 SNDRV_PCM_STREAM_PLAYBACK);
450 pr_debug("%s: preallocate playback buffer\n", __func__);
451 if (ret)
452 goto out;
453 }
454
455 if (dai->capture.channels_min) {
456 ret = mx1_mx2_pcm_preallocate_dma_buffer(pcm,
457 SNDRV_PCM_STREAM_CAPTURE);
458 pr_debug("%s: preallocate capture buffer\n", __func__);
459 if (ret)
460 goto out;
461 }
462 out:
463 return ret;
464}
465
466struct snd_soc_platform mx1_mx2_soc_platform = {
467 .name = "mx1_mx2-audio",
468 .pcm_ops = &mx1_mx2_pcm_ops,
469 .pcm_new = mx1_mx2_pcm_new,
470 .pcm_free = mx1_mx2_pcm_free_dma_buffers,
471};
472EXPORT_SYMBOL_GPL(mx1_mx2_soc_platform);
473
474static int __init mx1_mx2_soc_platform_init(void)
475{
476 return snd_soc_register_platform(&mx1_mx2_soc_platform);
477}
478module_init(mx1_mx2_soc_platform_init);
479
480static void __exit mx1_mx2_soc_platform_exit(void)
481{
482 snd_soc_unregister_platform(&mx1_mx2_soc_platform);
483}
484module_exit(mx1_mx2_soc_platform_exit);
485
486MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com");
487MODULE_DESCRIPTION("Freescale i.MX2x, i.MX1x PCM DMA module");
488MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/mx1_mx2-pcm.h b/sound/soc/imx/mx1_mx2-pcm.h
deleted file mode 100644
index 2e528106570..00000000000
--- a/sound/soc/imx/mx1_mx2-pcm.h
+++ /dev/null
@@ -1,26 +0,0 @@
1/*
2 * mx1_mx2-pcm.h :- ASoC platform header for Freescale i.MX1x, i.MX2x
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef _MX1_MX2_PCM_H
10#define _MX1_MX2_PCM_H
11
12/* DMA information for mx1_mx2 platforms */
13struct mx1_mx2_pcm_dma_params {
14 char *name; /* stream identifier */
15 unsigned int transfer_type; /* READ or WRITE DMA transfer */
16 dma_addr_t per_address; /* physical address of SSI fifo */
17 int event_id; /* fixed DMA number for SSI fifo */
18 int watermark_level; /* SSI fifo watermark level */
19 int per_config; /* DMA Config flags for peripheral */
20 int mem_config; /* DMA Config flags for RAM */
21 };
22
23/* platform data */
24extern struct snd_soc_platform mx1_mx2_soc_platform;
25
26#endif
diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c
deleted file mode 100644
index 07d2a248438..00000000000
--- a/sound/soc/imx/mx27vis_wm8974.c
+++ /dev/null
@@ -1,318 +0,0 @@
1/*
2 * mx27vis_wm8974.c -- SoC audio for mx27vis
3 *
4 * Copyright 2009 Vista Silicon S.L.
5 * Author: Javier Martin
6 * javier.martin@vista-silicon.com
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/device.h>
18#include <linux/i2c.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23
24
25#include "../codecs/wm8974.h"
26#include "mx1_mx2-pcm.h"
27#include "mxc-ssi.h"
28#include <mach/gpio.h>
29#include <mach/iomux.h>
30
31#define IGNORED_ARG 0
32
33
34static struct snd_soc_card mx27vis;
35
36/**
37 * This function connects SSI1 (HPCR1) as slave to
38 * SSI1 external signals (PPCR1)
39 * As slave, HPCR1 must set TFSDIR and TCLKDIR as inputs from
40 * port 4
41 */
42void audmux_connect_1_4(void)
43{
44 pr_debug("AUDMUX: normal operation mode\n");
45 /* Reset HPCR1 and PPCR1 */
46
47 DAM_HPCR1 = 0x00000000;
48 DAM_PPCR1 = 0x00000000;
49
50 /* set to synchronous */
51 DAM_HPCR1 |= AUDMUX_HPCR_SYN;
52 DAM_PPCR1 |= AUDMUX_PPCR_SYN;
53
54
55 /* set Rx sources 1 <--> 4 */
56 DAM_HPCR1 |= AUDMUX_HPCR_RXDSEL(3); /* port 4 */
57 DAM_PPCR1 |= AUDMUX_PPCR_RXDSEL(0); /* port 1 */
58
59 /* set Tx frame and Clock direction and source 4 --> 1 output */
60 DAM_HPCR1 |= AUDMUX_HPCR_TFSDIR | AUDMUX_HPCR_TCLKDIR;
61 DAM_HPCR1 |= AUDMUX_HPCR_TFCSEL(3); /* TxDS and TxCclk from port 4 */
62
63 return;
64}
65
66static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream,
67 struct snd_pcm_hw_params *params)
68{
69 struct snd_soc_pcm_runtime *rtd = substream->private_data;
70 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
71 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
72 unsigned int pll_out = 0, bclk = 0, fmt = 0, mclk = 0;
73 int ret = 0;
74
75 /*
76 * The WM8974 is better at generating accurate audio clocks than the
77 * MX27 SSI controller, so we will use it as master when we can.
78 */
79 switch (params_rate(params)) {
80 case 8000:
81 fmt = SND_SOC_DAIFMT_CBM_CFM;
82 mclk = WM8974_MCLKDIV_12;
83 pll_out = 24576000;
84 break;
85 case 16000:
86 fmt = SND_SOC_DAIFMT_CBM_CFM;
87 pll_out = 12288000;
88 break;
89 case 48000:
90 fmt = SND_SOC_DAIFMT_CBM_CFM;
91 bclk = WM8974_BCLKDIV_4;
92 pll_out = 12288000;
93 break;
94 case 96000:
95 fmt = SND_SOC_DAIFMT_CBM_CFM;
96 bclk = WM8974_BCLKDIV_2;
97 pll_out = 12288000;
98 break;
99 case 11025:
100 fmt = SND_SOC_DAIFMT_CBM_CFM;
101 bclk = WM8974_BCLKDIV_16;
102 pll_out = 11289600;
103 break;
104 case 22050:
105 fmt = SND_SOC_DAIFMT_CBM_CFM;
106 bclk = WM8974_BCLKDIV_8;
107 pll_out = 11289600;
108 break;
109 case 44100:
110 fmt = SND_SOC_DAIFMT_CBM_CFM;
111 bclk = WM8974_BCLKDIV_4;
112 mclk = WM8974_MCLKDIV_2;
113 pll_out = 11289600;
114 break;
115 case 88200:
116 fmt = SND_SOC_DAIFMT_CBM_CFM;
117 bclk = WM8974_BCLKDIV_2;
118 pll_out = 11289600;
119 break;
120 }
121
122 /* set codec DAI configuration */
123 ret = codec_dai->ops->set_fmt(codec_dai,
124 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
125 SND_SOC_DAIFMT_SYNC | fmt);
126 if (ret < 0) {
127 printk(KERN_ERR "Error from codec DAI configuration\n");
128 return ret;
129 }
130
131 /* set cpu DAI configuration */
132 ret = cpu_dai->ops->set_fmt(cpu_dai,
133 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
134 SND_SOC_DAIFMT_SYNC | fmt);
135 if (ret < 0) {
136 printk(KERN_ERR "Error from cpu DAI configuration\n");
137 return ret;
138 }
139
140 /* Put DC field of STCCR to 1 (not zero) */
141 ret = cpu_dai->ops->set_tdm_slot(cpu_dai, 0, 2);
142
143 /* set the SSI system clock as input */
144 ret = cpu_dai->ops->set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
145 SND_SOC_CLOCK_IN);
146 if (ret < 0) {
147 printk(KERN_ERR "Error when setting system SSI clk\n");
148 return ret;
149 }
150
151 /* set codec BCLK division for sample rate */
152 ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_BCLKDIV, bclk);
153 if (ret < 0) {
154 printk(KERN_ERR "Error when setting BCLK division\n");
155 return ret;
156 }
157
158
159 /* codec PLL input is 25 MHz */
160 ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG,
161 25000000, pll_out);
162 if (ret < 0) {
163 printk(KERN_ERR "Error when setting PLL input\n");
164 return ret;
165 }
166
167 /*set codec MCLK division for sample rate */
168 ret = codec_dai->ops->set_clkdiv(codec_dai, WM8974_MCLKDIV, mclk);
169 if (ret < 0) {
170 printk(KERN_ERR "Error when setting MCLK division\n");
171 return ret;
172 }
173
174 return 0;
175}
176
177static int mx27vis_hifi_hw_free(struct snd_pcm_substream *substream)
178{
179 struct snd_soc_pcm_runtime *rtd = substream->private_data;
180 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
181
182 /* disable the PLL */
183 return codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG,
184 0, 0);
185}
186
187/*
188 * mx27vis WM8974 HiFi DAI opserations.
189 */
190static struct snd_soc_ops mx27vis_hifi_ops = {
191 .hw_params = mx27vis_hifi_hw_params,
192 .hw_free = mx27vis_hifi_hw_free,
193};
194
195
196static int mx27vis_suspend(struct platform_device *pdev, pm_message_t state)
197{
198 return 0;
199}
200
201static int mx27vis_resume(struct platform_device *pdev)
202{
203 return 0;
204}
205
206static int mx27vis_probe(struct platform_device *pdev)
207{
208 int ret = 0;
209
210 ret = get_ssi_clk(0, &pdev->dev);
211
212 if (ret < 0) {
213 printk(KERN_ERR "%s: cant get ssi clock\n", __func__);
214 return ret;
215 }
216
217
218 return 0;
219}
220
221static int mx27vis_remove(struct platform_device *pdev)
222{
223 put_ssi_clk(0);
224 return 0;
225}
226
227static struct snd_soc_dai_link mx27vis_dai[] = {
228{ /* Hifi Playback*/
229 .name = "WM8974",
230 .stream_name = "WM8974 HiFi",
231 .cpu_dai = &imx_ssi_pcm_dai[0],
232 .codec_dai = &wm8974_dai,
233 .ops = &mx27vis_hifi_ops,
234},
235};
236
237static struct snd_soc_card mx27vis = {
238 .name = "mx27vis",
239 .platform = &mx1_mx2_soc_platform,
240 .probe = mx27vis_probe,
241 .remove = mx27vis_remove,
242 .suspend_pre = mx27vis_suspend,
243 .resume_post = mx27vis_resume,
244 .dai_link = mx27vis_dai,
245 .num_links = ARRAY_SIZE(mx27vis_dai),
246};
247
248static struct snd_soc_device mx27vis_snd_devdata = {
249 .card = &mx27vis,
250 .codec_dev = &soc_codec_dev_wm8974,
251};
252
253static struct platform_device *mx27vis_snd_device;
254
255/* Temporal definition of board specific behaviour */
256void gpio_ssi_active(int ssi_num)
257{
258 int ret = 0;
259
260 unsigned int ssi1_pins[] = {
261 PC20_PF_SSI1_FS,
262 PC21_PF_SSI1_RXD,
263 PC22_PF_SSI1_TXD,
264 PC23_PF_SSI1_CLK,
265 };
266 unsigned int ssi2_pins[] = {
267 PC24_PF_SSI2_FS,
268 PC25_PF_SSI2_RXD,
269 PC26_PF_SSI2_TXD,
270 PC27_PF_SSI2_CLK,
271 };
272 if (ssi_num == 0)
273 ret = mxc_gpio_setup_multiple_pins(ssi1_pins,
274 ARRAY_SIZE(ssi1_pins), "USB OTG");
275 else
276 ret = mxc_gpio_setup_multiple_pins(ssi2_pins,
277 ARRAY_SIZE(ssi2_pins), "USB OTG");
278 if (ret)
279 printk(KERN_ERR "Error requesting ssi %x pins\n", ssi_num);
280}
281
282
283static int __init mx27vis_init(void)
284{
285 int ret;
286
287 mx27vis_snd_device = platform_device_alloc("soc-audio", -1);
288 if (!mx27vis_snd_device)
289 return -ENOMEM;
290
291 platform_set_drvdata(mx27vis_snd_device, &mx27vis_snd_devdata);
292 mx27vis_snd_devdata.dev = &mx27vis_snd_device->dev;
293 ret = platform_device_add(mx27vis_snd_device);
294
295 if (ret) {
296 printk(KERN_ERR "ASoC: Platform device allocation failed\n");
297 platform_device_put(mx27vis_snd_device);
298 }
299
300 /* WM8974 uses SSI1 (HPCR1) via AUDMUX port 4 for audio (PPCR1) */
301 gpio_ssi_active(0);
302 audmux_connect_1_4();
303
304 return ret;
305}
306
307static void __exit mx27vis_exit(void)
308{
309 /* We should call some "ssi_gpio_inactive()" properly */
310}
311
312module_init(mx27vis_init);
313module_exit(mx27vis_exit);
314
315
316MODULE_AUTHOR("Javier Martin, javier.martin@vista-silicon.com");
317MODULE_DESCRIPTION("ALSA SoC WM8974 mx27vis");
318MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/mxc-ssi.c b/sound/soc/imx/mxc-ssi.c
deleted file mode 100644
index ccdefe60e75..00000000000
--- a/sound/soc/imx/mxc-ssi.c
+++ /dev/null
@@ -1,860 +0,0 @@
1/*
2 * mxc-ssi.c -- SSI driver for Freescale IMX
3 *
4 * Copyright 2006 Wolfson Microelectronics PLC.
5 * Author: Liam Girdwood
6 * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
7 *
8 * Based on mxc-alsa-mc13783 (C) 2006 Freescale.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 * TODO:
16 * Need to rework SSI register defs when new defs go into mainline.
17 * Add support for TDM and FIFO 1.
18 * Add support for i.mx3x DMA interface.
19 *
20 */
21
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/platform_device.h>
26#include <linux/slab.h>
27#include <linux/dma-mapping.h>
28#include <linux/clk.h>
29#include <sound/core.h>
30#include <sound/pcm.h>
31#include <sound/pcm_params.h>
32#include <sound/soc.h>
33#include <mach/dma-mx1-mx2.h>
34#include <asm/mach-types.h>
35
36#include "mxc-ssi.h"
37#include "mx1_mx2-pcm.h"
38
39#define SSI1_PORT 0
40#define SSI2_PORT 1
41
42static int ssi_active[2] = {0, 0};
43
44/* DMA information for mx1_mx2 platforms */
45static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out0 = {
46 .name = "SSI1 PCM Stereo out 0",
47 .transfer_type = DMA_MODE_WRITE,
48 .per_address = SSI1_BASE_ADDR + STX0,
49 .event_id = DMA_REQ_SSI1_TX0,
50 .watermark_level = TXFIFO_WATERMARK,
51 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
52 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
53};
54
55static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_out1 = {
56 .name = "SSI1 PCM Stereo out 1",
57 .transfer_type = DMA_MODE_WRITE,
58 .per_address = SSI1_BASE_ADDR + STX1,
59 .event_id = DMA_REQ_SSI1_TX1,
60 .watermark_level = TXFIFO_WATERMARK,
61 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
62 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
63};
64
65static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in0 = {
66 .name = "SSI1 PCM Stereo in 0",
67 .transfer_type = DMA_MODE_READ,
68 .per_address = SSI1_BASE_ADDR + SRX0,
69 .event_id = DMA_REQ_SSI1_RX0,
70 .watermark_level = RXFIFO_WATERMARK,
71 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
72 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
73};
74
75static struct mx1_mx2_pcm_dma_params imx_ssi1_pcm_stereo_in1 = {
76 .name = "SSI1 PCM Stereo in 1",
77 .transfer_type = DMA_MODE_READ,
78 .per_address = SSI1_BASE_ADDR + SRX1,
79 .event_id = DMA_REQ_SSI1_RX1,
80 .watermark_level = RXFIFO_WATERMARK,
81 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
82 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
83};
84
85static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out0 = {
86 .name = "SSI2 PCM Stereo out 0",
87 .transfer_type = DMA_MODE_WRITE,
88 .per_address = SSI2_BASE_ADDR + STX0,
89 .event_id = DMA_REQ_SSI2_TX0,
90 .watermark_level = TXFIFO_WATERMARK,
91 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
92 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
93};
94
95static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_out1 = {
96 .name = "SSI2 PCM Stereo out 1",
97 .transfer_type = DMA_MODE_WRITE,
98 .per_address = SSI2_BASE_ADDR + STX1,
99 .event_id = DMA_REQ_SSI2_TX1,
100 .watermark_level = TXFIFO_WATERMARK,
101 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
102 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
103};
104
105static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in0 = {
106 .name = "SSI2 PCM Stereo in 0",
107 .transfer_type = DMA_MODE_READ,
108 .per_address = SSI2_BASE_ADDR + SRX0,
109 .event_id = DMA_REQ_SSI2_RX0,
110 .watermark_level = RXFIFO_WATERMARK,
111 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
112 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
113};
114
115static struct mx1_mx2_pcm_dma_params imx_ssi2_pcm_stereo_in1 = {
116 .name = "SSI2 PCM Stereo in 1",
117 .transfer_type = DMA_MODE_READ,
118 .per_address = SSI2_BASE_ADDR + SRX1,
119 .event_id = DMA_REQ_SSI2_RX1,
120 .watermark_level = RXFIFO_WATERMARK,
121 .per_config = IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
122 .mem_config = IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
123};
124
125static struct clk *ssi_clk0, *ssi_clk1;
126
127int get_ssi_clk(int ssi, struct device *dev)
128{
129 switch (ssi) {
130 case 0:
131 ssi_clk0 = clk_get(dev, "ssi1");
132 if (IS_ERR(ssi_clk0))
133 return PTR_ERR(ssi_clk0);
134 return 0;
135 case 1:
136 ssi_clk1 = clk_get(dev, "ssi2");
137 if (IS_ERR(ssi_clk1))
138 return PTR_ERR(ssi_clk1);
139 return 0;
140 default:
141 return -EINVAL;
142 }
143}
144EXPORT_SYMBOL(get_ssi_clk);
145
146void put_ssi_clk(int ssi)
147{
148 switch (ssi) {
149 case 0:
150 clk_put(ssi_clk0);
151 ssi_clk0 = NULL;
152 break;
153 case 1:
154 clk_put(ssi_clk1);
155 ssi_clk1 = NULL;
156 break;
157 }
158}
159EXPORT_SYMBOL(put_ssi_clk);
160
161/*
162 * SSI system clock configuration.
163 * Should only be called when port is inactive (i.e. SSIEN = 0).
164 */
165static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
166 int clk_id, unsigned int freq, int dir)
167{
168 u32 scr;
169
170 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
171 scr = SSI1_SCR;
172 pr_debug("%s: SCR for SSI1 is %x\n", __func__, scr);
173 } else {
174 scr = SSI2_SCR;
175 pr_debug("%s: SCR for SSI2 is %x\n", __func__, scr);
176 }
177
178 if (scr & SSI_SCR_SSIEN) {
179 printk(KERN_WARNING "Warning ssi already enabled\n");
180 return 0;
181 }
182
183 switch (clk_id) {
184 case IMX_SSP_SYS_CLK:
185 if (dir == SND_SOC_CLOCK_OUT) {
186 scr |= SSI_SCR_SYS_CLK_EN;
187 pr_debug("%s: clk of is output\n", __func__);
188 } else {
189 scr &= ~SSI_SCR_SYS_CLK_EN;
190 pr_debug("%s: clk of is input\n", __func__);
191 }
192 break;
193 default:
194 return -EINVAL;
195 }
196
197 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
198 pr_debug("%s: writeback of SSI1_SCR\n", __func__);
199 SSI1_SCR = scr;
200 } else {
201 pr_debug("%s: writeback of SSI2_SCR\n", __func__);
202 SSI2_SCR = scr;
203 }
204
205 return 0;
206}
207
208/*
209 * SSI Clock dividers
210 * Should only be called when port is inactive (i.e. SSIEN = 0).
211 */
212static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
213 int div_id, int div)
214{
215 u32 stccr, srccr;
216
217 pr_debug("%s\n", __func__);
218 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
219 if (SSI1_SCR & SSI_SCR_SSIEN)
220 return 0;
221 srccr = SSI1_STCCR;
222 stccr = SSI1_STCCR;
223 } else {
224 if (SSI2_SCR & SSI_SCR_SSIEN)
225 return 0;
226 srccr = SSI2_STCCR;
227 stccr = SSI2_STCCR;
228 }
229
230 switch (div_id) {
231 case IMX_SSI_TX_DIV_2:
232 stccr &= ~SSI_STCCR_DIV2;
233 stccr |= div;
234 break;
235 case IMX_SSI_TX_DIV_PSR:
236 stccr &= ~SSI_STCCR_PSR;
237 stccr |= div;
238 break;
239 case IMX_SSI_TX_DIV_PM:
240 stccr &= ~0xff;
241 stccr |= SSI_STCCR_PM(div);
242 break;
243 case IMX_SSI_RX_DIV_2:
244 stccr &= ~SSI_STCCR_DIV2;
245 stccr |= div;
246 break;
247 case IMX_SSI_RX_DIV_PSR:
248 stccr &= ~SSI_STCCR_PSR;
249 stccr |= div;
250 break;
251 case IMX_SSI_RX_DIV_PM:
252 stccr &= ~0xff;
253 stccr |= SSI_STCCR_PM(div);
254 break;
255 default:
256 return -EINVAL;
257 }
258
259 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
260 SSI1_STCCR = stccr;
261 SSI1_SRCCR = srccr;
262 } else {
263 SSI2_STCCR = stccr;
264 SSI2_SRCCR = srccr;
265 }
266 return 0;
267}
268
269/*
270 * SSI Network Mode or TDM slots configuration.
271 * Should only be called when port is inactive (i.e. SSIEN = 0).
272 */
273static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
274 unsigned int mask, int slots)
275{
276 u32 stmsk, srmsk, stccr;
277
278 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
279 if (SSI1_SCR & SSI_SCR_SSIEN) {
280 printk(KERN_WARNING "Warning ssi already enabled\n");
281 return 0;
282 }
283 stccr = SSI1_STCCR;
284 } else {
285 if (SSI2_SCR & SSI_SCR_SSIEN) {
286 printk(KERN_WARNING "Warning ssi already enabled\n");
287 return 0;
288 }
289 stccr = SSI2_STCCR;
290 }
291
292 stmsk = srmsk = mask;
293 stccr &= ~SSI_STCCR_DC_MASK;
294 stccr |= SSI_STCCR_DC(slots - 1);
295
296 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
297 SSI1_STMSK = stmsk;
298 SSI1_SRMSK = srmsk;
299 SSI1_SRCCR = SSI1_STCCR = stccr;
300 } else {
301 SSI2_STMSK = stmsk;
302 SSI2_SRMSK = srmsk;
303 SSI2_SRCCR = SSI2_STCCR = stccr;
304 }
305
306 return 0;
307}
308
309/*
310 * SSI DAI format configuration.
311 * Should only be called when port is inactive (i.e. SSIEN = 0).
312 * Note: We don't use the I2S modes but instead manually configure the
313 * SSI for I2S.
314 */
315static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai,
316 unsigned int fmt)
317{
318 u32 stcr = 0, srcr = 0, scr;
319
320 /*
321 * This is done to avoid this function to modify
322 * previous set values in stcr
323 */
324 stcr = SSI1_STCR;
325
326 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
327 scr = SSI1_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
328 else
329 scr = SSI2_SCR & ~(SSI_SCR_SYN | SSI_SCR_NET);
330
331 if (scr & SSI_SCR_SSIEN) {
332 printk(KERN_WARNING "Warning ssi already enabled\n");
333 return 0;
334 }
335
336 /* DAI mode */
337 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
338 case SND_SOC_DAIFMT_I2S:
339 /* data on rising edge of bclk, frame low 1clk before data */
340 stcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
341 srcr |= SSI_SRCR_RFSI | SSI_SRCR_REFS | SSI_SRCR_RXBIT0;
342 break;
343 case SND_SOC_DAIFMT_LEFT_J:
344 /* data on rising edge of bclk, frame high with data */
345 stcr |= SSI_STCR_TXBIT0;
346 srcr |= SSI_SRCR_RXBIT0;
347 break;
348 case SND_SOC_DAIFMT_DSP_B:
349 /* data on rising edge of bclk, frame high with data */
350 stcr |= SSI_STCR_TFSL;
351 srcr |= SSI_SRCR_RFSL;
352 break;
353 case SND_SOC_DAIFMT_DSP_A:
354 /* data on rising edge of bclk, frame high 1clk before data */
355 stcr |= SSI_STCR_TFSL | SSI_STCR_TEFS;
356 srcr |= SSI_SRCR_RFSL | SSI_SRCR_REFS;
357 break;
358 }
359
360 /* DAI clock inversion */
361 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
362 case SND_SOC_DAIFMT_IB_IF:
363 stcr |= SSI_STCR_TFSI;
364 stcr &= ~SSI_STCR_TSCKP;
365 srcr |= SSI_SRCR_RFSI;
366 srcr &= ~SSI_SRCR_RSCKP;
367 break;
368 case SND_SOC_DAIFMT_IB_NF:
369 stcr &= ~(SSI_STCR_TSCKP | SSI_STCR_TFSI);
370 srcr &= ~(SSI_SRCR_RSCKP | SSI_SRCR_RFSI);
371 break;
372 case SND_SOC_DAIFMT_NB_IF:
373 stcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP;
374 srcr |= SSI_SRCR_RFSI | SSI_SRCR_RSCKP;
375 break;
376 case SND_SOC_DAIFMT_NB_NF:
377 stcr &= ~SSI_STCR_TFSI;
378 stcr |= SSI_STCR_TSCKP;
379 srcr &= ~SSI_SRCR_RFSI;
380 srcr |= SSI_SRCR_RSCKP;
381 break;
382 }
383
384 /* DAI clock master masks */
385 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
386 case SND_SOC_DAIFMT_CBS_CFS:
387 stcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR;
388 srcr |= SSI_SRCR_RFDIR | SSI_SRCR_RXDIR;
389 break;
390 case SND_SOC_DAIFMT_CBM_CFS:
391 stcr |= SSI_STCR_TFDIR;
392 srcr |= SSI_SRCR_RFDIR;
393 break;
394 case SND_SOC_DAIFMT_CBS_CFM:
395 stcr |= SSI_STCR_TXDIR;
396 srcr |= SSI_SRCR_RXDIR;
397 break;
398 }
399
400 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
401 SSI1_STCR = stcr;
402 SSI1_SRCR = srcr;
403 SSI1_SCR = scr;
404 } else {
405 SSI2_STCR = stcr;
406 SSI2_SRCR = srcr;
407 SSI2_SCR = scr;
408 }
409
410 return 0;
411}
412
413static int imx_ssi_startup(struct snd_pcm_substream *substream,
414 struct snd_soc_dai *dai)
415{
416 struct snd_soc_pcm_runtime *rtd = substream->private_data;
417 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
418
419 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
420 /* set up TX DMA params */
421 switch (cpu_dai->id) {
422 case IMX_DAI_SSI0:
423 cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out0;
424 break;
425 case IMX_DAI_SSI1:
426 cpu_dai->dma_data = &imx_ssi1_pcm_stereo_out1;
427 break;
428 case IMX_DAI_SSI2:
429 cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out0;
430 break;
431 case IMX_DAI_SSI3:
432 cpu_dai->dma_data = &imx_ssi2_pcm_stereo_out1;
433 }
434 pr_debug("%s: (playback)\n", __func__);
435 } else {
436 /* set up RX DMA params */
437 switch (cpu_dai->id) {
438 case IMX_DAI_SSI0:
439 cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in0;
440 break;
441 case IMX_DAI_SSI1:
442 cpu_dai->dma_data = &imx_ssi1_pcm_stereo_in1;
443 break;
444 case IMX_DAI_SSI2:
445 cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in0;
446 break;
447 case IMX_DAI_SSI3:
448 cpu_dai->dma_data = &imx_ssi2_pcm_stereo_in1;
449 }
450 pr_debug("%s: (capture)\n", __func__);
451 }
452
453 /*
454 * we cant really change any SSI values after SSI is enabled
455 * need to fix in software for max flexibility - lrg
456 */
457 if (cpu_dai->active) {
458 printk(KERN_WARNING "Warning ssi already enabled\n");
459 return 0;
460 }
461
462 /* reset the SSI port - Sect 45.4.4 */
463 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
464
465 if (!ssi_clk0)
466 return -EINVAL;
467
468 if (ssi_active[SSI1_PORT]++) {
469 pr_debug("%s: exit before reset\n", __func__);
470 return 0;
471 }
472
473 /* SSI1 Reset */
474 SSI1_SCR = 0;
475
476 SSI1_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
477 SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
478 SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
479 SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
480 } else {
481
482 if (!ssi_clk1)
483 return -EINVAL;
484
485 if (ssi_active[SSI2_PORT]++) {
486 pr_debug("%s: exit before reset\n", __func__);
487 return 0;
488 }
489
490 /* SSI2 Reset */
491 SSI2_SCR = 0;
492
493 SSI2_SFCSR = SSI_SFCSR_RFWM1(RXFIFO_WATERMARK) |
494 SSI_SFCSR_RFWM0(RXFIFO_WATERMARK) |
495 SSI_SFCSR_TFWM1(TXFIFO_WATERMARK) |
496 SSI_SFCSR_TFWM0(TXFIFO_WATERMARK);
497 }
498
499 return 0;
500}
501
502int imx_ssi_hw_tx_params(struct snd_pcm_substream *substream,
503 struct snd_pcm_hw_params *params)
504{
505 struct snd_soc_pcm_runtime *rtd = substream->private_data;
506 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
507 u32 stccr, stcr, sier;
508
509 pr_debug("%s\n", __func__);
510
511 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
512 stccr = SSI1_STCCR & ~SSI_STCCR_WL_MASK;
513 stcr = SSI1_STCR;
514 sier = SSI1_SIER;
515 } else {
516 stccr = SSI2_STCCR & ~SSI_STCCR_WL_MASK;
517 stcr = SSI2_STCR;
518 sier = SSI2_SIER;
519 }
520
521 /* DAI data (word) size */
522 switch (params_format(params)) {
523 case SNDRV_PCM_FORMAT_S16_LE:
524 stccr |= SSI_STCCR_WL(16);
525 break;
526 case SNDRV_PCM_FORMAT_S20_3LE:
527 stccr |= SSI_STCCR_WL(20);
528 break;
529 case SNDRV_PCM_FORMAT_S24_LE:
530 stccr |= SSI_STCCR_WL(24);
531 break;
532 }
533
534 /* enable interrupts */
535 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
536 stcr |= SSI_STCR_TFEN0;
537 else
538 stcr |= SSI_STCR_TFEN1;
539 sier |= SSI_SIER_TDMAE;
540
541 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
542 SSI1_STCR = stcr;
543 SSI1_STCCR = stccr;
544 SSI1_SIER = sier;
545 } else {
546 SSI2_STCR = stcr;
547 SSI2_STCCR = stccr;
548 SSI2_SIER = sier;
549 }
550
551 return 0;
552}
553
554int imx_ssi_hw_rx_params(struct snd_pcm_substream *substream,
555 struct snd_pcm_hw_params *params)
556{
557 struct snd_soc_pcm_runtime *rtd = substream->private_data;
558 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
559 u32 srccr, srcr, sier;
560
561 pr_debug("%s\n", __func__);
562
563 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
564 srccr = SSI1_SRCCR & ~SSI_SRCCR_WL_MASK;
565 srcr = SSI1_SRCR;
566 sier = SSI1_SIER;
567 } else {
568 srccr = SSI2_SRCCR & ~SSI_SRCCR_WL_MASK;
569 srcr = SSI2_SRCR;
570 sier = SSI2_SIER;
571 }
572
573 /* DAI data (word) size */
574 switch (params_format(params)) {
575 case SNDRV_PCM_FORMAT_S16_LE:
576 srccr |= SSI_SRCCR_WL(16);
577 break;
578 case SNDRV_PCM_FORMAT_S20_3LE:
579 srccr |= SSI_SRCCR_WL(20);
580 break;
581 case SNDRV_PCM_FORMAT_S24_LE:
582 srccr |= SSI_SRCCR_WL(24);
583 break;
584 }
585
586 /* enable interrupts */
587 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
588 srcr |= SSI_SRCR_RFEN0;
589 else
590 srcr |= SSI_SRCR_RFEN1;
591 sier |= SSI_SIER_RDMAE;
592
593 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
594 SSI1_SRCR = srcr;
595 SSI1_SRCCR = srccr;
596 SSI1_SIER = sier;
597 } else {
598 SSI2_SRCR = srcr;
599 SSI2_SRCCR = srccr;
600 SSI2_SIER = sier;
601 }
602
603 return 0;
604}
605
606/*
607 * Should only be called when port is inactive (i.e. SSIEN = 0),
608 * although can be called multiple times by upper layers.
609 */
610int imx_ssi_hw_params(struct snd_pcm_substream *substream,
611 struct snd_pcm_hw_params *params,
612 struct snd_soc_dai *dai)
613{
614 struct snd_soc_pcm_runtime *rtd = substream->private_data;
615 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
616
617 int ret;
618
619 /* cant change any parameters when SSI is running */
620 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
621 if (SSI1_SCR & SSI_SCR_SSIEN) {
622 printk(KERN_WARNING "Warning ssi already enabled\n");
623 return 0;
624 }
625 } else {
626 if (SSI2_SCR & SSI_SCR_SSIEN) {
627 printk(KERN_WARNING "Warning ssi already enabled\n");
628 return 0;
629 }
630 }
631
632 /*
633 * Configure both tx and rx params with the same settings. This is
634 * really a harware restriction because SSI must be disabled until
635 * we can change those values. If there is an active audio stream in
636 * one direction, enabling the other direction with different
637 * settings would mean disturbing the running one.
638 */
639 ret = imx_ssi_hw_tx_params(substream, params);
640 if (ret < 0)
641 return ret;
642 return imx_ssi_hw_rx_params(substream, params);
643}
644
645int imx_ssi_prepare(struct snd_pcm_substream *substream,
646 struct snd_soc_dai *dai)
647{
648 struct snd_soc_pcm_runtime *rtd = substream->private_data;
649 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
650 int ret;
651
652 pr_debug("%s\n", __func__);
653
654 /* Enable clks here to follow SSI recommended init sequence */
655 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
656 ret = clk_enable(ssi_clk0);
657 if (ret < 0)
658 printk(KERN_ERR "Unable to enable ssi_clk0\n");
659 } else {
660 ret = clk_enable(ssi_clk1);
661 if (ret < 0)
662 printk(KERN_ERR "Unable to enable ssi_clk1\n");
663 }
664
665 return 0;
666}
667
668static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
669 struct snd_soc_dai *dai)
670{
671 struct snd_soc_pcm_runtime *rtd = substream->private_data;
672 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
673 u32 scr;
674
675 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
676 scr = SSI1_SCR;
677 else
678 scr = SSI2_SCR;
679
680 switch (cmd) {
681 case SNDRV_PCM_TRIGGER_START:
682 case SNDRV_PCM_TRIGGER_RESUME:
683 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
684 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
685 scr |= SSI_SCR_TE | SSI_SCR_SSIEN;
686 else
687 scr |= SSI_SCR_RE | SSI_SCR_SSIEN;
688 break;
689 case SNDRV_PCM_TRIGGER_SUSPEND:
690 case SNDRV_PCM_TRIGGER_STOP:
691 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
692 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
693 scr &= ~SSI_SCR_TE;
694 else
695 scr &= ~SSI_SCR_RE;
696 break;
697 default:
698 return -EINVAL;
699 }
700
701 if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2)
702 SSI1_SCR = scr;
703 else
704 SSI2_SCR = scr;
705
706 return 0;
707}
708
709static void imx_ssi_shutdown(struct snd_pcm_substream *substream,
710 struct snd_soc_dai *dai)
711{
712 struct snd_soc_pcm_runtime *rtd = substream->private_data;
713 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
714
715 /* shutdown SSI if neither Tx or Rx is active */
716 if (!cpu_dai->active) {
717
718 if (cpu_dai->id == IMX_DAI_SSI0 ||
719 cpu_dai->id == IMX_DAI_SSI2) {
720
721 if (--ssi_active[SSI1_PORT] > 1)
722 return;
723
724 SSI1_SCR = 0;
725 clk_disable(ssi_clk0);
726 } else {
727 if (--ssi_active[SSI2_PORT])
728 return;
729 SSI2_SCR = 0;
730 clk_disable(ssi_clk1);
731 }
732 }
733}
734
735#ifdef CONFIG_PM
736static int imx_ssi_suspend(struct platform_device *dev,
737 struct snd_soc_dai *dai)
738{
739 return 0;
740}
741
742static int imx_ssi_resume(struct platform_device *pdev,
743 struct snd_soc_dai *dai)
744{
745 return 0;
746}
747
748#else
749#define imx_ssi_suspend NULL
750#define imx_ssi_resume NULL
751#endif
752
753#define IMX_SSI_RATES \
754 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
755 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
756 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
757 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
758 SNDRV_PCM_RATE_96000)
759
760#define IMX_SSI_BITS \
761 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
762 SNDRV_PCM_FMTBIT_S24_LE)
763
764static struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
765 .startup = imx_ssi_startup,
766 .shutdown = imx_ssi_shutdown,
767 .trigger = imx_ssi_trigger,
768 .prepare = imx_ssi_prepare,
769 .hw_params = imx_ssi_hw_params,
770 .set_sysclk = imx_ssi_set_dai_sysclk,
771 .set_clkdiv = imx_ssi_set_dai_clkdiv,
772 .set_fmt = imx_ssi_set_dai_fmt,
773 .set_tdm_slot = imx_ssi_set_dai_tdm_slot,
774};
775
776struct snd_soc_dai imx_ssi_pcm_dai[] = {
777{
778 .name = "imx-i2s-1-0",
779 .id = IMX_DAI_SSI0,
780 .suspend = imx_ssi_suspend,
781 .resume = imx_ssi_resume,
782 .playback = {
783 .channels_min = 1,
784 .channels_max = 2,
785 .formats = IMX_SSI_BITS,
786 .rates = IMX_SSI_RATES,},
787 .capture = {
788 .channels_min = 1,
789 .channels_max = 2,
790 .formats = IMX_SSI_BITS,
791 .rates = IMX_SSI_RATES,},
792 .ops = &imx_ssi_pcm_dai_ops,
793},
794{
795 .name = "imx-i2s-2-0",
796 .id = IMX_DAI_SSI1,
797 .playback = {
798 .channels_min = 1,
799 .channels_max = 2,
800 .formats = IMX_SSI_BITS,
801 .rates = IMX_SSI_RATES,},
802 .capture = {
803 .channels_min = 1,
804 .channels_max = 2,
805 .formats = IMX_SSI_BITS,
806 .rates = IMX_SSI_RATES,},
807 .ops = &imx_ssi_pcm_dai_ops,
808},
809{
810 .name = "imx-i2s-1-1",
811 .id = IMX_DAI_SSI2,
812 .suspend = imx_ssi_suspend,
813 .resume = imx_ssi_resume,
814 .playback = {
815 .channels_min = 1,
816 .channels_max = 2,
817 .formats = IMX_SSI_BITS,
818 .rates = IMX_SSI_RATES,},
819 .capture = {
820 .channels_min = 1,
821 .channels_max = 2,
822 .formats = IMX_SSI_BITS,
823 .rates = IMX_SSI_RATES,},
824 .ops = &imx_ssi_pcm_dai_ops,
825},
826{
827 .name = "imx-i2s-2-1",
828 .id = IMX_DAI_SSI3,
829 .playback = {
830 .channels_min = 1,
831 .channels_max = 2,
832 .formats = IMX_SSI_BITS,
833 .rates = IMX_SSI_RATES,},
834 .capture = {
835 .channels_min = 1,
836 .channels_max = 2,
837 .formats = IMX_SSI_BITS,
838 .rates = IMX_SSI_RATES,},
839 .ops = &imx_ssi_pcm_dai_ops,
840},
841};
842EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
843
844static int __init imx_ssi_init(void)
845{
846 return snd_soc_register_dais(imx_ssi_pcm_dai,
847 ARRAY_SIZE(imx_ssi_pcm_dai));
848}
849
850static void __exit imx_ssi_exit(void)
851{
852 snd_soc_unregister_dais(imx_ssi_pcm_dai,
853 ARRAY_SIZE(imx_ssi_pcm_dai));
854}
855
856module_init(imx_ssi_init);
857module_exit(imx_ssi_exit);
858MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com");
859MODULE_DESCRIPTION("i.MX ASoC I2S driver");
860MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/mxc-ssi.h b/sound/soc/imx/mxc-ssi.h
deleted file mode 100644
index 12bbdc9c7ec..00000000000
--- a/sound/soc/imx/mxc-ssi.h
+++ /dev/null
@@ -1,238 +0,0 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 */
6
7#ifndef _IMX_SSI_H
8#define _IMX_SSI_H
9
10#include <mach/hardware.h>
11
12/* SSI regs definition - MOVE to /arch/arm/plat-mxc/include/mach/ when stable */
13#define SSI1_IO_BASE_ADDR IO_ADDRESS(SSI1_BASE_ADDR)
14#define SSI2_IO_BASE_ADDR IO_ADDRESS(SSI2_BASE_ADDR)
15
16#define STX0 0x00
17#define STX1 0x04
18#define SRX0 0x08
19#define SRX1 0x0c
20#define SCR 0x10
21#define SISR 0x14
22#define SIER 0x18
23#define STCR 0x1c
24#define SRCR 0x20
25#define STCCR 0x24
26#define SRCCR 0x28
27#define SFCSR 0x2c
28#define STR 0x30
29#define SOR 0x34
30#define SACNT 0x38
31#define SACADD 0x3c
32#define SACDAT 0x40
33#define SATAG 0x44
34#define STMSK 0x48
35#define SRMSK 0x4c
36
37#define SSI1_STX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX0)))
38#define SSI1_STX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STX1)))
39#define SSI1_SRX0 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX0)))
40#define SSI1_SRX1 (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRX1)))
41#define SSI1_SCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SCR)))
42#define SSI1_SISR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SISR)))
43#define SSI1_SIER (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SIER)))
44#define SSI1_STCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCR)))
45#define SSI1_SRCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCR)))
46#define SSI1_STCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STCCR)))
47#define SSI1_SRCCR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRCCR)))
48#define SSI1_SFCSR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SFCSR)))
49#define SSI1_STR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STR)))
50#define SSI1_SOR (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SOR)))
51#define SSI1_SACNT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACNT)))
52#define SSI1_SACADD (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACADD)))
53#define SSI1_SACDAT (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SACDAT)))
54#define SSI1_SATAG (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SATAG)))
55#define SSI1_STMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + STMSK)))
56#define SSI1_SRMSK (*((volatile u32 *)(SSI1_IO_BASE_ADDR + SRMSK)))
57
58
59#define SSI2_STX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX0)))
60#define SSI2_STX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STX1)))
61#define SSI2_SRX0 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX0)))
62#define SSI2_SRX1 (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRX1)))
63#define SSI2_SCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SCR)))
64#define SSI2_SISR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SISR)))
65#define SSI2_SIER (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SIER)))
66#define SSI2_STCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCR)))
67#define SSI2_SRCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCR)))
68#define SSI2_STCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STCCR)))
69#define SSI2_SRCCR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRCCR)))
70#define SSI2_SFCSR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SFCSR)))
71#define SSI2_STR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STR)))
72#define SSI2_SOR (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SOR)))
73#define SSI2_SACNT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACNT)))
74#define SSI2_SACADD (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACADD)))
75#define SSI2_SACDAT (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SACDAT)))
76#define SSI2_SATAG (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SATAG)))
77#define SSI2_STMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + STMSK)))
78#define SSI2_SRMSK (*((volatile u32 *)(SSI2_IO_BASE_ADDR + SRMSK)))
79
80#define SSI_SCR_CLK_IST (1 << 9)
81#define SSI_SCR_TCH_EN (1 << 8)
82#define SSI_SCR_SYS_CLK_EN (1 << 7)
83#define SSI_SCR_I2S_MODE_NORM (0 << 5)
84#define SSI_SCR_I2S_MODE_MSTR (1 << 5)
85#define SSI_SCR_I2S_MODE_SLAVE (2 << 5)
86#define SSI_SCR_SYN (1 << 4)
87#define SSI_SCR_NET (1 << 3)
88#define SSI_SCR_RE (1 << 2)
89#define SSI_SCR_TE (1 << 1)
90#define SSI_SCR_SSIEN (1 << 0)
91
92#define SSI_SISR_CMDAU (1 << 18)
93#define SSI_SISR_CMDDU (1 << 17)
94#define SSI_SISR_RXT (1 << 16)
95#define SSI_SISR_RDR1 (1 << 15)
96#define SSI_SISR_RDR0 (1 << 14)
97#define SSI_SISR_TDE1 (1 << 13)
98#define SSI_SISR_TDE0 (1 << 12)
99#define SSI_SISR_ROE1 (1 << 11)
100#define SSI_SISR_ROE0 (1 << 10)
101#define SSI_SISR_TUE1 (1 << 9)
102#define SSI_SISR_TUE0 (1 << 8)
103#define SSI_SISR_TFS (1 << 7)
104#define SSI_SISR_RFS (1 << 6)
105#define SSI_SISR_TLS (1 << 5)
106#define SSI_SISR_RLS (1 << 4)
107#define SSI_SISR_RFF1 (1 << 3)
108#define SSI_SISR_RFF0 (1 << 2)
109#define SSI_SISR_TFE1 (1 << 1)
110#define SSI_SISR_TFE0 (1 << 0)
111
112#define SSI_SIER_RDMAE (1 << 22)
113#define SSI_SIER_RIE (1 << 21)
114#define SSI_SIER_TDMAE (1 << 20)
115#define SSI_SIER_TIE (1 << 19)
116#define SSI_SIER_CMDAU_EN (1 << 18)
117#define SSI_SIER_CMDDU_EN (1 << 17)
118#define SSI_SIER_RXT_EN (1 << 16)
119#define SSI_SIER_RDR1_EN (1 << 15)
120#define SSI_SIER_RDR0_EN (1 << 14)
121#define SSI_SIER_TDE1_EN (1 << 13)
122#define SSI_SIER_TDE0_EN (1 << 12)
123#define SSI_SIER_ROE1_EN (1 << 11)
124#define SSI_SIER_ROE0_EN (1 << 10)
125#define SSI_SIER_TUE1_EN (1 << 9)
126#define SSI_SIER_TUE0_EN (1 << 8)
127#define SSI_SIER_TFS_EN (1 << 7)
128#define SSI_SIER_RFS_EN (1 << 6)
129#define SSI_SIER_TLS_EN (1 << 5)
130#define SSI_SIER_RLS_EN (1 << 4)
131#define SSI_SIER_RFF1_EN (1 << 3)
132#define SSI_SIER_RFF0_EN (1 << 2)
133#define SSI_SIER_TFE1_EN (1 << 1)
134#define SSI_SIER_TFE0_EN (1 << 0)
135
136#define SSI_STCR_TXBIT0 (1 << 9)
137#define SSI_STCR_TFEN1 (1 << 8)
138#define SSI_STCR_TFEN0 (1 << 7)
139#define SSI_STCR_TFDIR (1 << 6)
140#define SSI_STCR_TXDIR (1 << 5)
141#define SSI_STCR_TSHFD (1 << 4)
142#define SSI_STCR_TSCKP (1 << 3)
143#define SSI_STCR_TFSI (1 << 2)
144#define SSI_STCR_TFSL (1 << 1)
145#define SSI_STCR_TEFS (1 << 0)
146
147#define SSI_SRCR_RXBIT0 (1 << 9)
148#define SSI_SRCR_RFEN1 (1 << 8)
149#define SSI_SRCR_RFEN0 (1 << 7)
150#define SSI_SRCR_RFDIR (1 << 6)
151#define SSI_SRCR_RXDIR (1 << 5)
152#define SSI_SRCR_RSHFD (1 << 4)
153#define SSI_SRCR_RSCKP (1 << 3)
154#define SSI_SRCR_RFSI (1 << 2)
155#define SSI_SRCR_RFSL (1 << 1)
156#define SSI_SRCR_REFS (1 << 0)
157
158#define SSI_STCCR_DIV2 (1 << 18)
159#define SSI_STCCR_PSR (1 << 15)
160#define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13)
161#define SSI_STCCR_DC(x) (((x) & 0x1f) << 8)
162#define SSI_STCCR_PM(x) (((x) & 0xff) << 0)
163#define SSI_STCCR_WL_MASK (0xf << 13)
164#define SSI_STCCR_DC_MASK (0x1f << 8)
165#define SSI_STCCR_PM_MASK (0xff << 0)
166
167#define SSI_SRCCR_DIV2 (1 << 18)
168#define SSI_SRCCR_PSR (1 << 15)
169#define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13)
170#define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8)
171#define SSI_SRCCR_PM(x) (((x) & 0xff) << 0)
172#define SSI_SRCCR_WL_MASK (0xf << 13)
173#define SSI_SRCCR_DC_MASK (0x1f << 8)
174#define SSI_SRCCR_PM_MASK (0xff << 0)
175
176
177#define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28)
178#define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24)
179#define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20)
180#define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16)
181#define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12)
182#define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) << 8)
183#define SSI_SFCSR_RFWM0(x) (((x) & 0xf) << 4)
184#define SSI_SFCSR_TFWM0(x) (((x) & 0xf) << 0)
185
186#define SSI_STR_TEST (1 << 15)
187#define SSI_STR_RCK2TCK (1 << 14)
188#define SSI_STR_RFS2TFS (1 << 13)
189#define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8)
190#define SSI_STR_TXD2RXD (1 << 7)
191#define SSI_STR_TCK2RCK (1 << 6)
192#define SSI_STR_TFS2RFS (1 << 5)
193#define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0)
194
195#define SSI_SOR_CLKOFF (1 << 6)
196#define SSI_SOR_RX_CLR (1 << 5)
197#define SSI_SOR_TX_CLR (1 << 4)
198#define SSI_SOR_INIT (1 << 3)
199#define SSI_SOR_WAIT(x) (((x) & 0x3) << 1)
200#define SSI_SOR_SYNRST (1 << 0)
201
202#define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5)
203#define SSI_SACNT_WR (x << 4)
204#define SSI_SACNT_RD (x << 3)
205#define SSI_SACNT_TIF (x << 2)
206#define SSI_SACNT_FV (x << 1)
207#define SSI_SACNT_AC97EN (x << 0)
208
209/* Watermarks for FIFO's */
210#define TXFIFO_WATERMARK 0x4
211#define RXFIFO_WATERMARK 0x4
212
213/* i.MX DAI SSP ID's */
214#define IMX_DAI_SSI0 0 /* SSI1 FIFO 0 */
215#define IMX_DAI_SSI1 1 /* SSI1 FIFO 1 */
216#define IMX_DAI_SSI2 2 /* SSI2 FIFO 0 */
217#define IMX_DAI_SSI3 3 /* SSI2 FIFO 1 */
218
219/* SSI clock sources */
220#define IMX_SSP_SYS_CLK 0
221
222/* SSI audio dividers */
223#define IMX_SSI_TX_DIV_2 0
224#define IMX_SSI_TX_DIV_PSR 1
225#define IMX_SSI_TX_DIV_PM 2
226#define IMX_SSI_RX_DIV_2 3
227#define IMX_SSI_RX_DIV_PSR 4
228#define IMX_SSI_RX_DIV_PM 5
229
230
231/* SSI Div 2 */
232#define IMX_SSI_DIV_2_OFF (~SSI_STCCR_DIV2)
233#define IMX_SSI_DIV_2_ON SSI_STCCR_DIV2
234
235extern struct snd_soc_dai imx_ssi_pcm_dai[4];
236extern int get_ssi_clk(int ssi, struct device *dev);
237extern void put_ssi_clk(int ssi);
238#endif
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c
index acfce1c0f1c..7e3f41696c4 100644
--- a/sound/soc/pxa/raumfeld.c
+++ b/sound/soc/pxa/raumfeld.c
@@ -41,7 +41,9 @@ static struct i2c_board_info max9486_hwmon_info = {
41}; 41};
42 42
43#define MAX9485_MCLK_FREQ_112896 0x22 43#define MAX9485_MCLK_FREQ_112896 0x22
44#define MAX9485_MCLK_FREQ_122880 0x23 44#define MAX9485_MCLK_FREQ_122880 0x23
45#define MAX9485_MCLK_FREQ_225792 0x32
46#define MAX9485_MCLK_FREQ_245760 0x33
45 47
46static void set_max9485_clk(char clk) 48static void set_max9485_clk(char clk)
47{ 49{
@@ -71,9 +73,17 @@ static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
71 struct snd_soc_pcm_runtime *rtd = substream->private_data; 73 struct snd_soc_pcm_runtime *rtd = substream->private_data;
72 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 74 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
73 75
74 set_max9485_clk(MAX9485_MCLK_FREQ_112896); 76 /* set freq to 0 to enable all possible codec sample rates */
77 return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
78}
75 79
76 return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0); 80static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
81{
82 struct snd_soc_pcm_runtime *rtd = substream->private_data;
83 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
84
85 /* set freq to 0 to enable all possible codec sample rates */
86 snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
77} 87}
78 88
79static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream, 89static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
@@ -86,20 +96,24 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
86 int ret = 0; 96 int ret = 0;
87 97
88 switch (params_rate(params)) { 98 switch (params_rate(params)) {
89 case 8000: 99 case 44100:
90 case 16000: 100 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
101 clk = 11289600;
102 break;
91 case 48000: 103 case 48000:
92 case 96000:
93 set_max9485_clk(MAX9485_MCLK_FREQ_122880); 104 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
94 clk = 12288000; 105 clk = 12288000;
95 break; 106 break;
96 case 11025:
97 case 22050:
98 case 44100:
99 case 88200: 107 case 88200:
100 set_max9485_clk(MAX9485_MCLK_FREQ_112896); 108 set_max9485_clk(MAX9485_MCLK_FREQ_225792);
101 clk = 11289600; 109 clk = 22579200;
102 break; 110 break;
111 case 96000:
112 set_max9485_clk(MAX9485_MCLK_FREQ_245760);
113 clk = 24576000;
114 break;
115 default:
116 return -EINVAL;
103 } 117 }
104 118
105 fmt = SND_SOC_DAIFMT_I2S | 119 fmt = SND_SOC_DAIFMT_I2S |
@@ -128,7 +142,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
128 if (ret < 0) 142 if (ret < 0)
129 return ret; 143 return ret;
130 144
131 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); 145 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
132 if (ret < 0) 146 if (ret < 0)
133 return ret; 147 return ret;
134 148
@@ -137,6 +151,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
137 151
138static struct snd_soc_ops raumfeld_cs4270_ops = { 152static struct snd_soc_ops raumfeld_cs4270_ops = {
139 .startup = raumfeld_cs4270_startup, 153 .startup = raumfeld_cs4270_startup,
154 .shutdown = raumfeld_cs4270_shutdown,
140 .hw_params = raumfeld_cs4270_hw_params, 155 .hw_params = raumfeld_cs4270_hw_params,
141}; 156};
142 157
@@ -181,20 +196,24 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
181 int fmt, ret = 0, clk = 0; 196 int fmt, ret = 0, clk = 0;
182 197
183 switch (params_rate(params)) { 198 switch (params_rate(params)) {
184 case 8000: 199 case 44100:
185 case 16000: 200 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
201 clk = 11289600;
202 break;
186 case 48000: 203 case 48000:
187 case 96000:
188 set_max9485_clk(MAX9485_MCLK_FREQ_122880); 204 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
189 clk = 12288000; 205 clk = 12288000;
190 break; 206 break;
191 case 11025:
192 case 22050:
193 case 44100:
194 case 88200: 207 case 88200:
195 set_max9485_clk(MAX9485_MCLK_FREQ_112896); 208 set_max9485_clk(MAX9485_MCLK_FREQ_225792);
196 clk = 11289600; 209 clk = 22579200;
210 break;
211 case 96000:
212 set_max9485_clk(MAX9485_MCLK_FREQ_245760);
213 clk = 24576000;
197 break; 214 break;
215 default:
216 return -EINVAL;
198 } 217 }
199 218
200 fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF; 219 fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
@@ -217,7 +236,7 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
217 if (ret < 0) 236 if (ret < 0)
218 return ret; 237 return ret;
219 238
220 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1); 239 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
221 if (ret < 0) 240 if (ret < 0)
222 return ret; 241 return ret;
223 242
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index cc7edb5f792..93ed3aad163 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -15,16 +15,10 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/device.h> 17#include <linux/device.h>
18#include <linux/delay.h>
19#include <linux/clk.h> 18#include <linux/clk.h>
20#include <linux/kernel.h>
21#include <linux/gpio.h> 19#include <linux/gpio.h>
22#include <linux/io.h> 20#include <linux/io.h>
23 21
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/initval.h>
28#include <sound/soc.h> 22#include <sound/soc.h>
29 23
30#include <plat/regs-s3c2412-iis.h> 24#include <plat/regs-s3c2412-iis.h>
@@ -38,6 +32,11 @@
38#include "s3c-dma.h" 32#include "s3c-dma.h"
39#include "s3c64xx-i2s.h" 33#include "s3c64xx-i2s.h"
40 34
35/* The value should be set to maximum of the total number
36 * of I2Sv3 controllers that any supported SoC has.
37 */
38#define MAX_I2SV3 2
39
41static struct s3c2410_dma_client s3c64xx_dma_client_out = { 40static struct s3c2410_dma_client s3c64xx_dma_client_out = {
42 .name = "I2S PCM Stereo out" 41 .name = "I2S PCM Stereo out"
43}; 42};
@@ -46,37 +45,12 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = {
46 .name = "I2S PCM Stereo in" 45 .name = "I2S PCM Stereo in"
47}; 46};
48 47
49static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { 48static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3];
50 [0] = { 49static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
51 .channel = DMACH_I2S0_OUT, 50static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
52 .client = &s3c64xx_dma_client_out,
53 .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD,
54 .dma_size = 4,
55 },
56 [1] = {
57 .channel = DMACH_I2S1_OUT,
58 .client = &s3c64xx_dma_client_out,
59 .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD,
60 .dma_size = 4,
61 },
62};
63
64static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[2] = {
65 [0] = {
66 .channel = DMACH_I2S0_IN,
67 .client = &s3c64xx_dma_client_in,
68 .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD,
69 .dma_size = 4,
70 },
71 [1] = {
72 .channel = DMACH_I2S1_IN,
73 .client = &s3c64xx_dma_client_in,
74 .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD,
75 .dma_size = 4,
76 },
77};
78 51
79static struct s3c_i2sv2_info s3c64xx_i2s[2]; 52struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3];
53EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
80 54
81static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) 55static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
82{ 56{
@@ -169,55 +143,13 @@ static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
169 .set_sysclk = s3c64xx_i2s_set_sysclk, 143 .set_sysclk = s3c64xx_i2s_set_sysclk,
170}; 144};
171 145
172struct snd_soc_dai s3c64xx_i2s_dai[] = {
173 {
174 .name = "s3c64xx-i2s",
175 .id = 0,
176 .probe = s3c64xx_i2s_probe,
177 .playback = {
178 .channels_min = 2,
179 .channels_max = 2,
180 .rates = S3C64XX_I2S_RATES,
181 .formats = S3C64XX_I2S_FMTS,
182 },
183 .capture = {
184 .channels_min = 2,
185 .channels_max = 2,
186 .rates = S3C64XX_I2S_RATES,
187 .formats = S3C64XX_I2S_FMTS,
188 },
189 .ops = &s3c64xx_i2s_dai_ops,
190 .symmetric_rates = 1,
191 },
192 {
193 .name = "s3c64xx-i2s",
194 .id = 1,
195 .probe = s3c64xx_i2s_probe,
196 .playback = {
197 .channels_min = 2,
198 .channels_max = 2,
199 .rates = S3C64XX_I2S_RATES,
200 .formats = S3C64XX_I2S_FMTS,
201 },
202 .capture = {
203 .channels_min = 2,
204 .channels_max = 2,
205 .rates = S3C64XX_I2S_RATES,
206 .formats = S3C64XX_I2S_FMTS,
207 },
208 .ops = &s3c64xx_i2s_dai_ops,
209 .symmetric_rates = 1,
210 },
211};
212EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
213
214static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) 146static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
215{ 147{
216 struct s3c_i2sv2_info *i2s; 148 struct s3c_i2sv2_info *i2s;
217 struct snd_soc_dai *dai; 149 struct snd_soc_dai *dai;
218 int ret; 150 int ret;
219 151
220 if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) { 152 if (pdev->id >= MAX_I2SV3) {
221 dev_err(&pdev->dev, "id %d out of range\n", pdev->id); 153 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
222 return -EINVAL; 154 return -EINVAL;
223 } 155 }
@@ -225,10 +157,40 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
225 i2s = &s3c64xx_i2s[pdev->id]; 157 i2s = &s3c64xx_i2s[pdev->id];
226 dai = &s3c64xx_i2s_dai[pdev->id]; 158 dai = &s3c64xx_i2s_dai[pdev->id];
227 dai->dev = &pdev->dev; 159 dai->dev = &pdev->dev;
160 dai->name = "s3c64xx-i2s";
161 dai->id = pdev->id;
162 dai->symmetric_rates = 1;
163 dai->playback.channels_min = 2;
164 dai->playback.channels_max = 2;
165 dai->playback.rates = S3C64XX_I2S_RATES;
166 dai->playback.formats = S3C64XX_I2S_FMTS;
167 dai->capture.channels_min = 2;
168 dai->capture.channels_max = 2;
169 dai->capture.rates = S3C64XX_I2S_RATES;
170 dai->capture.formats = S3C64XX_I2S_FMTS;
171 dai->probe = s3c64xx_i2s_probe;
172 dai->ops = &s3c64xx_i2s_dai_ops;
228 173
229 i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; 174 i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
230 i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; 175 i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
231 176
177 if (pdev->id == 0) {
178 i2s->dma_capture->channel = DMACH_I2S0_IN;
179 i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD;
180 i2s->dma_playback->channel = DMACH_I2S0_OUT;
181 i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD;
182 } else {
183 i2s->dma_capture->channel = DMACH_I2S1_IN;
184 i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD;
185 i2s->dma_playback->channel = DMACH_I2S1_OUT;
186 i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD;
187 }
188
189 i2s->dma_capture->client = &s3c64xx_dma_client_in;
190 i2s->dma_capture->dma_size = 4;
191 i2s->dma_playback->client = &s3c64xx_dma_client_out;
192 i2s->dma_playback->dma_size = 4;
193
232 i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus"); 194 i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
233 if (IS_ERR(i2s->iis_cclk)) { 195 if (IS_ERR(i2s->iis_cclk)) {
234 dev_err(&pdev->dev, "failed to get audio-bus\n"); 196 dev_err(&pdev->dev, "failed to get audio-bus\n");
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 9e697658655..3f1cd550334 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -26,6 +26,12 @@ config SND_SOC_SH4_FSI
26 help 26 help
27 This option enables FSI sound support 27 This option enables FSI sound support
28 28
29config SND_SOC_SH4_SIU
30 tristate
31 depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
32 select DMADEVICES
33 select SH_DMAE
34
29## 35##
30## Boards 36## Boards
31## 37##
@@ -47,4 +53,12 @@ config SND_FSI_AK4642
47 This option enables generic sound support for the 53 This option enables generic sound support for the
48 FSI - AK4642 unit 54 FSI - AK4642 unit
49 55
56config SND_FSI_DA7210
57 bool "FSI-DA7210 sound support"
58 depends on SND_SOC_SH4_FSI
59 select SND_SOC_DA7210
60 help
61 This option enables generic sound support for the
62 FSI - DA7210 unit
63
50endmenu 64endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
index a6997872f24..5a97d2539d8 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -6,13 +6,17 @@ obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o
6snd-soc-hac-objs := hac.o 6snd-soc-hac-objs := hac.o
7snd-soc-ssi-objs := ssi.o 7snd-soc-ssi-objs := ssi.o
8snd-soc-fsi-objs := fsi.o 8snd-soc-fsi-objs := fsi.o
9snd-soc-siu-objs := siu_pcm.o siu_dai.o
9obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o 10obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o
10obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o 11obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
11obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o 12obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o
13obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o
12 14
13## boards 15## boards
14snd-soc-sh7760-ac97-objs := sh7760-ac97.o 16snd-soc-sh7760-ac97-objs := sh7760-ac97.o
15snd-soc-fsi-ak4642-objs := fsi-ak4642.o 17snd-soc-fsi-ak4642-objs := fsi-ak4642.o
18snd-soc-fsi-da7210-objs := fsi-da7210.o
16 19
17obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o 20obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
18obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o 21obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o
22obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
new file mode 100644
index 00000000000..33b4d177f46
--- /dev/null
+++ b/sound/soc/sh/fsi-da7210.c
@@ -0,0 +1,83 @@
1/*
2 * fsi-da7210.c
3 *
4 * Copyright (C) 2009 Renesas Solutions Corp.
5 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/interrupt.h>
14#include <linux/platform_device.h>
15#include <linux/io.h>
16#include <linux/i2c.h>
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22
23#include <sound/sh_fsi.h>
24#include "../codecs/da7210.h"
25
26static int fsi_da7210_init(struct snd_soc_codec *codec)
27{
28 return snd_soc_dai_set_fmt(&da7210_dai,
29 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
30 SND_SOC_DAIFMT_CBM_CFM);
31}
32
33static struct snd_soc_dai_link fsi_da7210_dai = {
34 .name = "DA7210",
35 .stream_name = "DA7210",
36 .cpu_dai = &fsi_soc_dai[1], /* FSI B */
37 .codec_dai = &da7210_dai,
38 .init = fsi_da7210_init,
39};
40
41static struct snd_soc_card fsi_soc_card = {
42 .name = "FSI",
43 .platform = &fsi_soc_platform,
44 .dai_link = &fsi_da7210_dai,
45 .num_links = 1,
46};
47
48static struct snd_soc_device fsi_da7210_snd_devdata = {
49 .card = &fsi_soc_card,
50 .codec_dev = &soc_codec_dev_da7210,
51};
52
53static struct platform_device *fsi_da7210_snd_device;
54
55static int __init fsi_da7210_sound_init(void)
56{
57 int ret;
58
59 fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1);
60 if (!fsi_da7210_snd_device)
61 return -ENOMEM;
62
63 platform_set_drvdata(fsi_da7210_snd_device, &fsi_da7210_snd_devdata);
64 fsi_da7210_snd_devdata.dev = &fsi_da7210_snd_device->dev;
65 ret = platform_device_add(fsi_da7210_snd_device);
66 if (ret)
67 platform_device_put(fsi_da7210_snd_device);
68
69 return ret;
70}
71
72static void __exit fsi_da7210_sound_exit(void)
73{
74 platform_device_unregister(fsi_da7210_snd_device);
75}
76
77module_init(fsi_da7210_sound_init);
78module_exit(fsi_da7210_sound_exit);
79
80/* Module information */
81MODULE_DESCRIPTION("ALSA SoC FSI DA2710");
82MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
83MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 42813b80838..5f9f2693f4e 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -67,6 +67,7 @@
67/* DOFF_ST */ 67/* DOFF_ST */
68#define ERR_OVER 0x00000010 68#define ERR_OVER 0x00000010
69#define ERR_UNDER 0x00000001 69#define ERR_UNDER 0x00000001
70#define ST_ERR (ERR_OVER | ERR_UNDER)
70 71
71/* CLK_RST */ 72/* CLK_RST */
72#define B_CLK 0x00000010 73#define B_CLK 0x00000010
@@ -92,6 +93,7 @@
92struct fsi_priv { 93struct fsi_priv {
93 void __iomem *base; 94 void __iomem *base;
94 struct snd_pcm_substream *substream; 95 struct snd_pcm_substream *substream;
96 struct fsi_master *master;
95 97
96 int fifo_max; 98 int fifo_max;
97 int chan; 99 int chan;
@@ -110,8 +112,6 @@ struct fsi_master {
110 struct sh_fsi_platform_info *info; 112 struct sh_fsi_platform_info *info;
111}; 113};
112 114
113static struct fsi_master *master;
114
115/************************************************************************ 115/************************************************************************
116 116
117 117
@@ -166,7 +166,7 @@ static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
166 return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); 166 return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
167} 167}
168 168
169static int fsi_master_write(u32 reg, u32 data) 169static int fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
170{ 170{
171 if ((reg < MREG_START) || 171 if ((reg < MREG_START) ||
172 (reg > MREG_END)) 172 (reg > MREG_END))
@@ -175,7 +175,7 @@ static int fsi_master_write(u32 reg, u32 data)
175 return __fsi_reg_write((u32)(master->base + reg), data); 175 return __fsi_reg_write((u32)(master->base + reg), data);
176} 176}
177 177
178static u32 fsi_master_read(u32 reg) 178static u32 fsi_master_read(struct fsi_master *master, u32 reg)
179{ 179{
180 if ((reg < MREG_START) || 180 if ((reg < MREG_START) ||
181 (reg > MREG_END)) 181 (reg > MREG_END))
@@ -184,7 +184,8 @@ static u32 fsi_master_read(u32 reg)
184 return __fsi_reg_read((u32)(master->base + reg)); 184 return __fsi_reg_read((u32)(master->base + reg));
185} 185}
186 186
187static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) 187static int fsi_master_mask_set(struct fsi_master *master,
188 u32 reg, u32 mask, u32 data)
188{ 189{
189 if ((reg < MREG_START) || 190 if ((reg < MREG_START) ||
190 (reg > MREG_END)) 191 (reg > MREG_END))
@@ -200,43 +201,35 @@ static int fsi_master_mask_set(u32 reg, u32 mask, u32 data)
200 201
201 202
202************************************************************************/ 203************************************************************************/
203static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream) 204static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
204{ 205{
205 struct snd_soc_pcm_runtime *rtd; 206 return fsi->master;
206 struct fsi_priv *fsi = NULL; 207}
207 208
208 if (!substream || !master) 209static int fsi_is_port_a(struct fsi_priv *fsi)
209 return NULL; 210{
211 return fsi->master->base == fsi->base;
212}
210 213
211 rtd = substream->private_data; 214static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
212 switch (rtd->dai->cpu_dai->id) { 215{
213 case 0: 216 struct snd_soc_pcm_runtime *rtd = substream->private_data;
214 fsi = &master->fsia; 217 struct snd_soc_dai_link *machine = rtd->dai;
215 break;
216 case 1:
217 fsi = &master->fsib;
218 break;
219 }
220 218
221 return fsi; 219 return machine->cpu_dai;
222} 220}
223 221
224static int fsi_is_port_a(struct fsi_priv *fsi) 222static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream)
225{ 223{
226 /* return 224 struct snd_soc_dai *dai = fsi_get_dai(substream);
227 * 1 : port a
228 * 0 : port b
229 */
230
231 if (fsi == &master->fsia)
232 return 1;
233 225
234 return 0; 226 return dai->private_data;
235} 227}
236 228
237static u32 fsi_get_info_flags(struct fsi_priv *fsi) 229static u32 fsi_get_info_flags(struct fsi_priv *fsi)
238{ 230{
239 int is_porta = fsi_is_port_a(fsi); 231 int is_porta = fsi_is_port_a(fsi);
232 struct fsi_master *master = fsi_get_master(fsi);
240 233
241 return is_porta ? master->info->porta_flags : 234 return is_porta ? master->info->porta_flags :
242 master->info->portb_flags; 235 master->info->portb_flags;
@@ -314,27 +307,30 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play)
314static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) 307static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
315{ 308{
316 u32 data = fsi_port_ab_io_bit(fsi, is_play); 309 u32 data = fsi_port_ab_io_bit(fsi, is_play);
310 struct fsi_master *master = fsi_get_master(fsi);
317 311
318 fsi_master_mask_set(IMSK, data, data); 312 fsi_master_mask_set(master, IMSK, data, data);
319 fsi_master_mask_set(IEMSK, data, data); 313 fsi_master_mask_set(master, IEMSK, data, data);
320} 314}
321 315
322static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) 316static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
323{ 317{
324 u32 data = fsi_port_ab_io_bit(fsi, is_play); 318 u32 data = fsi_port_ab_io_bit(fsi, is_play);
319 struct fsi_master *master = fsi_get_master(fsi);
325 320
326 fsi_master_mask_set(IMSK, data, 0); 321 fsi_master_mask_set(master, IMSK, data, 0);
327 fsi_master_mask_set(IEMSK, data, 0); 322 fsi_master_mask_set(master, IEMSK, data, 0);
328} 323}
329 324
330static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) 325static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
331{ 326{
332 u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); 327 u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
328 struct fsi_master *master = fsi_get_master(fsi);
333 329
334 if (enable) 330 if (enable)
335 fsi_master_mask_set(CLK_RST, val, val); 331 fsi_master_mask_set(master, CLK_RST, val, val);
336 else 332 else
337 fsi_master_mask_set(CLK_RST, val, 0); 333 fsi_master_mask_set(master, CLK_RST, val, 0);
338} 334}
339 335
340static void fsi_irq_init(struct fsi_priv *fsi, int is_play) 336static void fsi_irq_init(struct fsi_priv *fsi, int is_play)
@@ -355,23 +351,23 @@ static void fsi_irq_init(struct fsi_priv *fsi, int is_play)
355 fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); 351 fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR);
356 352
357 /* clear interrupt factor */ 353 /* clear interrupt factor */
358 fsi_master_mask_set(INT_ST, data, 0); 354 fsi_master_mask_set(fsi_get_master(fsi), INT_ST, data, 0);
359} 355}
360 356
361static void fsi_soft_all_reset(void) 357static void fsi_soft_all_reset(struct fsi_master *master)
362{ 358{
363 u32 status = fsi_master_read(SOFT_RST); 359 u32 status = fsi_master_read(master, SOFT_RST);
364 360
365 /* port AB reset */ 361 /* port AB reset */
366 status &= 0x000000ff; 362 status &= 0x000000ff;
367 fsi_master_write(SOFT_RST, status); 363 fsi_master_write(master, SOFT_RST, status);
368 mdelay(10); 364 mdelay(10);
369 365
370 /* soft reset */ 366 /* soft reset */
371 status &= 0x000000f0; 367 status &= 0x000000f0;
372 fsi_master_write(SOFT_RST, status); 368 fsi_master_write(master, SOFT_RST, status);
373 status |= 0x00000001; 369 status |= 0x00000001;
374 fsi_master_write(SOFT_RST, status); 370 fsi_master_write(master, SOFT_RST, status);
375 mdelay(10); 371 mdelay(10);
376} 372}
377 373
@@ -380,18 +376,21 @@ static int fsi_data_push(struct fsi_priv *fsi)
380{ 376{
381 struct snd_pcm_runtime *runtime; 377 struct snd_pcm_runtime *runtime;
382 struct snd_pcm_substream *substream = NULL; 378 struct snd_pcm_substream *substream = NULL;
379 u32 status;
383 int send; 380 int send;
384 int fifo_free; 381 int fifo_free;
385 int width; 382 int width;
386 u8 *start; 383 u8 *start;
387 int i; 384 int i, ret, over_period;
388 385
389 if (!fsi || 386 if (!fsi ||
390 !fsi->substream || 387 !fsi->substream ||
391 !fsi->substream->runtime) 388 !fsi->substream->runtime)
392 return -EINVAL; 389 return -EINVAL;
393 390
394 runtime = fsi->substream->runtime; 391 over_period = 0;
392 substream = fsi->substream;
393 runtime = substream->runtime;
395 394
396 /* FSI FIFO has limit. 395 /* FSI FIFO has limit.
397 * So, this driver can not send periods data at a time 396 * So, this driver can not send periods data at a time
@@ -399,7 +398,7 @@ static int fsi_data_push(struct fsi_priv *fsi)
399 if (fsi->byte_offset >= 398 if (fsi->byte_offset >=
400 fsi->period_len * (fsi->periods + 1)) { 399 fsi->period_len * (fsi->periods + 1)) {
401 400
402 substream = fsi->substream; 401 over_period = 1;
403 fsi->periods = (fsi->periods + 1) % runtime->periods; 402 fsi->periods = (fsi->periods + 1) % runtime->periods;
404 403
405 if (0 == fsi->periods) 404 if (0 == fsi->periods)
@@ -438,30 +437,42 @@ static int fsi_data_push(struct fsi_priv *fsi)
438 437
439 fsi->byte_offset += send * width; 438 fsi->byte_offset += send * width;
440 439
440 ret = 0;
441 status = fsi_reg_read(fsi, DOFF_ST);
442 if (status & ERR_OVER) {
443 struct snd_soc_dai *dai = fsi_get_dai(substream);
444 dev_err(dai->dev, "over run error\n");
445 fsi_reg_write(fsi, DOFF_ST, status & ~ST_ERR);
446 ret = -EIO;
447 }
448
441 fsi_irq_enable(fsi, 1); 449 fsi_irq_enable(fsi, 1);
442 450
443 if (substream) 451 if (over_period)
444 snd_pcm_period_elapsed(substream); 452 snd_pcm_period_elapsed(substream);
445 453
446 return 0; 454 return ret;
447} 455}
448 456
449static int fsi_data_pop(struct fsi_priv *fsi) 457static int fsi_data_pop(struct fsi_priv *fsi)
450{ 458{
451 struct snd_pcm_runtime *runtime; 459 struct snd_pcm_runtime *runtime;
452 struct snd_pcm_substream *substream = NULL; 460 struct snd_pcm_substream *substream = NULL;
461 u32 status;
453 int free; 462 int free;
454 int fifo_fill; 463 int fifo_fill;
455 int width; 464 int width;
456 u8 *start; 465 u8 *start;
457 int i; 466 int i, ret, over_period;
458 467
459 if (!fsi || 468 if (!fsi ||
460 !fsi->substream || 469 !fsi->substream ||
461 !fsi->substream->runtime) 470 !fsi->substream->runtime)
462 return -EINVAL; 471 return -EINVAL;
463 472
464 runtime = fsi->substream->runtime; 473 over_period = 0;
474 substream = fsi->substream;
475 runtime = substream->runtime;
465 476
466 /* FSI FIFO has limit. 477 /* FSI FIFO has limit.
467 * So, this driver can not send periods data at a time 478 * So, this driver can not send periods data at a time
@@ -469,7 +480,7 @@ static int fsi_data_pop(struct fsi_priv *fsi)
469 if (fsi->byte_offset >= 480 if (fsi->byte_offset >=
470 fsi->period_len * (fsi->periods + 1)) { 481 fsi->period_len * (fsi->periods + 1)) {
471 482
472 substream = fsi->substream; 483 over_period = 1;
473 fsi->periods = (fsi->periods + 1) % runtime->periods; 484 fsi->periods = (fsi->periods + 1) % runtime->periods;
474 485
475 if (0 == fsi->periods) 486 if (0 == fsi->periods)
@@ -507,22 +518,32 @@ static int fsi_data_pop(struct fsi_priv *fsi)
507 518
508 fsi->byte_offset += fifo_fill * width; 519 fsi->byte_offset += fifo_fill * width;
509 520
521 ret = 0;
522 status = fsi_reg_read(fsi, DIFF_ST);
523 if (status & ERR_UNDER) {
524 struct snd_soc_dai *dai = fsi_get_dai(substream);
525 dev_err(dai->dev, "under run error\n");
526 fsi_reg_write(fsi, DIFF_ST, status & ~ST_ERR);
527 ret = -EIO;
528 }
529
510 fsi_irq_enable(fsi, 0); 530 fsi_irq_enable(fsi, 0);
511 531
512 if (substream) 532 if (over_period)
513 snd_pcm_period_elapsed(substream); 533 snd_pcm_period_elapsed(substream);
514 534
515 return 0; 535 return ret;
516} 536}
517 537
518static irqreturn_t fsi_interrupt(int irq, void *data) 538static irqreturn_t fsi_interrupt(int irq, void *data)
519{ 539{
520 u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; 540 struct fsi_master *master = data;
521 u32 int_st = fsi_master_read(INT_ST); 541 u32 status = fsi_master_read(master, SOFT_RST) & ~0x00000010;
542 u32 int_st = fsi_master_read(master, INT_ST);
522 543
523 /* clear irq status */ 544 /* clear irq status */
524 fsi_master_write(SOFT_RST, status); 545 fsi_master_write(master, SOFT_RST, status);
525 fsi_master_write(SOFT_RST, status | 0x00000010); 546 fsi_master_write(master, SOFT_RST, status | 0x00000010);
526 547
527 if (int_st & INT_A_OUT) 548 if (int_st & INT_A_OUT)
528 fsi_data_push(&master->fsia); 549 fsi_data_push(&master->fsia);
@@ -533,7 +554,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
533 if (int_st & INT_B_IN) 554 if (int_st & INT_B_IN)
534 fsi_data_pop(&master->fsib); 555 fsi_data_pop(&master->fsib);
535 556
536 fsi_master_write(INT_ST, 0x0000000); 557 fsi_master_write(master, INT_ST, 0x0000000);
537 558
538 return IRQ_HANDLED; 559 return IRQ_HANDLED;
539} 560}
@@ -548,7 +569,7 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
548static int fsi_dai_startup(struct snd_pcm_substream *substream, 569static int fsi_dai_startup(struct snd_pcm_substream *substream,
549 struct snd_soc_dai *dai) 570 struct snd_soc_dai *dai)
550{ 571{
551 struct fsi_priv *fsi = fsi_get(substream); 572 struct fsi_priv *fsi = fsi_get_priv(substream);
552 const char *msg; 573 const char *msg;
553 u32 flags = fsi_get_info_flags(fsi); 574 u32 flags = fsi_get_info_flags(fsi);
554 u32 fmt; 575 u32 fmt;
@@ -667,7 +688,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
667static void fsi_dai_shutdown(struct snd_pcm_substream *substream, 688static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
668 struct snd_soc_dai *dai) 689 struct snd_soc_dai *dai)
669{ 690{
670 struct fsi_priv *fsi = fsi_get(substream); 691 struct fsi_priv *fsi = fsi_get_priv(substream);
671 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 692 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
672 693
673 fsi_irq_disable(fsi, is_play); 694 fsi_irq_disable(fsi, is_play);
@@ -679,7 +700,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
679static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, 700static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
680 struct snd_soc_dai *dai) 701 struct snd_soc_dai *dai)
681{ 702{
682 struct fsi_priv *fsi = fsi_get(substream); 703 struct fsi_priv *fsi = fsi_get_priv(substream);
683 struct snd_pcm_runtime *runtime = substream->runtime; 704 struct snd_pcm_runtime *runtime = substream->runtime;
684 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 705 int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
685 int ret = 0; 706 int ret = 0;
@@ -760,7 +781,7 @@ static int fsi_hw_free(struct snd_pcm_substream *substream)
760static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) 781static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
761{ 782{
762 struct snd_pcm_runtime *runtime = substream->runtime; 783 struct snd_pcm_runtime *runtime = substream->runtime;
763 struct fsi_priv *fsi = fsi_get(substream); 784 struct fsi_priv *fsi = fsi_get_priv(substream);
764 long location; 785 long location;
765 786
766 location = (fsi->byte_offset - 1); 787 location = (fsi->byte_offset - 1);
@@ -870,10 +891,16 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform);
870************************************************************************/ 891************************************************************************/
871static int fsi_probe(struct platform_device *pdev) 892static int fsi_probe(struct platform_device *pdev)
872{ 893{
894 struct fsi_master *master;
873 struct resource *res; 895 struct resource *res;
874 unsigned int irq; 896 unsigned int irq;
875 int ret; 897 int ret;
876 898
899 if (0 != pdev->id) {
900 dev_err(&pdev->dev, "current fsi support id 0 only now\n");
901 return -ENODEV;
902 }
903
877 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 904 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
878 irq = platform_get_irq(pdev, 0); 905 irq = platform_get_irq(pdev, 0);
879 if (!res || (int)irq <= 0) { 906 if (!res || (int)irq <= 0) {
@@ -899,15 +926,19 @@ static int fsi_probe(struct platform_device *pdev)
899 master->irq = irq; 926 master->irq = irq;
900 master->info = pdev->dev.platform_data; 927 master->info = pdev->dev.platform_data;
901 master->fsia.base = master->base; 928 master->fsia.base = master->base;
929 master->fsia.master = master;
902 master->fsib.base = master->base + 0x40; 930 master->fsib.base = master->base + 0x40;
931 master->fsib.master = master;
903 932
904 pm_runtime_enable(&pdev->dev); 933 pm_runtime_enable(&pdev->dev);
905 pm_runtime_resume(&pdev->dev); 934 pm_runtime_resume(&pdev->dev);
906 935
907 fsi_soc_dai[0].dev = &pdev->dev; 936 fsi_soc_dai[0].dev = &pdev->dev;
937 fsi_soc_dai[0].private_data = &master->fsia;
908 fsi_soc_dai[1].dev = &pdev->dev; 938 fsi_soc_dai[1].dev = &pdev->dev;
939 fsi_soc_dai[1].private_data = &master->fsib;
909 940
910 fsi_soft_all_reset(); 941 fsi_soft_all_reset(master);
911 942
912 ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); 943 ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master);
913 if (ret) { 944 if (ret) {
@@ -937,6 +968,10 @@ exit:
937 968
938static int fsi_remove(struct platform_device *pdev) 969static int fsi_remove(struct platform_device *pdev)
939{ 970{
971 struct fsi_master *master;
972
973 master = fsi_get_master(fsi_soc_dai[0].private_data);
974
940 snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); 975 snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
941 snd_soc_unregister_platform(&fsi_soc_platform); 976 snd_soc_unregister_platform(&fsi_soc_platform);
942 977
@@ -946,7 +981,12 @@ static int fsi_remove(struct platform_device *pdev)
946 981
947 iounmap(master->base); 982 iounmap(master->base);
948 kfree(master); 983 kfree(master);
949 master = NULL; 984
985 fsi_soc_dai[0].dev = NULL;
986 fsi_soc_dai[0].private_data = NULL;
987 fsi_soc_dai[1].dev = NULL;
988 fsi_soc_dai[1].private_data = NULL;
989
950 return 0; 990 return 0;
951} 991}
952 992
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
new file mode 100644
index 00000000000..9cc04ab2bce
--- /dev/null
+++ b/sound/soc/sh/siu.h
@@ -0,0 +1,193 @@
1/*
2 * siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
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 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef SIU_H
23#define SIU_H
24
25/* Common kernel and user-space firmware-building defines and types */
26
27#define YRAM0_SIZE (0x0040 / 4) /* 16 */
28#define YRAM1_SIZE (0x0080 / 4) /* 32 */
29#define YRAM2_SIZE (0x0040 / 4) /* 16 */
30#define YRAM3_SIZE (0x0080 / 4) /* 32 */
31#define YRAM4_SIZE (0x0080 / 4) /* 32 */
32#define YRAM_DEF_SIZE (YRAM0_SIZE + YRAM1_SIZE + YRAM2_SIZE + \
33 YRAM3_SIZE + YRAM4_SIZE)
34#define YRAM_FIR_SIZE (0x0400 / 4) /* 256 */
35#define YRAM_IIR_SIZE (0x0200 / 4) /* 128 */
36
37#define XRAM0_SIZE (0x0400 / 4) /* 256 */
38#define XRAM1_SIZE (0x0200 / 4) /* 128 */
39#define XRAM2_SIZE (0x0200 / 4) /* 128 */
40
41/* PRAM program array size */
42#define PRAM0_SIZE (0x0100 / 4) /* 64 */
43#define PRAM1_SIZE ((0x2000 - 0x0100) / 4) /* 1984 */
44
45#include <linux/types.h>
46
47struct siu_spb_param {
48 __u32 ab1a; /* input FIFO address */
49 __u32 ab0a; /* output FIFO address */
50 __u32 dir; /* 0=the ather except CPUOUTPUT, 1=CPUINPUT */
51 __u32 event; /* SPB program starting conditions */
52 __u32 stfifo; /* STFIFO register setting value */
53 __u32 trdat; /* TRDAT register setting value */
54};
55
56struct siu_firmware {
57 __u32 yram_fir_coeff[YRAM_FIR_SIZE];
58 __u32 pram0[PRAM0_SIZE];
59 __u32 pram1[PRAM1_SIZE];
60 __u32 yram0[YRAM0_SIZE];
61 __u32 yram1[YRAM1_SIZE];
62 __u32 yram2[YRAM2_SIZE];
63 __u32 yram3[YRAM3_SIZE];
64 __u32 yram4[YRAM4_SIZE];
65 __u32 spbpar_num;
66 struct siu_spb_param spbpar[32];
67};
68
69#ifdef __KERNEL__
70
71#include <linux/dmaengine.h>
72#include <linux/interrupt.h>
73#include <linux/io.h>
74
75#include <asm/dma-sh.h>
76
77#include <sound/core.h>
78#include <sound/pcm.h>
79#include <sound/soc-dai.h>
80
81#define SIU_PERIOD_BYTES_MAX 8192 /* DMA transfer/period size */
82#define SIU_PERIOD_BYTES_MIN 256 /* DMA transfer/period size */
83#define SIU_PERIODS_MAX 64 /* Max periods in buffer */
84#define SIU_PERIODS_MIN 4 /* Min periods in buffer */
85#define SIU_BUFFER_BYTES_MAX (SIU_PERIOD_BYTES_MAX * SIU_PERIODS_MAX)
86
87/* SIU ports: only one can be used at a time */
88enum {
89 SIU_PORT_A,
90 SIU_PORT_B,
91 SIU_PORT_NUM,
92};
93
94/* SIU clock configuration */
95enum {
96 SIU_CLKA_PLL,
97 SIU_CLKA_EXT,
98 SIU_CLKB_PLL,
99 SIU_CLKB_EXT
100};
101
102struct siu_info {
103 int port_id;
104 u32 __iomem *pram;
105 u32 __iomem *xram;
106 u32 __iomem *yram;
107 u32 __iomem *reg;
108 struct siu_firmware fw;
109};
110
111struct siu_stream {
112 struct tasklet_struct tasklet;
113 struct snd_pcm_substream *substream;
114 snd_pcm_format_t format;
115 size_t buf_bytes;
116 size_t period_bytes;
117 int cur_period; /* Period currently in dma */
118 u32 volume;
119 snd_pcm_sframes_t xfer_cnt; /* Number of frames */
120 u8 rw_flg; /* transfer status */
121 /* DMA status */
122 struct dma_chan *chan; /* DMA channel */
123 struct dma_async_tx_descriptor *tx_desc;
124 dma_cookie_t cookie;
125 struct sh_dmae_slave param;
126};
127
128struct siu_port {
129 unsigned long play_cap; /* Used to track full duplex */
130 struct snd_pcm *pcm;
131 struct siu_stream playback;
132 struct siu_stream capture;
133 u32 stfifo; /* STFIFO value from firmware */
134 u32 trdat; /* TRDAT value from firmware */
135};
136
137extern struct siu_port *siu_ports[SIU_PORT_NUM];
138
139static inline struct siu_port *siu_port_info(struct snd_pcm_substream *substream)
140{
141 struct platform_device *pdev =
142 to_platform_device(substream->pcm->card->dev);
143 return siu_ports[pdev->id];
144}
145
146/* Register access */
147static inline void siu_write32(u32 __iomem *addr, u32 val)
148{
149 __raw_writel(val, addr);
150}
151
152static inline u32 siu_read32(u32 __iomem *addr)
153{
154 return __raw_readl(addr);
155}
156
157/* SIU registers */
158#define SIU_IFCTL (0x000 / sizeof(u32))
159#define SIU_SRCTL (0x004 / sizeof(u32))
160#define SIU_SFORM (0x008 / sizeof(u32))
161#define SIU_CKCTL (0x00c / sizeof(u32))
162#define SIU_TRDAT (0x010 / sizeof(u32))
163#define SIU_STFIFO (0x014 / sizeof(u32))
164#define SIU_DPAK (0x01c / sizeof(u32))
165#define SIU_CKREV (0x020 / sizeof(u32))
166#define SIU_EVNTC (0x028 / sizeof(u32))
167#define SIU_SBCTL (0x040 / sizeof(u32))
168#define SIU_SBPSET (0x044 / sizeof(u32))
169#define SIU_SBFSTS (0x068 / sizeof(u32))
170#define SIU_SBDVCA (0x06c / sizeof(u32))
171#define SIU_SBDVCB (0x070 / sizeof(u32))
172#define SIU_SBACTIV (0x074 / sizeof(u32))
173#define SIU_DMAIA (0x090 / sizeof(u32))
174#define SIU_DMAIB (0x094 / sizeof(u32))
175#define SIU_DMAOA (0x098 / sizeof(u32))
176#define SIU_DMAOB (0x09c / sizeof(u32))
177#define SIU_DMAML (0x0a0 / sizeof(u32))
178#define SIU_SPSTS (0x0cc / sizeof(u32))
179#define SIU_SPCTL (0x0d0 / sizeof(u32))
180#define SIU_BRGASEL (0x100 / sizeof(u32))
181#define SIU_BRRA (0x104 / sizeof(u32))
182#define SIU_BRGBSEL (0x108 / sizeof(u32))
183#define SIU_BRRB (0x10c / sizeof(u32))
184
185extern struct snd_soc_platform siu_platform;
186extern struct snd_soc_dai siu_i2s_dai;
187
188int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card);
189void siu_free_port(struct siu_port *port_info);
190
191#endif
192
193#endif /* SIU_H */
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
new file mode 100644
index 00000000000..5452d19607e
--- /dev/null
+++ b/sound/soc/sh/siu_dai.c
@@ -0,0 +1,847 @@
1/*
2 * siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
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 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/delay.h>
23#include <linux/firmware.h>
24#include <linux/pm_runtime.h>
25
26#include <asm/clock.h>
27#include <asm/siu.h>
28
29#include <sound/control.h>
30#include <sound/soc-dai.h>
31
32#include "siu.h"
33
34/* Board specifics */
35#if defined(CONFIG_CPU_SUBTYPE_SH7722)
36# define SIU_MAX_VOLUME 0x1000
37#else
38# define SIU_MAX_VOLUME 0x7fff
39#endif
40
41#define PRAM_SIZE 0x2000
42#define XRAM_SIZE 0x800
43#define YRAM_SIZE 0x800
44
45#define XRAM_OFFSET 0x4000
46#define YRAM_OFFSET 0x6000
47#define REG_OFFSET 0xc000
48
49#define PLAYBACK_ENABLED 1
50#define CAPTURE_ENABLED 2
51
52#define VOLUME_CAPTURE 0
53#define VOLUME_PLAYBACK 1
54#define DFLT_VOLUME_LEVEL 0x08000800
55
56/*
57 * SPDIF is only available on port A and on some SIU implementations it is only
58 * available for input. Due to the lack of hardware to test it, SPDIF is left
59 * disabled in this driver version
60 */
61struct format_flag {
62 u32 i2s;
63 u32 pcm;
64 u32 spdif;
65 u32 mask;
66};
67
68struct port_flag {
69 struct format_flag playback;
70 struct format_flag capture;
71};
72
73static struct port_flag siu_flags[SIU_PORT_NUM] = {
74 [SIU_PORT_A] = {
75 .playback = {
76 .i2s = 0x50000000,
77 .pcm = 0x40000000,
78 .spdif = 0x80000000, /* not on all SIU versions */
79 .mask = 0xd0000000,
80 },
81 .capture = {
82 .i2s = 0x05000000,
83 .pcm = 0x04000000,
84 .spdif = 0x08000000,
85 .mask = 0x0d000000,
86 },
87 },
88 [SIU_PORT_B] = {
89 .playback = {
90 .i2s = 0x00500000,
91 .pcm = 0x00400000,
92 .spdif = 0, /* impossible - turn off */
93 .mask = 0x00500000,
94 },
95 .capture = {
96 .i2s = 0x00050000,
97 .pcm = 0x00040000,
98 .spdif = 0, /* impossible - turn off */
99 .mask = 0x00050000,
100 },
101 },
102};
103
104static void siu_dai_start(struct siu_port *port_info)
105{
106 struct siu_info *info = siu_i2s_dai.private_data;
107 u32 __iomem *base = info->reg;
108
109 dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
110
111 /* Turn on SIU clock */
112 pm_runtime_get_sync(siu_i2s_dai.dev);
113
114 /* Issue software reset to siu */
115 siu_write32(base + SIU_SRCTL, 0);
116
117 /* Wait for the reset to take effect */
118 udelay(1);
119
120 port_info->stfifo = 0;
121 port_info->trdat = 0;
122
123 /* portA, portB, SIU operate */
124 siu_write32(base + SIU_SRCTL, 0x301);
125
126 /* portA=256fs, portB=256fs */
127 siu_write32(base + SIU_CKCTL, 0x40400000);
128
129 /* portA's BRG does not divide SIUCKA */
130 siu_write32(base + SIU_BRGASEL, 0);
131 siu_write32(base + SIU_BRRA, 0);
132
133 /* portB's BRG divides SIUCKB by half */
134 siu_write32(base + SIU_BRGBSEL, 1);
135 siu_write32(base + SIU_BRRB, 0);
136
137 siu_write32(base + SIU_IFCTL, 0x44440000);
138
139 /* portA: 32 bit/fs, master; portB: 32 bit/fs, master */
140 siu_write32(base + SIU_SFORM, 0x0c0c0000);
141
142 /*
143 * Volume levels: looks like the DSP firmware implements volume controls
144 * differently from what's described in the datasheet
145 */
146 siu_write32(base + SIU_SBDVCA, port_info->playback.volume);
147 siu_write32(base + SIU_SBDVCB, port_info->capture.volume);
148}
149
150static void siu_dai_stop(void)
151{
152 struct siu_info *info = siu_i2s_dai.private_data;
153 u32 __iomem *base = info->reg;
154
155 /* SIU software reset */
156 siu_write32(base + SIU_SRCTL, 0);
157
158 /* Turn off SIU clock */
159 pm_runtime_put_sync(siu_i2s_dai.dev);
160}
161
162static void siu_dai_spbAselect(struct siu_port *port_info)
163{
164 struct siu_info *info = siu_i2s_dai.private_data;
165 struct siu_firmware *fw = &info->fw;
166 u32 *ydef = fw->yram0;
167 u32 idx;
168
169 /* path A use */
170 if (!info->port_id)
171 idx = 1; /* portA */
172 else
173 idx = 2; /* portB */
174
175 ydef[0] = (fw->spbpar[idx].ab1a << 16) |
176 (fw->spbpar[idx].ab0a << 8) |
177 (fw->spbpar[idx].dir << 7) | 3;
178 ydef[1] = fw->yram0[1]; /* 0x03000300 */
179 ydef[2] = (16 / 2) << 24;
180 ydef[3] = fw->yram0[3]; /* 0 */
181 ydef[4] = fw->yram0[4]; /* 0 */
182 ydef[7] = fw->spbpar[idx].event;
183 port_info->stfifo |= fw->spbpar[idx].stfifo;
184 port_info->trdat |= fw->spbpar[idx].trdat;
185}
186
187static void siu_dai_spbBselect(struct siu_port *port_info)
188{
189 struct siu_info *info = siu_i2s_dai.private_data;
190 struct siu_firmware *fw = &info->fw;
191 u32 *ydef = fw->yram0;
192 u32 idx;
193
194 /* path B use */
195 if (!info->port_id)
196 idx = 7; /* portA */
197 else
198 idx = 8; /* portB */
199
200 ydef[5] = (fw->spbpar[idx].ab1a << 16) |
201 (fw->spbpar[idx].ab0a << 8) | 1;
202 ydef[6] = fw->spbpar[idx].event;
203 port_info->stfifo |= fw->spbpar[idx].stfifo;
204 port_info->trdat |= fw->spbpar[idx].trdat;
205}
206
207static void siu_dai_open(struct siu_stream *siu_stream)
208{
209 struct siu_info *info = siu_i2s_dai.private_data;
210 u32 __iomem *base = info->reg;
211 u32 srctl, ifctl;
212
213 srctl = siu_read32(base + SIU_SRCTL);
214 ifctl = siu_read32(base + SIU_IFCTL);
215
216 switch (info->port_id) {
217 case SIU_PORT_A:
218 /* portA operates */
219 srctl |= 0x200;
220 ifctl &= ~0xc2;
221 break;
222 case SIU_PORT_B:
223 /* portB operates */
224 srctl |= 0x100;
225 ifctl &= ~0x31;
226 break;
227 }
228
229 siu_write32(base + SIU_SRCTL, srctl);
230 /* Unmute and configure portA */
231 siu_write32(base + SIU_IFCTL, ifctl);
232}
233
234/*
235 * At the moment only fixed Left-upper, Left-lower, Right-upper, Right-lower
236 * packing is supported
237 */
238static void siu_dai_pcmdatapack(struct siu_stream *siu_stream)
239{
240 struct siu_info *info = siu_i2s_dai.private_data;
241 u32 __iomem *base = info->reg;
242 u32 dpak;
243
244 dpak = siu_read32(base + SIU_DPAK);
245
246 switch (info->port_id) {
247 case SIU_PORT_A:
248 dpak &= ~0xc0000000;
249 break;
250 case SIU_PORT_B:
251 dpak &= ~0x00c00000;
252 break;
253 }
254
255 siu_write32(base + SIU_DPAK, dpak);
256}
257
258static int siu_dai_spbstart(struct siu_port *port_info)
259{
260 struct siu_info *info = siu_i2s_dai.private_data;
261 u32 __iomem *base = info->reg;
262 struct siu_firmware *fw = &info->fw;
263 u32 *ydef = fw->yram0;
264 int cnt;
265 u32 __iomem *add;
266 u32 *ptr;
267
268 /* Load SPB Program in PRAM */
269 ptr = fw->pram0;
270 add = info->pram;
271 for (cnt = 0; cnt < PRAM0_SIZE; cnt++, add++, ptr++)
272 siu_write32(add, *ptr);
273
274 ptr = fw->pram1;
275 add = info->pram + (0x0100 / sizeof(u32));
276 for (cnt = 0; cnt < PRAM1_SIZE; cnt++, add++, ptr++)
277 siu_write32(add, *ptr);
278
279 /* XRAM initialization */
280 add = info->xram;
281 for (cnt = 0; cnt < XRAM0_SIZE + XRAM1_SIZE + XRAM2_SIZE; cnt++, add++)
282 siu_write32(add, 0);
283
284 /* YRAM variable area initialization */
285 add = info->yram;
286 for (cnt = 0; cnt < YRAM_DEF_SIZE; cnt++, add++)
287 siu_write32(add, ydef[cnt]);
288
289 /* YRAM FIR coefficient area initialization */
290 add = info->yram + (0x0200 / sizeof(u32));
291 for (cnt = 0; cnt < YRAM_FIR_SIZE; cnt++, add++)
292 siu_write32(add, fw->yram_fir_coeff[cnt]);
293
294 /* YRAM IIR coefficient area initialization */
295 add = info->yram + (0x0600 / sizeof(u32));
296 for (cnt = 0; cnt < YRAM_IIR_SIZE; cnt++, add++)
297 siu_write32(add, 0);
298
299 siu_write32(base + SIU_TRDAT, port_info->trdat);
300 port_info->trdat = 0x0;
301
302
303 /* SPB start condition: software */
304 siu_write32(base + SIU_SBACTIV, 0);
305 /* Start SPB */
306 siu_write32(base + SIU_SBCTL, 0xc0000000);
307 /* Wait for program to halt */
308 cnt = 0x10000;
309 while (--cnt && siu_read32(base + SIU_SBCTL) != 0x80000000)
310 cpu_relax();
311
312 if (!cnt)
313 return -EBUSY;
314
315 /* SPB program start address setting */
316 siu_write32(base + SIU_SBPSET, 0x00400000);
317 /* SPB hardware start(FIFOCTL source) */
318 siu_write32(base + SIU_SBACTIV, 0xc0000000);
319
320 return 0;
321}
322
323static void siu_dai_spbstop(struct siu_port *port_info)
324{
325 struct siu_info *info = siu_i2s_dai.private_data;
326 u32 __iomem *base = info->reg;
327
328 siu_write32(base + SIU_SBACTIV, 0);
329 /* SPB stop */
330 siu_write32(base + SIU_SBCTL, 0);
331
332 port_info->stfifo = 0;
333}
334
335/* API functions */
336
337/* Playback and capture hardware properties are identical */
338static struct snd_pcm_hardware siu_dai_pcm_hw = {
339 .info = SNDRV_PCM_INFO_INTERLEAVED,
340 .formats = SNDRV_PCM_FMTBIT_S16,
341 .rates = SNDRV_PCM_RATE_8000_48000,
342 .rate_min = 8000,
343 .rate_max = 48000,
344 .channels_min = 2,
345 .channels_max = 2,
346 .buffer_bytes_max = SIU_BUFFER_BYTES_MAX,
347 .period_bytes_min = SIU_PERIOD_BYTES_MIN,
348 .period_bytes_max = SIU_PERIOD_BYTES_MAX,
349 .periods_min = SIU_PERIODS_MIN,
350 .periods_max = SIU_PERIODS_MAX,
351};
352
353static int siu_dai_info_volume(struct snd_kcontrol *kctrl,
354 struct snd_ctl_elem_info *uinfo)
355{
356 struct siu_port *port_info = snd_kcontrol_chip(kctrl);
357
358 dev_dbg(port_info->pcm->card->dev, "%s\n", __func__);
359
360 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
361 uinfo->count = 2;
362 uinfo->value.integer.min = 0;
363 uinfo->value.integer.max = SIU_MAX_VOLUME;
364
365 return 0;
366}
367
368static int siu_dai_get_volume(struct snd_kcontrol *kctrl,
369 struct snd_ctl_elem_value *ucontrol)
370{
371 struct siu_port *port_info = snd_kcontrol_chip(kctrl);
372 struct device *dev = port_info->pcm->card->dev;
373 u32 vol;
374
375 dev_dbg(dev, "%s\n", __func__);
376
377 switch (kctrl->private_value) {
378 case VOLUME_PLAYBACK:
379 /* Playback is always on port 0 */
380 vol = port_info->playback.volume;
381 ucontrol->value.integer.value[0] = vol & 0xffff;
382 ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
383 break;
384 case VOLUME_CAPTURE:
385 /* Capture is always on port 1 */
386 vol = port_info->capture.volume;
387 ucontrol->value.integer.value[0] = vol & 0xffff;
388 ucontrol->value.integer.value[1] = vol >> 16 & 0xffff;
389 break;
390 default:
391 dev_err(dev, "%s() invalid private_value=%ld\n",
392 __func__, kctrl->private_value);
393 return -EINVAL;
394 }
395
396 return 0;
397}
398
399static int siu_dai_put_volume(struct snd_kcontrol *kctrl,
400 struct snd_ctl_elem_value *ucontrol)
401{
402 struct siu_port *port_info = snd_kcontrol_chip(kctrl);
403 struct device *dev = port_info->pcm->card->dev;
404 struct siu_info *info = siu_i2s_dai.private_data;
405 u32 __iomem *base = info->reg;
406 u32 new_vol;
407 u32 cur_vol;
408
409 dev_dbg(dev, "%s\n", __func__);
410
411 if (ucontrol->value.integer.value[0] < 0 ||
412 ucontrol->value.integer.value[0] > SIU_MAX_VOLUME ||
413 ucontrol->value.integer.value[1] < 0 ||
414 ucontrol->value.integer.value[1] > SIU_MAX_VOLUME)
415 return -EINVAL;
416
417 new_vol = ucontrol->value.integer.value[0] |
418 ucontrol->value.integer.value[1] << 16;
419
420 /* See comment above - DSP firmware implementation */
421 switch (kctrl->private_value) {
422 case VOLUME_PLAYBACK:
423 /* Playback is always on port 0 */
424 cur_vol = port_info->playback.volume;
425 siu_write32(base + SIU_SBDVCA, new_vol);
426 port_info->playback.volume = new_vol;
427 break;
428 case VOLUME_CAPTURE:
429 /* Capture is always on port 1 */
430 cur_vol = port_info->capture.volume;
431 siu_write32(base + SIU_SBDVCB, new_vol);
432 port_info->capture.volume = new_vol;
433 break;
434 default:
435 dev_err(dev, "%s() invalid private_value=%ld\n",
436 __func__, kctrl->private_value);
437 return -EINVAL;
438 }
439
440 if (cur_vol != new_vol)
441 return 1;
442
443 return 0;
444}
445
446static struct snd_kcontrol_new playback_controls = {
447 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
448 .name = "PCM Playback Volume",
449 .index = 0,
450 .info = siu_dai_info_volume,
451 .get = siu_dai_get_volume,
452 .put = siu_dai_put_volume,
453 .private_value = VOLUME_PLAYBACK,
454};
455
456static struct snd_kcontrol_new capture_controls = {
457 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
458 .name = "PCM Capture Volume",
459 .index = 0,
460 .info = siu_dai_info_volume,
461 .get = siu_dai_get_volume,
462 .put = siu_dai_put_volume,
463 .private_value = VOLUME_CAPTURE,
464};
465
466int siu_init_port(int port, struct siu_port **port_info, struct snd_card *card)
467{
468 struct device *dev = card->dev;
469 struct snd_kcontrol *kctrl;
470 int ret;
471
472 *port_info = kzalloc(sizeof(**port_info), GFP_KERNEL);
473 if (!*port_info)
474 return -ENOMEM;
475
476 dev_dbg(dev, "%s: port #%d@%p\n", __func__, port, *port_info);
477
478 (*port_info)->playback.volume = DFLT_VOLUME_LEVEL;
479 (*port_info)->capture.volume = DFLT_VOLUME_LEVEL;
480
481 /*
482 * Add mixer support. The SPB is used to change the volume. Both
483 * ports use the same SPB. Therefore, we only register one
484 * control instance since it will be used by both channels.
485 * In error case we continue without controls.
486 */
487 kctrl = snd_ctl_new1(&playback_controls, *port_info);
488 ret = snd_ctl_add(card, kctrl);
489 if (ret < 0)
490 dev_err(dev,
491 "failed to add playback controls %p port=%d err=%d\n",
492 kctrl, port, ret);
493
494 kctrl = snd_ctl_new1(&capture_controls, *port_info);
495 ret = snd_ctl_add(card, kctrl);
496 if (ret < 0)
497 dev_err(dev,
498 "failed to add capture controls %p port=%d err=%d\n",
499 kctrl, port, ret);
500
501 return 0;
502}
503
504void siu_free_port(struct siu_port *port_info)
505{
506 kfree(port_info);
507}
508
509static int siu_dai_startup(struct snd_pcm_substream *substream,
510 struct snd_soc_dai *dai)
511{
512 struct siu_info *info = siu_i2s_dai.private_data;
513 struct snd_pcm_runtime *rt = substream->runtime;
514 struct siu_port *port_info = siu_port_info(substream);
515 int ret;
516
517 dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
518 info->port_id, port_info);
519
520 snd_soc_set_runtime_hwparams(substream, &siu_dai_pcm_hw);
521
522 ret = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
523 if (unlikely(ret < 0))
524 return ret;
525
526 siu_dai_start(port_info);
527
528 return 0;
529}
530
531static void siu_dai_shutdown(struct snd_pcm_substream *substream,
532 struct snd_soc_dai *dai)
533{
534 struct siu_info *info = siu_i2s_dai.private_data;
535 struct siu_port *port_info = siu_port_info(substream);
536
537 dev_dbg(substream->pcm->card->dev, "%s: port=%d@%p\n", __func__,
538 info->port_id, port_info);
539
540 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
541 port_info->play_cap &= ~PLAYBACK_ENABLED;
542 else
543 port_info->play_cap &= ~CAPTURE_ENABLED;
544
545 /* Stop the siu if the other stream is not using it */
546 if (!port_info->play_cap) {
547 /* during stmread or stmwrite ? */
548 BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
549 siu_dai_spbstop(port_info);
550 siu_dai_stop();
551 }
552}
553
554/* PCM part of siu_dai_playback_prepare() / siu_dai_capture_prepare() */
555static int siu_dai_prepare(struct snd_pcm_substream *substream,
556 struct snd_soc_dai *dai)
557{
558 struct siu_info *info = siu_i2s_dai.private_data;
559 struct snd_pcm_runtime *rt = substream->runtime;
560 struct siu_port *port_info = siu_port_info(substream);
561 struct siu_stream *siu_stream;
562 int self, ret;
563
564 dev_dbg(substream->pcm->card->dev,
565 "%s: port %d, active streams %lx, %d channels\n",
566 __func__, info->port_id, port_info->play_cap, rt->channels);
567
568 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
569 self = PLAYBACK_ENABLED;
570 siu_stream = &port_info->playback;
571 } else {
572 self = CAPTURE_ENABLED;
573 siu_stream = &port_info->capture;
574 }
575
576 /* Set up the siu if not already done */
577 if (!port_info->play_cap) {
578 siu_stream->rw_flg = 0; /* stream-data transfer flag */
579
580 siu_dai_spbAselect(port_info);
581 siu_dai_spbBselect(port_info);
582
583 siu_dai_open(siu_stream);
584
585 siu_dai_pcmdatapack(siu_stream);
586
587 ret = siu_dai_spbstart(port_info);
588 if (ret < 0)
589 goto fail;
590 }
591
592 port_info->play_cap |= self;
593
594fail:
595 return ret;
596}
597
598/*
599 * SIU can set bus format to I2S / PCM / SPDIF independently for playback and
600 * capture, however, the current API sets the bus format globally for a DAI.
601 */
602static int siu_dai_set_fmt(struct snd_soc_dai *dai,
603 unsigned int fmt)
604{
605 struct siu_info *info = siu_i2s_dai.private_data;
606 u32 __iomem *base = info->reg;
607 u32 ifctl;
608
609 dev_dbg(dai->dev, "%s: fmt 0x%x on port %d\n",
610 __func__, fmt, info->port_id);
611
612 if (info->port_id < 0)
613 return -ENODEV;
614
615 /* Here select between I2S / PCM / SPDIF */
616 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
617 case SND_SOC_DAIFMT_I2S:
618 ifctl = siu_flags[info->port_id].playback.i2s |
619 siu_flags[info->port_id].capture.i2s;
620 break;
621 case SND_SOC_DAIFMT_LEFT_J:
622 ifctl = siu_flags[info->port_id].playback.pcm |
623 siu_flags[info->port_id].capture.pcm;
624 break;
625 /* SPDIF disabled - see comment at the top */
626 default:
627 return -EINVAL;
628 }
629
630 ifctl |= ~(siu_flags[info->port_id].playback.mask |
631 siu_flags[info->port_id].capture.mask) &
632 siu_read32(base + SIU_IFCTL);
633 siu_write32(base + SIU_IFCTL, ifctl);
634
635 return 0;
636}
637
638static int siu_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
639 unsigned int freq, int dir)
640{
641 struct clk *siu_clk, *parent_clk;
642 char *siu_name, *parent_name;
643 int ret;
644
645 if (dir != SND_SOC_CLOCK_IN)
646 return -EINVAL;
647
648 dev_dbg(dai->dev, "%s: using clock %d\n", __func__, clk_id);
649
650 switch (clk_id) {
651 case SIU_CLKA_PLL:
652 siu_name = "siua_clk";
653 parent_name = "pll_clk";
654 break;
655 case SIU_CLKA_EXT:
656 siu_name = "siua_clk";
657 parent_name = "siumcka_clk";
658 break;
659 case SIU_CLKB_PLL:
660 siu_name = "siub_clk";
661 parent_name = "pll_clk";
662 break;
663 case SIU_CLKB_EXT:
664 siu_name = "siub_clk";
665 parent_name = "siumckb_clk";
666 break;
667 default:
668 return -EINVAL;
669 }
670
671 siu_clk = clk_get(siu_i2s_dai.dev, siu_name);
672 if (IS_ERR(siu_clk))
673 return PTR_ERR(siu_clk);
674
675 parent_clk = clk_get(siu_i2s_dai.dev, parent_name);
676 if (!IS_ERR(parent_clk)) {
677 ret = clk_set_parent(siu_clk, parent_clk);
678 if (!ret)
679 clk_set_rate(siu_clk, freq);
680 clk_put(parent_clk);
681 }
682
683 clk_put(siu_clk);
684
685 return 0;
686}
687
688static struct snd_soc_dai_ops siu_dai_ops = {
689 .startup = siu_dai_startup,
690 .shutdown = siu_dai_shutdown,
691 .prepare = siu_dai_prepare,
692 .set_sysclk = siu_dai_set_sysclk,
693 .set_fmt = siu_dai_set_fmt,
694};
695
696struct snd_soc_dai siu_i2s_dai = {
697 .name = "sh-siu",
698 .id = 0,
699 .playback = {
700 .channels_min = 2,
701 .channels_max = 2,
702 .formats = SNDRV_PCM_FMTBIT_S16,
703 .rates = SNDRV_PCM_RATE_8000_48000,
704 },
705 .capture = {
706 .channels_min = 2,
707 .channels_max = 2,
708 .formats = SNDRV_PCM_FMTBIT_S16,
709 .rates = SNDRV_PCM_RATE_8000_48000,
710 },
711 .ops = &siu_dai_ops,
712};
713EXPORT_SYMBOL_GPL(siu_i2s_dai);
714
715static int __devinit siu_probe(struct platform_device *pdev)
716{
717 const struct firmware *fw_entry;
718 struct resource *res, *region;
719 struct siu_info *info;
720 int ret;
721
722 info = kmalloc(sizeof(*info), GFP_KERNEL);
723 if (!info)
724 return -ENOMEM;
725
726 ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
727 if (ret)
728 goto ereqfw;
729
730 /*
731 * Loaded firmware is "const" - read only, but we have to modify it in
732 * snd_siu_sh7343_spbAselect() and snd_siu_sh7343_spbBselect()
733 */
734 memcpy(&info->fw, fw_entry->data, fw_entry->size);
735
736 release_firmware(fw_entry);
737
738 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
739 if (!res) {
740 ret = -ENODEV;
741 goto egetres;
742 }
743
744 region = request_mem_region(res->start, resource_size(res),
745 pdev->name);
746 if (!region) {
747 dev_err(&pdev->dev, "SIU region already claimed\n");
748 ret = -EBUSY;
749 goto ereqmemreg;
750 }
751
752 ret = -ENOMEM;
753 info->pram = ioremap(res->start, PRAM_SIZE);
754 if (!info->pram)
755 goto emappram;
756 info->xram = ioremap(res->start + XRAM_OFFSET, XRAM_SIZE);
757 if (!info->xram)
758 goto emapxram;
759 info->yram = ioremap(res->start + YRAM_OFFSET, YRAM_SIZE);
760 if (!info->yram)
761 goto emapyram;
762 info->reg = ioremap(res->start + REG_OFFSET, resource_size(res) -
763 REG_OFFSET);
764 if (!info->reg)
765 goto emapreg;
766
767 siu_i2s_dai.dev = &pdev->dev;
768 siu_i2s_dai.private_data = info;
769
770 ret = snd_soc_register_dais(&siu_i2s_dai, 1);
771 if (ret < 0)
772 goto edaiinit;
773
774 ret = snd_soc_register_platform(&siu_platform);
775 if (ret < 0)
776 goto esocregp;
777
778 pm_runtime_enable(&pdev->dev);
779
780 return ret;
781
782esocregp:
783 snd_soc_unregister_dais(&siu_i2s_dai, 1);
784edaiinit:
785 iounmap(info->reg);
786emapreg:
787 iounmap(info->yram);
788emapyram:
789 iounmap(info->xram);
790emapxram:
791 iounmap(info->pram);
792emappram:
793 release_mem_region(res->start, resource_size(res));
794ereqmemreg:
795egetres:
796ereqfw:
797 kfree(info);
798
799 return ret;
800}
801
802static int __devexit siu_remove(struct platform_device *pdev)
803{
804 struct siu_info *info = siu_i2s_dai.private_data;
805 struct resource *res;
806
807 pm_runtime_disable(&pdev->dev);
808
809 snd_soc_unregister_platform(&siu_platform);
810 snd_soc_unregister_dais(&siu_i2s_dai, 1);
811
812 iounmap(info->reg);
813 iounmap(info->yram);
814 iounmap(info->xram);
815 iounmap(info->pram);
816 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
817 if (res)
818 release_mem_region(res->start, resource_size(res));
819 kfree(info);
820
821 return 0;
822}
823
824static struct platform_driver siu_driver = {
825 .driver = {
826 .name = "sh_siu",
827 },
828 .probe = siu_probe,
829 .remove = __devexit_p(siu_remove),
830};
831
832static int __init siu_init(void)
833{
834 return platform_driver_register(&siu_driver);
835}
836
837static void __exit siu_exit(void)
838{
839 platform_driver_unregister(&siu_driver);
840}
841
842module_init(siu_init)
843module_exit(siu_exit)
844
845MODULE_AUTHOR("Carlos Munoz <carlos@kenati.com>");
846MODULE_DESCRIPTION("ALSA SoC SH7722 SIU driver");
847MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
new file mode 100644
index 00000000000..c5efc30f013
--- /dev/null
+++ b/sound/soc/sh/siu_pcm.c
@@ -0,0 +1,616 @@
1/*
2 * siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
3 *
4 * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5 * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
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 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21#include <linux/delay.h>
22#include <linux/dma-mapping.h>
23#include <linux/dmaengine.h>
24#include <linux/interrupt.h>
25#include <linux/module.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28
29#include <sound/control.h>
30#include <sound/core.h>
31#include <sound/pcm.h>
32#include <sound/pcm_params.h>
33#include <sound/soc-dai.h>
34
35#include <asm/dma-sh.h>
36#include <asm/siu.h>
37
38#include "siu.h"
39
40#define GET_MAX_PERIODS(buf_bytes, period_bytes) \
41 ((buf_bytes) / (period_bytes))
42#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
43 ((buf_addr) + ((period_num) * (period_bytes)))
44
45#define RWF_STM_RD 0x01 /* Read in progress */
46#define RWF_STM_WT 0x02 /* Write in progress */
47
48struct siu_port *siu_ports[SIU_PORT_NUM];
49
50/* transfersize is number of u32 dma transfers per period */
51static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
52{
53 struct siu_info *info = siu_i2s_dai.private_data;
54 u32 __iomem *base = info->reg;
55 struct siu_stream *siu_stream = &port_info->playback;
56 u32 stfifo;
57
58 if (!siu_stream->rw_flg)
59 return -EPERM;
60
61 /* output FIFO disable */
62 stfifo = siu_read32(base + SIU_STFIFO);
63 siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18);
64 pr_debug("%s: STFIFO %x -> %x\n", __func__,
65 stfifo, stfifo & ~0x0c180c18);
66
67 /* during stmwrite clear */
68 siu_stream->rw_flg = 0;
69
70 return 0;
71}
72
73static int siu_pcm_stmwrite_start(struct siu_port *port_info)
74{
75 struct siu_stream *siu_stream = &port_info->playback;
76
77 if (siu_stream->rw_flg)
78 return -EPERM;
79
80 /* Current period in buffer */
81 port_info->playback.cur_period = 0;
82
83 /* during stmwrite flag set */
84 siu_stream->rw_flg = RWF_STM_WT;
85
86 /* DMA transfer start */
87 tasklet_schedule(&siu_stream->tasklet);
88
89 return 0;
90}
91
92static void siu_dma_tx_complete(void *arg)
93{
94 struct siu_stream *siu_stream = arg;
95
96 if (!siu_stream->rw_flg)
97 return;
98
99 /* Update completed period count */
100 if (++siu_stream->cur_period >=
101 GET_MAX_PERIODS(siu_stream->buf_bytes,
102 siu_stream->period_bytes))
103 siu_stream->cur_period = 0;
104
105 pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n",
106 __func__, siu_stream->cur_period,
107 siu_stream->cur_period * siu_stream->period_bytes,
108 siu_stream->buf_bytes, siu_stream->cookie);
109
110 tasklet_schedule(&siu_stream->tasklet);
111
112 /* Notify alsa: a period is done */
113 snd_pcm_period_elapsed(siu_stream->substream);
114}
115
116static int siu_pcm_wr_set(struct siu_port *port_info,
117 dma_addr_t buff, u32 size)
118{
119 struct siu_info *info = siu_i2s_dai.private_data;
120 u32 __iomem *base = info->reg;
121 struct siu_stream *siu_stream = &port_info->playback;
122 struct snd_pcm_substream *substream = siu_stream->substream;
123 struct device *dev = substream->pcm->card->dev;
124 struct dma_async_tx_descriptor *desc;
125 dma_cookie_t cookie;
126 struct scatterlist sg;
127 u32 stfifo;
128
129 sg_init_table(&sg, 1);
130 sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
131 size, offset_in_page(buff));
132 sg_dma_address(&sg) = buff;
133
134 desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
135 &sg, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
136 if (!desc) {
137 dev_err(dev, "Failed to allocate a dma descriptor\n");
138 return -ENOMEM;
139 }
140
141 desc->callback = siu_dma_tx_complete;
142 desc->callback_param = siu_stream;
143 cookie = desc->tx_submit(desc);
144 if (cookie < 0) {
145 dev_err(dev, "Failed to submit a dma transfer\n");
146 return cookie;
147 }
148
149 siu_stream->tx_desc = desc;
150 siu_stream->cookie = cookie;
151
152 dma_async_issue_pending(siu_stream->chan);
153
154 /* only output FIFO enable */
155 stfifo = siu_read32(base + SIU_STFIFO);
156 siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18));
157 dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
158 stfifo, stfifo | (port_info->stfifo & 0x0c180c18));
159
160 return 0;
161}
162
163static int siu_pcm_rd_set(struct siu_port *port_info,
164 dma_addr_t buff, size_t size)
165{
166 struct siu_info *info = siu_i2s_dai.private_data;
167 u32 __iomem *base = info->reg;
168 struct siu_stream *siu_stream = &port_info->capture;
169 struct snd_pcm_substream *substream = siu_stream->substream;
170 struct device *dev = substream->pcm->card->dev;
171 struct dma_async_tx_descriptor *desc;
172 dma_cookie_t cookie;
173 struct scatterlist sg;
174 u32 stfifo;
175
176 dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff);
177
178 sg_init_table(&sg, 1);
179 sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
180 size, offset_in_page(buff));
181 sg_dma_address(&sg) = buff;
182
183 desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
184 &sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
185 if (!desc) {
186 dev_err(dev, "Failed to allocate dma descriptor\n");
187 return -ENOMEM;
188 }
189
190 desc->callback = siu_dma_tx_complete;
191 desc->callback_param = siu_stream;
192 cookie = desc->tx_submit(desc);
193 if (cookie < 0) {
194 dev_err(dev, "Failed to submit dma descriptor\n");
195 return cookie;
196 }
197
198 siu_stream->tx_desc = desc;
199 siu_stream->cookie = cookie;
200
201 dma_async_issue_pending(siu_stream->chan);
202
203 /* only input FIFO enable */
204 stfifo = siu_read32(base + SIU_STFIFO);
205 siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) |
206 (port_info->stfifo & 0x13071307));
207 dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
208 stfifo, stfifo | (port_info->stfifo & 0x13071307));
209
210 return 0;
211}
212
213static void siu_io_tasklet(unsigned long data)
214{
215 struct siu_stream *siu_stream = (struct siu_stream *)data;
216 struct snd_pcm_substream *substream = siu_stream->substream;
217 struct device *dev = substream->pcm->card->dev;
218 struct snd_pcm_runtime *rt = substream->runtime;
219 struct siu_port *port_info = siu_port_info(substream);
220
221 dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg);
222
223 if (!siu_stream->rw_flg) {
224 dev_dbg(dev, "%s: stream inactive\n", __func__);
225 return;
226 }
227
228 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
229 dma_addr_t buff;
230 size_t count;
231 u8 *virt;
232
233 buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
234 siu_stream->cur_period,
235 siu_stream->period_bytes);
236 virt = PERIOD_OFFSET(rt->dma_area,
237 siu_stream->cur_period,
238 siu_stream->period_bytes);
239 count = siu_stream->period_bytes;
240
241 /* DMA transfer start */
242 siu_pcm_rd_set(port_info, buff, count);
243 } else {
244 siu_pcm_wr_set(port_info,
245 (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
246 siu_stream->cur_period,
247 siu_stream->period_bytes),
248 siu_stream->period_bytes);
249 }
250}
251
252/* Capture */
253static int siu_pcm_stmread_start(struct siu_port *port_info)
254{
255 struct siu_stream *siu_stream = &port_info->capture;
256
257 if (siu_stream->xfer_cnt > 0x1000000)
258 return -EINVAL;
259 if (siu_stream->rw_flg)
260 return -EPERM;
261
262 /* Current period in buffer */
263 siu_stream->cur_period = 0;
264
265 /* during stmread flag set */
266 siu_stream->rw_flg = RWF_STM_RD;
267
268 tasklet_schedule(&siu_stream->tasklet);
269
270 return 0;
271}
272
273static int siu_pcm_stmread_stop(struct siu_port *port_info)
274{
275 struct siu_info *info = siu_i2s_dai.private_data;
276 u32 __iomem *base = info->reg;
277 struct siu_stream *siu_stream = &port_info->capture;
278 struct device *dev = siu_stream->substream->pcm->card->dev;
279 u32 stfifo;
280
281 if (!siu_stream->rw_flg)
282 return -EPERM;
283
284 /* input FIFO disable */
285 stfifo = siu_read32(base + SIU_STFIFO);
286 siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
287 dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
288 stfifo, stfifo & ~0x13071307);
289
290 /* during stmread flag clear */
291 siu_stream->rw_flg = 0;
292
293 return 0;
294}
295
296static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
297 struct snd_pcm_hw_params *hw_params)
298{
299 struct siu_info *info = siu_i2s_dai.private_data;
300 struct device *dev = ss->pcm->card->dev;
301 int ret;
302
303 dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
304
305 ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
306 if (ret < 0)
307 dev_err(dev, "snd_pcm_lib_malloc_pages() failed\n");
308
309 return ret;
310}
311
312static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
313{
314 struct siu_info *info = siu_i2s_dai.private_data;
315 struct siu_port *port_info = siu_port_info(ss);
316 struct device *dev = ss->pcm->card->dev;
317 struct siu_stream *siu_stream;
318
319 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
320 siu_stream = &port_info->playback;
321 else
322 siu_stream = &port_info->capture;
323
324 dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
325
326 return snd_pcm_lib_free_pages(ss);
327}
328
329static bool filter(struct dma_chan *chan, void *slave)
330{
331 struct sh_dmae_slave *param = slave;
332
333 pr_debug("%s: slave ID %d\n", __func__, param->slave_id);
334
335 if (unlikely(param->dma_dev != chan->device->dev))
336 return false;
337
338 chan->private = param;
339 return true;
340}
341
342static int siu_pcm_open(struct snd_pcm_substream *ss)
343{
344 /* Playback / Capture */
345 struct siu_info *info = siu_i2s_dai.private_data;
346 struct siu_port *port_info = siu_port_info(ss);
347 struct siu_stream *siu_stream;
348 u32 port = info->port_id;
349 struct siu_platform *pdata = siu_i2s_dai.dev->platform_data;
350 struct device *dev = ss->pcm->card->dev;
351 dma_cap_mask_t mask;
352 struct sh_dmae_slave *param;
353
354 dma_cap_zero(mask);
355 dma_cap_set(DMA_SLAVE, mask);
356
357 dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info);
358
359 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
360 siu_stream = &port_info->playback;
361 param = &siu_stream->param;
362 param->slave_id = port ? SHDMA_SLAVE_SIUB_TX :
363 SHDMA_SLAVE_SIUA_TX;
364 } else {
365 siu_stream = &port_info->capture;
366 param = &siu_stream->param;
367 param->slave_id = port ? SHDMA_SLAVE_SIUB_RX :
368 SHDMA_SLAVE_SIUA_RX;
369 }
370
371 param->dma_dev = pdata->dma_dev;
372 /* Get DMA channel */
373 siu_stream->chan = dma_request_channel(mask, filter, param);
374 if (!siu_stream->chan) {
375 dev_err(dev, "DMA channel allocation failed!\n");
376 return -EBUSY;
377 }
378
379 siu_stream->substream = ss;
380
381 return 0;
382}
383
384static int siu_pcm_close(struct snd_pcm_substream *ss)
385{
386 struct siu_info *info = siu_i2s_dai.private_data;
387 struct device *dev = ss->pcm->card->dev;
388 struct siu_port *port_info = siu_port_info(ss);
389 struct siu_stream *siu_stream;
390
391 dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
392
393 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
394 siu_stream = &port_info->playback;
395 else
396 siu_stream = &port_info->capture;
397
398 dma_release_channel(siu_stream->chan);
399 siu_stream->chan = NULL;
400
401 siu_stream->substream = NULL;
402
403 return 0;
404}
405
406static int siu_pcm_prepare(struct snd_pcm_substream *ss)
407{
408 struct siu_info *info = siu_i2s_dai.private_data;
409 struct siu_port *port_info = siu_port_info(ss);
410 struct device *dev = ss->pcm->card->dev;
411 struct snd_pcm_runtime *rt = ss->runtime;
412 struct siu_stream *siu_stream;
413 snd_pcm_sframes_t xfer_cnt;
414
415 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
416 siu_stream = &port_info->playback;
417 else
418 siu_stream = &port_info->capture;
419
420 rt = siu_stream->substream->runtime;
421
422 siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
423 siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
424
425 dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__,
426 info->port_id, rt->channels, siu_stream->period_bytes);
427
428 /* We only support buffers that are multiples of the period */
429 if (siu_stream->buf_bytes % siu_stream->period_bytes) {
430 dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n",
431 __func__, siu_stream->buf_bytes,
432 siu_stream->period_bytes);
433 return -EINVAL;
434 }
435
436 xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
437 if (!xfer_cnt || xfer_cnt > 0x1000000)
438 return -EINVAL;
439
440 siu_stream->format = rt->format;
441 siu_stream->xfer_cnt = xfer_cnt;
442
443 dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d "
444 "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
445 (unsigned long)rt->dma_addr, siu_stream->buf_bytes,
446 siu_stream->period_bytes,
447 siu_stream->format, rt->channels, (int)xfer_cnt);
448
449 return 0;
450}
451
452static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
453{
454 struct siu_info *info = siu_i2s_dai.private_data;
455 struct device *dev = ss->pcm->card->dev;
456 struct siu_port *port_info = siu_port_info(ss);
457 int ret;
458
459 dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__,
460 info->port_id, port_info, cmd);
461
462 switch (cmd) {
463 case SNDRV_PCM_TRIGGER_START:
464 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
465 ret = siu_pcm_stmwrite_start(port_info);
466 else
467 ret = siu_pcm_stmread_start(port_info);
468
469 if (ret < 0)
470 dev_warn(dev, "%s: start failed on port=%d\n",
471 __func__, info->port_id);
472
473 break;
474 case SNDRV_PCM_TRIGGER_STOP:
475 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
476 siu_pcm_stmwrite_stop(port_info);
477 else
478 siu_pcm_stmread_stop(port_info);
479 ret = 0;
480
481 break;
482 default:
483 dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd);
484 ret = -EINVAL;
485 }
486
487 return ret;
488}
489
490/*
491 * So far only resolution of one period is supported, subject to extending the
492 * dmangine API
493 */
494static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
495{
496 struct device *dev = ss->pcm->card->dev;
497 struct siu_info *info = siu_i2s_dai.private_data;
498 u32 __iomem *base = info->reg;
499 struct siu_port *port_info = siu_port_info(ss);
500 struct snd_pcm_runtime *rt = ss->runtime;
501 size_t ptr;
502 struct siu_stream *siu_stream;
503
504 if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
505 siu_stream = &port_info->playback;
506 else
507 siu_stream = &port_info->capture;
508
509 /*
510 * ptr is the offset into the buffer where the dma is currently at. We
511 * check if the dma buffer has just wrapped.
512 */
513 ptr = PERIOD_OFFSET(rt->dma_addr,
514 siu_stream->cur_period,
515 siu_stream->period_bytes) - rt->dma_addr;
516
517 dev_dbg(dev,
518 "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
519 __func__, info->port_id, siu_read32(base + SIU_EVNTC),
520 siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
521 siu_stream->cookie);
522
523 if (ptr >= siu_stream->buf_bytes)
524 ptr = 0;
525
526 return bytes_to_frames(ss->runtime, ptr);
527}
528
529static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
530 struct snd_pcm *pcm)
531{
532 /* card->dev == socdev->dev, see snd_soc_new_pcms() */
533 struct siu_info *info = siu_i2s_dai.private_data;
534 struct platform_device *pdev = to_platform_device(card->dev);
535 int ret;
536 int i;
537
538 /* pdev->id selects between SIUA and SIUB */
539 if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM)
540 return -EINVAL;
541
542 info->port_id = pdev->id;
543
544 /*
545 * While the siu has 2 ports, only one port can be on at a time (only 1
546 * SPB). So far all the boards using the siu had only one of the ports
547 * wired to a codec. To simplify things, we only register one port with
548 * alsa. In case both ports are needed, it should be changed here
549 */
550 for (i = pdev->id; i < pdev->id + 1; i++) {
551 struct siu_port **port_info = &siu_ports[i];
552
553 ret = siu_init_port(i, port_info, card);
554 if (ret < 0)
555 return ret;
556
557 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
558 SNDRV_DMA_TYPE_DEV, NULL,
559 SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
560 if (ret < 0) {
561 dev_err(card->dev,
562 "snd_pcm_lib_preallocate_pages_for_all() err=%d",
563 ret);
564 goto fail;
565 }
566
567 (*port_info)->pcm = pcm;
568
569 /* IO tasklets */
570 tasklet_init(&(*port_info)->playback.tasklet, siu_io_tasklet,
571 (unsigned long)&(*port_info)->playback);
572 tasklet_init(&(*port_info)->capture.tasklet, siu_io_tasklet,
573 (unsigned long)&(*port_info)->capture);
574 }
575
576 dev_info(card->dev, "SuperH SIU driver initialized.\n");
577 return 0;
578
579fail:
580 siu_free_port(siu_ports[pdev->id]);
581 dev_err(card->dev, "SIU: failed to initialize.\n");
582 return ret;
583}
584
585static void siu_pcm_free(struct snd_pcm *pcm)
586{
587 struct platform_device *pdev = to_platform_device(pcm->card->dev);
588 struct siu_port *port_info = siu_ports[pdev->id];
589
590 tasklet_kill(&port_info->capture.tasklet);
591 tasklet_kill(&port_info->playback.tasklet);
592
593 siu_free_port(port_info);
594 snd_pcm_lib_preallocate_free_for_all(pcm);
595
596 dev_dbg(pcm->card->dev, "%s\n", __func__);
597}
598
599static struct snd_pcm_ops siu_pcm_ops = {
600 .open = siu_pcm_open,
601 .close = siu_pcm_close,
602 .ioctl = snd_pcm_lib_ioctl,
603 .hw_params = siu_pcm_hw_params,
604 .hw_free = siu_pcm_hw_free,
605 .prepare = siu_pcm_prepare,
606 .trigger = siu_pcm_trigger,
607 .pointer = siu_pcm_pointer_dma,
608};
609
610struct snd_soc_platform siu_platform = {
611 .name = "siu-audio",
612 .pcm_ops = &siu_pcm_ops,
613 .pcm_new = siu_pcm_new,
614 .pcm_free = siu_pcm_free,
615};
616EXPORT_SYMBOL_GPL(siu_platform);
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index d2505e8b06c..02c235711bb 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -182,7 +182,7 @@ static struct {
182 { 182 {
183 .addr_bits = 7, .data_bits = 9, 183 .addr_bits = 7, .data_bits = 9,
184 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, 184 .write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
185 .spi_write = snd_soc_7_9_spi_write 185 .spi_write = snd_soc_7_9_spi_write,
186 }, 186 },
187 { 187 {
188 .addr_bits = 8, .data_bits = 8, 188 .addr_bits = 8, .data_bits = 8,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 0a6440c6f54..9085b40fa04 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1276,8 +1276,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
1276 codec_dai->codec = card->codec; 1276 codec_dai->codec = card->codec;
1277 1277
1278 /* check client and interface hw capabilities */ 1278 /* check client and interface hw capabilities */
1279 sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, 1279 snprintf(new_name, sizeof(new_name), "%s %s-%d",
1280 num); 1280 dai_link->stream_name, codec_dai->name, num);
1281 1281
1282 if (codec_dai->playback.channels_min) 1282 if (codec_dai->playback.channels_min)
1283 playback = 1; 1283 playback = 1;
@@ -1427,9 +1427,9 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits);
1427 * 1427 *
1428 * Returns 1 for change else 0. 1428 * Returns 1 for change else 0.
1429 */ 1429 */
1430static int snd_soc_update_bits_locked(struct snd_soc_codec *codec, 1430int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
1431 unsigned short reg, unsigned int mask, 1431 unsigned short reg, unsigned int mask,
1432 unsigned int value) 1432 unsigned int value)
1433{ 1433{
1434 int change; 1434 int change;
1435 1435
@@ -1439,6 +1439,7 @@ static int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
1439 1439
1440 return change; 1440 return change;
1441} 1441}
1442EXPORT_SYMBOL_GPL(snd_soc_update_bits_locked);
1442 1443
1443/** 1444/**
1444 * snd_soc_test_bits - test register for change 1445 * snd_soc_test_bits - test register for change
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 0d294ef7259..6c335109578 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -44,13 +44,6 @@
44#include <sound/soc-dapm.h> 44#include <sound/soc-dapm.h>
45#include <sound/initval.h> 45#include <sound/initval.h>
46 46
47/* debug */
48#ifdef DEBUG
49#define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
50#else
51#define dump_dapm(codec, action)
52#endif
53
54/* dapm power sequences - make this per codec in the future */ 47/* dapm power sequences - make this per codec in the future */
55static int dapm_up_seq[] = { 48static int dapm_up_seq[] = {
56 [snd_soc_dapm_pre] = 0, 49 [snd_soc_dapm_pre] = 0,
@@ -739,6 +732,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
739 struct snd_soc_dapm_widget *b, 732 struct snd_soc_dapm_widget *b,
740 int sort[]) 733 int sort[])
741{ 734{
735 if (a->codec != b->codec)
736 return (unsigned long)a - (unsigned long)b;
742 if (sort[a->id] != sort[b->id]) 737 if (sort[a->id] != sort[b->id])
743 return sort[a->id] - sort[b->id]; 738 return sort[a->id] - sort[b->id];
744 if (a->reg != b->reg) 739 if (a->reg != b->reg)
@@ -1017,13 +1012,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
1017 sys_power = 0; 1012 sys_power = 0;
1018 break; 1013 break;
1019 case SND_SOC_DAPM_STREAM_NOP: 1014 case SND_SOC_DAPM_STREAM_NOP:
1020 sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; 1015 switch (codec->bias_level) {
1016 case SND_SOC_BIAS_STANDBY:
1017 case SND_SOC_BIAS_OFF:
1018 sys_power = 0;
1019 break;
1020 default:
1021 sys_power = 1;
1022 break;
1023 }
1021 break; 1024 break;
1022 default: 1025 default:
1023 break; 1026 break;
1024 } 1027 }
1025 } 1028 }
1026 1029
1030 if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
1031 ret = snd_soc_dapm_set_bias_level(socdev,
1032 SND_SOC_BIAS_STANDBY);
1033 if (ret != 0)
1034 pr_err("Failed to turn on bias: %d\n", ret);
1035 }
1036
1027 /* If we're changing to all on or all off then prepare */ 1037 /* If we're changing to all on or all off then prepare */
1028 if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || 1038 if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
1029 (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { 1039 (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
@@ -1047,6 +1057,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
1047 pr_err("Failed to apply standby bias: %d\n", ret); 1057 pr_err("Failed to apply standby bias: %d\n", ret);
1048 } 1058 }
1049 1059
1060 /* If we're in standby and can support bias off then do that */
1061 if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
1062 codec->idle_bias_off) {
1063 ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
1064 if (ret != 0)
1065 pr_err("Failed to turn off bias: %d\n", ret);
1066 }
1067
1050 /* If we just powered up then move to active bias */ 1068 /* If we just powered up then move to active bias */
1051 if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { 1069 if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
1052 ret = snd_soc_dapm_set_bias_level(socdev, 1070 ret = snd_soc_dapm_set_bias_level(socdev,
@@ -1061,66 +1079,6 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
1061 return 0; 1079 return 0;
1062} 1080}
1063 1081
1064#ifdef DEBUG
1065static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
1066{
1067 struct snd_soc_dapm_widget *w;
1068 struct snd_soc_dapm_path *p = NULL;
1069 int in, out;
1070
1071 printk("DAPM %s %s\n", codec->name, action);
1072
1073 list_for_each_entry(w, &codec->dapm_widgets, list) {
1074
1075 /* only display widgets that effect routing */
1076 switch (w->id) {
1077 case snd_soc_dapm_pre:
1078 case snd_soc_dapm_post:
1079 case snd_soc_dapm_vmid:
1080 continue;
1081 case snd_soc_dapm_mux:
1082 case snd_soc_dapm_value_mux:
1083 case snd_soc_dapm_output:
1084 case snd_soc_dapm_input:
1085 case snd_soc_dapm_switch:
1086 case snd_soc_dapm_hp:
1087 case snd_soc_dapm_mic:
1088 case snd_soc_dapm_spk:
1089 case snd_soc_dapm_line:
1090 case snd_soc_dapm_micbias:
1091 case snd_soc_dapm_dac:
1092 case snd_soc_dapm_adc:
1093 case snd_soc_dapm_pga:
1094 case snd_soc_dapm_mixer:
1095 case snd_soc_dapm_mixer_named_ctl:
1096 case snd_soc_dapm_supply:
1097 case snd_soc_dapm_aif_in:
1098 case snd_soc_dapm_aif_out:
1099 if (w->name) {
1100 in = is_connected_input_ep(w);
1101 dapm_clear_walk(w->codec);
1102 out = is_connected_output_ep(w);
1103 dapm_clear_walk(w->codec);
1104 printk("%s: %s in %d out %d\n", w->name,
1105 w->power ? "On":"Off",in, out);
1106
1107 list_for_each_entry(p, &w->sources, list_sink) {
1108 if (p->connect)
1109 printk(" in %s %s\n", p->name ? p->name : "static",
1110 p->source->name);
1111 }
1112 list_for_each_entry(p, &w->sinks, list_source) {
1113 if (p->connect)
1114 printk(" out %s %s\n", p->name ? p->name : "static",
1115 p->sink->name);
1116 }
1117 }
1118 break;
1119 }
1120 }
1121}
1122#endif
1123
1124#ifdef CONFIG_DEBUG_FS 1082#ifdef CONFIG_DEBUG_FS
1125static int dapm_widget_power_open_file(struct inode *inode, struct file *file) 1083static int dapm_widget_power_open_file(struct inode *inode, struct file *file)
1126{ 1084{
@@ -1147,9 +1105,16 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
1147 out = is_connected_output_ep(w); 1105 out = is_connected_output_ep(w);
1148 dapm_clear_walk(w->codec); 1106 dapm_clear_walk(w->codec);
1149 1107
1150 ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n", 1108 ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d",
1151 w->name, w->power ? "On" : "Off", in, out); 1109 w->name, w->power ? "On" : "Off", in, out);
1152 1110
1111 if (w->reg >= 0)
1112 ret += snprintf(buf + ret, PAGE_SIZE - ret,
1113 " - R%d(0x%x) bit %d",
1114 w->reg, w->reg, w->shift);
1115
1116 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1117
1153 if (w->sname) 1118 if (w->sname)
1154 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", 1119 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1155 w->sname, 1120 w->sname,
@@ -1245,18 +1210,15 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1245 path->connect = 0; /* old connection must be powered down */ 1210 path->connect = 0; /* old connection must be powered down */
1246 } 1211 }
1247 1212
1248 if (found) { 1213 if (found)
1249 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); 1214 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
1250 dump_dapm(widget->codec, "mux power update");
1251 }
1252 1215
1253 return 0; 1216 return 0;
1254} 1217}
1255 1218
1256/* test and update the power status of a mixer or switch widget */ 1219/* test and update the power status of a mixer or switch widget */
1257static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 1220static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1258 struct snd_kcontrol *kcontrol, int reg, 1221 struct snd_kcontrol *kcontrol, int connect)
1259 int val_mask, int val, int invert)
1260{ 1222{
1261 struct snd_soc_dapm_path *path; 1223 struct snd_soc_dapm_path *path;
1262 int found = 0; 1224 int found = 0;
@@ -1266,9 +1228,6 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1266 widget->id != snd_soc_dapm_switch) 1228 widget->id != snd_soc_dapm_switch)
1267 return -ENODEV; 1229 return -ENODEV;
1268 1230
1269 if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
1270 return 0;
1271
1272 /* find dapm widget path assoc with kcontrol */ 1231 /* find dapm widget path assoc with kcontrol */
1273 list_for_each_entry(path, &widget->codec->dapm_paths, list) { 1232 list_for_each_entry(path, &widget->codec->dapm_paths, list) {
1274 if (path->kcontrol != kcontrol) 1233 if (path->kcontrol != kcontrol)
@@ -1276,19 +1235,12 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1276 1235
1277 /* found, now check type */ 1236 /* found, now check type */
1278 found = 1; 1237 found = 1;
1279 if (val) 1238 path->connect = connect;
1280 /* new connection */
1281 path->connect = invert ? 0:1;
1282 else
1283 /* old connection must be powered down */
1284 path->connect = invert ? 1:0;
1285 break; 1239 break;
1286 } 1240 }
1287 1241
1288 if (found) { 1242 if (found)
1289 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); 1243 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
1290 dump_dapm(widget->codec, "mixer power update");
1291 }
1292 1244
1293 return 0; 1245 return 0;
1294} 1246}
@@ -1404,9 +1356,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
1404 */ 1356 */
1405int snd_soc_dapm_sync(struct snd_soc_codec *codec) 1357int snd_soc_dapm_sync(struct snd_soc_codec *codec)
1406{ 1358{
1407 int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); 1359 return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
1408 dump_dapm(codec, "sync");
1409 return ret;
1410} 1360}
1411EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); 1361EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
1412 1362
@@ -1688,6 +1638,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1688 unsigned int mask = (1 << fls(max)) - 1; 1638 unsigned int mask = (1 << fls(max)) - 1;
1689 unsigned int invert = mc->invert; 1639 unsigned int invert = mc->invert;
1690 unsigned int val, val2, val_mask; 1640 unsigned int val, val2, val_mask;
1641 int connect;
1691 int ret; 1642 int ret;
1692 1643
1693 val = (ucontrol->value.integer.value[0] & mask); 1644 val = (ucontrol->value.integer.value[0] & mask);
@@ -1714,7 +1665,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1714 return 1; 1665 return 1;
1715 } 1666 }
1716 1667
1717 dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); 1668 if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
1669 if (val)
1670 /* new connection */
1671 connect = invert ? 0:1;
1672 else
1673 /* old connection must be powered down */
1674 connect = invert ? 1:0;
1675
1676 dapm_mixer_update_power(widget, kcontrol, connect);
1677 }
1678
1718 if (widget->event) { 1679 if (widget->event) {
1719 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1680 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1720 ret = widget->event(widget, kcontrol, 1681 ret = widget->event(widget, kcontrol,
@@ -2152,7 +2113,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
2152 2113
2153 dapm_power_widgets(codec, event); 2114 dapm_power_widgets(codec, event);
2154 mutex_unlock(&codec->mutex); 2115 mutex_unlock(&codec->mutex);
2155 dump_dapm(codec, __func__);
2156 return 0; 2116 return 0;
2157} 2117}
2158EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); 2118EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);