diff options
author | Johannes Stezenbach <js@sig21.net> | 2011-06-22 08:59:24 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-06-22 14:10:59 -0400 |
commit | c034abf6e5039cbbe691de37903c514c1033bf75 (patch) | |
tree | b544e78a4d0b7529c5d8391a04340defe2fbd296 | |
parent | bab3b59d531bb4dd04d2996dd553ab6e38ec8972 (diff) |
ASoC: add STA32X codec driver
Signed-off-by: Johannes Stezenbach <js@sig21.net>
[zonque@gmail.com: transform to new ASoC structure]
Signed-off-by: Daniel Mack <zonque@gmail.com>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/sta32x.c | 777 | ||||
-rw-r--r-- | sound/soc/codecs/sta32x.h | 210 |
4 files changed, 993 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7a2e4269b255..6d32346ac7ce 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -42,6 +42,7 @@ config SND_SOC_ALL_CODECS | |||
42 | select SND_SOC_SN95031 if INTEL_SCU_IPC | 42 | select SND_SOC_SN95031 if INTEL_SCU_IPC |
43 | select SND_SOC_SPDIF | 43 | select SND_SOC_SPDIF |
44 | select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI | 44 | select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI |
45 | select SND_SOC_STA32X if I2C | ||
45 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 46 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
46 | select SND_SOC_TLV320AIC23 if I2C | 47 | select SND_SOC_TLV320AIC23 if I2C |
47 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 48 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
@@ -220,6 +221,9 @@ config SND_SOC_SPDIF | |||
220 | config SND_SOC_SSM2602 | 221 | config SND_SOC_SSM2602 |
221 | tristate | 222 | tristate |
222 | 223 | ||
224 | config SND_SOC_STA32X | ||
225 | tristate | ||
226 | |||
223 | config SND_SOC_STAC9766 | 227 | config SND_SOC_STAC9766 |
224 | tristate | 228 | tristate |
225 | 229 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 30a4c631aef4..600102eb6010 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -29,6 +29,7 @@ snd-soc-alc5623-objs := alc5623.o | |||
29 | snd-soc-sn95031-objs := sn95031.o | 29 | snd-soc-sn95031-objs := sn95031.o |
30 | snd-soc-spdif-objs := spdif_transciever.o | 30 | snd-soc-spdif-objs := spdif_transciever.o |
31 | snd-soc-ssm2602-objs := ssm2602.o | 31 | snd-soc-ssm2602-objs := ssm2602.o |
32 | snd-soc-sta32x-objs := sta32x.o | ||
32 | snd-soc-stac9766-objs := stac9766.o | 33 | snd-soc-stac9766-objs := stac9766.o |
33 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 34 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
34 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 35 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
@@ -122,6 +123,7 @@ obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | |||
122 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o | 123 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o |
123 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 124 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o |
124 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 125 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
126 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o | ||
125 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 127 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
126 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 128 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
127 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 129 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c new file mode 100644 index 000000000000..486628a144b4 --- /dev/null +++ b/sound/soc/codecs/sta32x.c | |||
@@ -0,0 +1,777 @@ | |||
1 | /* | ||
2 | * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system | ||
3 | * | ||
4 | * Copyright: 2011 Raumfeld GmbH | ||
5 | * Author: Johannes Stezenbach <js@sig21.net> | ||
6 | * | ||
7 | * based on code from: | ||
8 | * Wolfson Microelectronics PLC. | ||
9 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
10 | * Freescale Semiconductor, Inc. | ||
11 | * Timur Tabi <timur@freescale.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/regulator/consumer.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/initval.h> | ||
36 | #include <sound/tlv.h> | ||
37 | |||
38 | #include "sta32x.h" | ||
39 | |||
40 | #define STA32X_RATES (SNDRV_PCM_RATE_32000 | \ | ||
41 | SNDRV_PCM_RATE_44100 | \ | ||
42 | SNDRV_PCM_RATE_48000 | \ | ||
43 | SNDRV_PCM_RATE_88200 | \ | ||
44 | SNDRV_PCM_RATE_96000 | \ | ||
45 | SNDRV_PCM_RATE_176400 | \ | ||
46 | SNDRV_PCM_RATE_192000) | ||
47 | |||
48 | #define STA32X_FORMATS \ | ||
49 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
50 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
51 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
52 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ | ||
53 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ | ||
54 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) | ||
55 | |||
56 | /* Power-up register defaults */ | ||
57 | static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = { | ||
58 | 0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60, | ||
59 | 0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69, | ||
60 | 0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, | ||
62 | 0xc0, 0xf3, 0x33, 0x00, 0x0c, | ||
63 | }; | ||
64 | |||
65 | /* regulator power supply names */ | ||
66 | static const char *sta32x_supply_names[] = { | ||
67 | "Vdda", /* analog supply, 3.3VV */ | ||
68 | "Vdd3", /* digital supply, 3.3V */ | ||
69 | "Vcc" /* power amp spply, 10V - 36V */ | ||
70 | }; | ||
71 | |||
72 | /* codec private data */ | ||
73 | struct sta32x_priv { | ||
74 | struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; | ||
75 | struct snd_soc_codec *codec; | ||
76 | |||
77 | unsigned int mclk; | ||
78 | unsigned int format; | ||
79 | }; | ||
80 | |||
81 | static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); | ||
82 | static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); | ||
83 | static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0); | ||
84 | |||
85 | static const char *sta32x_drc_ac[] = { | ||
86 | "Anti-Clipping", "Dynamic Range Compression" }; | ||
87 | static const char *sta32x_auto_eq_mode[] = { | ||
88 | "User", "Preset", "Loudness" }; | ||
89 | static const char *sta32x_auto_gc_mode[] = { | ||
90 | "User", "AC no clipping", "AC limited clipping (10%)", | ||
91 | "DRC nighttime listening mode" }; | ||
92 | static const char *sta32x_auto_xo_mode[] = { | ||
93 | "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz", | ||
94 | "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" }; | ||
95 | static const char *sta32x_preset_eq_mode[] = { | ||
96 | "Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft", | ||
97 | "Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1", | ||
98 | "Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2", | ||
99 | "Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7", | ||
100 | "Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12", | ||
101 | "Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" }; | ||
102 | static const char *sta32x_limiter_select[] = { | ||
103 | "Limiter Disabled", "Limiter #1", "Limiter #2" }; | ||
104 | static const char *sta32x_limiter_attack_rate[] = { | ||
105 | "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", | ||
106 | "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", | ||
107 | "0.0645", "0.0564", "0.0501", "0.0451" }; | ||
108 | static const char *sta32x_limiter_release_rate[] = { | ||
109 | "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", | ||
110 | "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", | ||
111 | "0.0134", "0.0117", "0.0110", "0.0104" }; | ||
112 | |||
113 | static const unsigned int sta32x_limiter_ac_attack_tlv[] = { | ||
114 | TLV_DB_RANGE_HEAD(2), | ||
115 | 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), | ||
116 | 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), | ||
117 | }; | ||
118 | |||
119 | static const unsigned int sta32x_limiter_ac_release_tlv[] = { | ||
120 | TLV_DB_RANGE_HEAD(5), | ||
121 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), | ||
122 | 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), | ||
123 | 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), | ||
124 | 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), | ||
125 | 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), | ||
126 | }; | ||
127 | |||
128 | static const unsigned int sta32x_limiter_drc_attack_tlv[] = { | ||
129 | TLV_DB_RANGE_HEAD(3), | ||
130 | 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), | ||
131 | 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), | ||
132 | 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), | ||
133 | }; | ||
134 | |||
135 | static const unsigned int sta32x_limiter_drc_release_tlv[] = { | ||
136 | TLV_DB_RANGE_HEAD(5), | ||
137 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), | ||
138 | 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), | ||
139 | 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), | ||
140 | 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), | ||
141 | 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), | ||
142 | }; | ||
143 | |||
144 | static const struct soc_enum sta32x_drc_ac_enum = | ||
145 | SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, | ||
146 | 2, sta32x_drc_ac); | ||
147 | static const struct soc_enum sta32x_auto_eq_enum = | ||
148 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, | ||
149 | 3, sta32x_auto_eq_mode); | ||
150 | static const struct soc_enum sta32x_auto_gc_enum = | ||
151 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, | ||
152 | 4, sta32x_auto_gc_mode); | ||
153 | static const struct soc_enum sta32x_auto_xo_enum = | ||
154 | SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, | ||
155 | 16, sta32x_auto_xo_mode); | ||
156 | static const struct soc_enum sta32x_preset_eq_enum = | ||
157 | SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, | ||
158 | 32, sta32x_preset_eq_mode); | ||
159 | static const struct soc_enum sta32x_limiter_ch1_enum = | ||
160 | SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, | ||
161 | 3, sta32x_limiter_select); | ||
162 | static const struct soc_enum sta32x_limiter_ch2_enum = | ||
163 | SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, | ||
164 | 3, sta32x_limiter_select); | ||
165 | static const struct soc_enum sta32x_limiter_ch3_enum = | ||
166 | SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, | ||
167 | 3, sta32x_limiter_select); | ||
168 | static const struct soc_enum sta32x_limiter1_attack_rate_enum = | ||
169 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, | ||
170 | 16, sta32x_limiter_attack_rate); | ||
171 | static const struct soc_enum sta32x_limiter2_attack_rate_enum = | ||
172 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, | ||
173 | 16, sta32x_limiter_attack_rate); | ||
174 | static const struct soc_enum sta32x_limiter1_release_rate_enum = | ||
175 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, | ||
176 | 16, sta32x_limiter_release_rate); | ||
177 | static const struct soc_enum sta32x_limiter2_release_rate_enum = | ||
178 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, | ||
179 | 16, sta32x_limiter_release_rate); | ||
180 | static const struct snd_kcontrol_new sta32x_snd_controls[] = { | ||
181 | SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), | ||
182 | SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), | ||
183 | SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1), | ||
184 | SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1), | ||
185 | SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1), | ||
186 | SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv), | ||
187 | SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv), | ||
188 | SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv), | ||
189 | SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0), | ||
190 | SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum), | ||
191 | SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0), | ||
192 | SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0), | ||
193 | SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0), | ||
194 | SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0), | ||
195 | SOC_ENUM("Automode EQ", sta32x_auto_eq_enum), | ||
196 | SOC_ENUM("Automode GC", sta32x_auto_gc_enum), | ||
197 | SOC_ENUM("Automode XO", sta32x_auto_xo_enum), | ||
198 | SOC_ENUM("Preset EQ", sta32x_preset_eq_enum), | ||
199 | SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), | ||
200 | SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), | ||
201 | SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), | ||
202 | SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), | ||
203 | SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
204 | SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
205 | SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
206 | SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum), | ||
207 | SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum), | ||
208 | SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum), | ||
209 | SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv), | ||
210 | SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv), | ||
211 | SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), | ||
212 | SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), | ||
213 | SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | ||
214 | SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | ||
215 | |||
216 | /* depending on mode, the attack/release thresholds have | ||
217 | * two different enum definitions; provide both | ||
218 | */ | ||
219 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, | ||
220 | 16, 0, sta32x_limiter_ac_attack_tlv), | ||
221 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, | ||
222 | 16, 0, sta32x_limiter_ac_attack_tlv), | ||
223 | SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, | ||
224 | 16, 0, sta32x_limiter_ac_release_tlv), | ||
225 | SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, | ||
226 | 16, 0, sta32x_limiter_ac_release_tlv), | ||
227 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, | ||
228 | 16, 0, sta32x_limiter_drc_attack_tlv), | ||
229 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, | ||
230 | 16, 0, sta32x_limiter_drc_attack_tlv), | ||
231 | SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, | ||
232 | 16, 0, sta32x_limiter_drc_release_tlv), | ||
233 | SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, | ||
234 | 16, 0, sta32x_limiter_drc_release_tlv), | ||
235 | }; | ||
236 | |||
237 | static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { | ||
238 | SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), | ||
239 | SND_SOC_DAPM_OUTPUT("LEFT"), | ||
240 | SND_SOC_DAPM_OUTPUT("RIGHT"), | ||
241 | SND_SOC_DAPM_OUTPUT("SUB"), | ||
242 | }; | ||
243 | |||
244 | static const struct snd_soc_dapm_route sta32x_dapm_routes[] = { | ||
245 | { "LEFT", NULL, "DAC" }, | ||
246 | { "RIGHT", NULL, "DAC" }, | ||
247 | { "SUB", NULL, "DAC" }, | ||
248 | }; | ||
249 | |||
250 | /* MCLK interpolation ratio per fs */ | ||
251 | static struct { | ||
252 | int fs; | ||
253 | int ir; | ||
254 | } interpolation_ratios[] = { | ||
255 | { 32000, 0 }, | ||
256 | { 44100, 0 }, | ||
257 | { 48000, 0 }, | ||
258 | { 88200, 1 }, | ||
259 | { 96000, 1 }, | ||
260 | { 176400, 2 }, | ||
261 | { 192000, 2 }, | ||
262 | }; | ||
263 | |||
264 | /* MCLK to fs clock ratios */ | ||
265 | static struct { | ||
266 | int ratio; | ||
267 | int mcs; | ||
268 | } mclk_ratios[3][7] = { | ||
269 | { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 }, | ||
270 | { 128, 4 }, { 576, 5 }, { 0, 0 } }, | ||
271 | { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, | ||
272 | { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, | ||
273 | }; | ||
274 | |||
275 | |||
276 | /** | ||
277 | * sta32x_set_dai_sysclk - configure MCLK | ||
278 | * @codec_dai: the codec DAI | ||
279 | * @clk_id: the clock ID (ignored) | ||
280 | * @freq: the MCLK input frequency | ||
281 | * @dir: the clock direction (ignored) | ||
282 | * | ||
283 | * The value of MCLK is used to determine which sample rates are supported | ||
284 | * by the STA32X, based on the mclk_ratios table. | ||
285 | * | ||
286 | * This function must be called by the machine driver's 'startup' function, | ||
287 | * otherwise the list of supported sample rates will not be available in | ||
288 | * time for ALSA. | ||
289 | * | ||
290 | * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause | ||
291 | * theoretically possible sample rates to be enabled. Call it again with a | ||
292 | * proper value set one the external clock is set (most probably you would do | ||
293 | * that from a machine's driver 'hw_param' hook. | ||
294 | */ | ||
295 | static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
296 | int clk_id, unsigned int freq, int dir) | ||
297 | { | ||
298 | struct snd_soc_codec *codec = codec_dai->codec; | ||
299 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
300 | int i, j, ir, fs; | ||
301 | unsigned int rates = 0; | ||
302 | unsigned int rate_min = -1; | ||
303 | unsigned int rate_max = 0; | ||
304 | |||
305 | pr_debug("mclk=%u\n", freq); | ||
306 | sta32x->mclk = freq; | ||
307 | |||
308 | if (sta32x->mclk) { | ||
309 | for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { | ||
310 | ir = interpolation_ratios[i].ir; | ||
311 | fs = interpolation_ratios[i].fs; | ||
312 | for (j = 0; mclk_ratios[ir][j].ratio; j++) { | ||
313 | if (mclk_ratios[ir][j].ratio * fs == freq) { | ||
314 | rates |= snd_pcm_rate_to_rate_bit(fs); | ||
315 | if (fs < rate_min) | ||
316 | rate_min = fs; | ||
317 | if (fs > rate_max) | ||
318 | rate_max = fs; | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | /* FIXME: soc should support a rate list */ | ||
323 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
324 | |||
325 | if (!rates) { | ||
326 | dev_err(codec->dev, "could not find a valid sample rate\n"); | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | } else { | ||
330 | /* enable all possible rates */ | ||
331 | rates = STA32X_RATES; | ||
332 | rate_min = 32000; | ||
333 | rate_max = 192000; | ||
334 | } | ||
335 | |||
336 | codec_dai->driver->playback.rates = rates; | ||
337 | codec_dai->driver->playback.rate_min = rate_min; | ||
338 | codec_dai->driver->playback.rate_max = rate_max; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * sta32x_set_dai_fmt - configure the codec for the selected audio format | ||
344 | * @codec_dai: the codec DAI | ||
345 | * @fmt: a SND_SOC_DAIFMT_x value indicating the data format | ||
346 | * | ||
347 | * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the | ||
348 | * codec accordingly. | ||
349 | */ | ||
350 | static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
351 | unsigned int fmt) | ||
352 | { | ||
353 | struct snd_soc_codec *codec = codec_dai->codec; | ||
354 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
355 | u8 confb = snd_soc_read(codec, STA32X_CONFB); | ||
356 | |||
357 | pr_debug("\n"); | ||
358 | confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM); | ||
359 | |||
360 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
361 | case SND_SOC_DAIFMT_CBS_CFS: | ||
362 | break; | ||
363 | default: | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
368 | case SND_SOC_DAIFMT_I2S: | ||
369 | case SND_SOC_DAIFMT_RIGHT_J: | ||
370 | case SND_SOC_DAIFMT_LEFT_J: | ||
371 | sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
372 | break; | ||
373 | default: | ||
374 | return -EINVAL; | ||
375 | } | ||
376 | |||
377 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
378 | case SND_SOC_DAIFMT_NB_NF: | ||
379 | confb |= STA32X_CONFB_C2IM; | ||
380 | break; | ||
381 | case SND_SOC_DAIFMT_NB_IF: | ||
382 | confb |= STA32X_CONFB_C1IM; | ||
383 | break; | ||
384 | default: | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | |||
388 | snd_soc_write(codec, STA32X_CONFB, confb); | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | /** | ||
393 | * sta32x_hw_params - program the STA32X with the given hardware parameters. | ||
394 | * @substream: the audio stream | ||
395 | * @params: the hardware parameters to set | ||
396 | * @dai: the SOC DAI (ignored) | ||
397 | * | ||
398 | * This function programs the hardware with the values provided. | ||
399 | * Specifically, the sample rate and the data format. | ||
400 | */ | ||
401 | static int sta32x_hw_params(struct snd_pcm_substream *substream, | ||
402 | struct snd_pcm_hw_params *params, | ||
403 | struct snd_soc_dai *dai) | ||
404 | { | ||
405 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
406 | struct snd_soc_codec *codec = rtd->codec; | ||
407 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
408 | unsigned int rate; | ||
409 | int i, mcs = -1, ir = -1; | ||
410 | u8 confa, confb; | ||
411 | |||
412 | rate = params_rate(params); | ||
413 | pr_debug("rate: %u\n", rate); | ||
414 | for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) | ||
415 | if (interpolation_ratios[i].fs == rate) | ||
416 | ir = interpolation_ratios[i].ir; | ||
417 | if (ir < 0) | ||
418 | return -EINVAL; | ||
419 | for (i = 0; mclk_ratios[ir][i].ratio; i++) | ||
420 | if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) | ||
421 | mcs = mclk_ratios[ir][i].mcs; | ||
422 | if (mcs < 0) | ||
423 | return -EINVAL; | ||
424 | |||
425 | confa = snd_soc_read(codec, STA32X_CONFA); | ||
426 | confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); | ||
427 | confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); | ||
428 | |||
429 | confb = snd_soc_read(codec, STA32X_CONFB); | ||
430 | confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB); | ||
431 | switch (params_format(params)) { | ||
432 | case SNDRV_PCM_FORMAT_S24_LE: | ||
433 | case SNDRV_PCM_FORMAT_S24_BE: | ||
434 | case SNDRV_PCM_FORMAT_S24_3LE: | ||
435 | case SNDRV_PCM_FORMAT_S24_3BE: | ||
436 | pr_debug("24bit\n"); | ||
437 | /* fall through */ | ||
438 | case SNDRV_PCM_FORMAT_S32_LE: | ||
439 | case SNDRV_PCM_FORMAT_S32_BE: | ||
440 | pr_debug("24bit or 32bit\n"); | ||
441 | switch (sta32x->format) { | ||
442 | case SND_SOC_DAIFMT_I2S: | ||
443 | confb |= 0x0; | ||
444 | break; | ||
445 | case SND_SOC_DAIFMT_LEFT_J: | ||
446 | confb |= 0x1; | ||
447 | break; | ||
448 | case SND_SOC_DAIFMT_RIGHT_J: | ||
449 | confb |= 0x2; | ||
450 | break; | ||
451 | } | ||
452 | |||
453 | break; | ||
454 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
455 | case SNDRV_PCM_FORMAT_S20_3BE: | ||
456 | pr_debug("20bit\n"); | ||
457 | switch (sta32x->format) { | ||
458 | case SND_SOC_DAIFMT_I2S: | ||
459 | confb |= 0x4; | ||
460 | break; | ||
461 | case SND_SOC_DAIFMT_LEFT_J: | ||
462 | confb |= 0x5; | ||
463 | break; | ||
464 | case SND_SOC_DAIFMT_RIGHT_J: | ||
465 | confb |= 0x6; | ||
466 | break; | ||
467 | } | ||
468 | |||
469 | break; | ||
470 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
471 | case SNDRV_PCM_FORMAT_S18_3BE: | ||
472 | pr_debug("18bit\n"); | ||
473 | switch (sta32x->format) { | ||
474 | case SND_SOC_DAIFMT_I2S: | ||
475 | confb |= 0x8; | ||
476 | break; | ||
477 | case SND_SOC_DAIFMT_LEFT_J: | ||
478 | confb |= 0x9; | ||
479 | break; | ||
480 | case SND_SOC_DAIFMT_RIGHT_J: | ||
481 | confb |= 0xa; | ||
482 | break; | ||
483 | } | ||
484 | |||
485 | break; | ||
486 | case SNDRV_PCM_FORMAT_S16_LE: | ||
487 | case SNDRV_PCM_FORMAT_S16_BE: | ||
488 | pr_debug("16bit\n"); | ||
489 | switch (sta32x->format) { | ||
490 | case SND_SOC_DAIFMT_I2S: | ||
491 | confb |= 0x0; | ||
492 | break; | ||
493 | case SND_SOC_DAIFMT_LEFT_J: | ||
494 | confb |= 0xd; | ||
495 | break; | ||
496 | case SND_SOC_DAIFMT_RIGHT_J: | ||
497 | confb |= 0xe; | ||
498 | break; | ||
499 | } | ||
500 | |||
501 | break; | ||
502 | default: | ||
503 | return -EINVAL; | ||
504 | } | ||
505 | |||
506 | snd_soc_write(codec, STA32X_CONFA, confa); | ||
507 | snd_soc_write(codec, STA32X_CONFB, confb); | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | /** | ||
512 | * sta32x_set_bias_level - DAPM callback | ||
513 | * @codec: the codec device | ||
514 | * @level: DAPM power level | ||
515 | * | ||
516 | * This is called by ALSA to put the codec into low power mode | ||
517 | * or to wake it up. If the codec is powered off completely | ||
518 | * all registers must be restored after power on. | ||
519 | */ | ||
520 | static int sta32x_set_bias_level(struct snd_soc_codec *codec, | ||
521 | enum snd_soc_bias_level level) | ||
522 | { | ||
523 | int ret; | ||
524 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
525 | |||
526 | pr_debug("level = %d\n", level); | ||
527 | switch (level) { | ||
528 | case SND_SOC_BIAS_ON: | ||
529 | break; | ||
530 | |||
531 | case SND_SOC_BIAS_PREPARE: | ||
532 | /* Full power on */ | ||
533 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
534 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
535 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); | ||
536 | break; | ||
537 | |||
538 | case SND_SOC_BIAS_STANDBY: | ||
539 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
540 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), | ||
541 | sta32x->supplies); | ||
542 | if (ret != 0) { | ||
543 | dev_err(codec->dev, | ||
544 | "Failed to enable supplies: %d\n", ret); | ||
545 | return ret; | ||
546 | } | ||
547 | |||
548 | snd_soc_cache_sync(codec); | ||
549 | } | ||
550 | |||
551 | /* Power up to mute */ | ||
552 | /* FIXME */ | ||
553 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
554 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
555 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); | ||
556 | |||
557 | break; | ||
558 | |||
559 | case SND_SOC_BIAS_OFF: | ||
560 | /* The chip runs through the power down sequence for us. */ | ||
561 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
562 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
563 | STA32X_CONFF_PWDN); | ||
564 | msleep(300); | ||
565 | |||
566 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), | ||
567 | sta32x->supplies); | ||
568 | break; | ||
569 | } | ||
570 | codec->dapm.bias_level = level; | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static struct snd_soc_dai_ops sta32x_dai_ops = { | ||
575 | .hw_params = sta32x_hw_params, | ||
576 | .set_sysclk = sta32x_set_dai_sysclk, | ||
577 | .set_fmt = sta32x_set_dai_fmt, | ||
578 | }; | ||
579 | |||
580 | static struct snd_soc_dai_driver sta32x_dai = { | ||
581 | .name = "STA32X", | ||
582 | .playback = { | ||
583 | .stream_name = "Playback", | ||
584 | .channels_min = 2, | ||
585 | .channels_max = 2, | ||
586 | .rates = STA32X_RATES, | ||
587 | .formats = STA32X_FORMATS, | ||
588 | }, | ||
589 | .ops = &sta32x_dai_ops, | ||
590 | }; | ||
591 | |||
592 | #ifdef CONFIG_PM | ||
593 | static int sta32x_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
594 | { | ||
595 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int sta32x_resume(struct snd_soc_codec *codec) | ||
600 | { | ||
601 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
602 | return 0; | ||
603 | } | ||
604 | #else | ||
605 | #define sta32x_suspend NULL | ||
606 | #define sta32x_resume NULL | ||
607 | #endif | ||
608 | |||
609 | static int sta32x_probe(struct snd_soc_codec *codec) | ||
610 | { | ||
611 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
612 | int i, ret = 0; | ||
613 | |||
614 | sta32x->codec = codec; | ||
615 | |||
616 | /* regulators */ | ||
617 | for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) | ||
618 | sta32x->supplies[i].supply = sta32x_supply_names[i]; | ||
619 | |||
620 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies), | ||
621 | sta32x->supplies); | ||
622 | if (ret != 0) { | ||
623 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
624 | goto err; | ||
625 | } | ||
626 | |||
627 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), | ||
628 | sta32x->supplies); | ||
629 | if (ret != 0) { | ||
630 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
631 | goto err_get; | ||
632 | } | ||
633 | |||
634 | /* Tell ASoC what kind of I/O to use to read the registers. ASoC will | ||
635 | * then do the I2C transactions itself. | ||
636 | */ | ||
637 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | ||
638 | if (ret < 0) { | ||
639 | dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); | ||
640 | return ret; | ||
641 | } | ||
642 | |||
643 | /* read reg reset values into cache */ | ||
644 | for (i = 0; i < STA32X_REGISTER_COUNT; i++) | ||
645 | snd_soc_cache_write(codec, i, sta32x_regs[i]); | ||
646 | |||
647 | /* FIXME enable thermal warning adjustment and recovery */ | ||
648 | snd_soc_update_bits(codec, STA32X_CONFA, | ||
649 | STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, 0); | ||
650 | |||
651 | /* FIXME select 2.1 mode */ | ||
652 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
653 | STA32X_CONFF_OCFG_MASK, | ||
654 | 1 << STA32X_CONFF_OCFG_SHIFT); | ||
655 | |||
656 | /* FIXME channel to output mapping */ | ||
657 | snd_soc_update_bits(codec, STA32X_C1CFG, | ||
658 | STA32X_CxCFG_OM_MASK, | ||
659 | 0 << STA32X_CxCFG_OM_SHIFT); | ||
660 | snd_soc_update_bits(codec, STA32X_C2CFG, | ||
661 | STA32X_CxCFG_OM_MASK, | ||
662 | 1 << STA32X_CxCFG_OM_SHIFT); | ||
663 | snd_soc_update_bits(codec, STA32X_C3CFG, | ||
664 | STA32X_CxCFG_OM_MASK, | ||
665 | 2 << STA32X_CxCFG_OM_SHIFT); | ||
666 | |||
667 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
668 | /* Bias level configuration will have done an extra enable */ | ||
669 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
670 | |||
671 | return 0; | ||
672 | |||
673 | err_get: | ||
674 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
675 | err: | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | static int sta32x_remove(struct snd_soc_codec *codec) | ||
680 | { | ||
681 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
682 | |||
683 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
684 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
685 | |||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | static const struct snd_soc_codec_driver sta32x_codec = { | ||
690 | .probe = sta32x_probe, | ||
691 | .remove = sta32x_remove, | ||
692 | .suspend = sta32x_suspend, | ||
693 | .resume = sta32x_resume, | ||
694 | .reg_cache_size = STA32X_REGISTER_COUNT, | ||
695 | .reg_word_size = sizeof(u8), | ||
696 | .set_bias_level = sta32x_set_bias_level, | ||
697 | .controls = sta32x_snd_controls, | ||
698 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), | ||
699 | .dapm_widgets = sta32x_dapm_widgets, | ||
700 | .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets), | ||
701 | .dapm_routes = sta32x_dapm_routes, | ||
702 | .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes), | ||
703 | }; | ||
704 | |||
705 | static __devinit int sta32x_i2c_probe(struct i2c_client *i2c, | ||
706 | const struct i2c_device_id *id) | ||
707 | { | ||
708 | struct sta32x_priv *sta32x; | ||
709 | int ret; | ||
710 | |||
711 | sta32x = kzalloc(sizeof(struct sta32x_priv), GFP_KERNEL); | ||
712 | if (!sta32x) | ||
713 | return -ENOMEM; | ||
714 | |||
715 | i2c_set_clientdata(i2c, sta32x); | ||
716 | |||
717 | ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); | ||
718 | if (ret != 0) { | ||
719 | dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret); | ||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static __devexit int sta32x_i2c_remove(struct i2c_client *client) | ||
727 | { | ||
728 | struct sta32x_priv *sta32x = i2c_get_clientdata(client); | ||
729 | struct snd_soc_codec *codec = sta32x->codec; | ||
730 | |||
731 | if (codec) | ||
732 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
733 | |||
734 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
735 | |||
736 | if (codec) { | ||
737 | snd_soc_unregister_codec(&client->dev); | ||
738 | snd_soc_codec_set_drvdata(codec, NULL); | ||
739 | } | ||
740 | |||
741 | kfree(sta32x); | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static const struct i2c_device_id sta32x_i2c_id[] = { | ||
746 | { "sta326", 0 }, | ||
747 | { "sta328", 0 }, | ||
748 | { "sta329", 0 }, | ||
749 | { } | ||
750 | }; | ||
751 | MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id); | ||
752 | |||
753 | static struct i2c_driver sta32x_i2c_driver = { | ||
754 | .driver = { | ||
755 | .name = "sta32x", | ||
756 | .owner = THIS_MODULE, | ||
757 | }, | ||
758 | .probe = sta32x_i2c_probe, | ||
759 | .remove = __devexit_p(sta32x_i2c_remove), | ||
760 | .id_table = sta32x_i2c_id, | ||
761 | }; | ||
762 | |||
763 | static int __init sta32x_init(void) | ||
764 | { | ||
765 | return i2c_add_driver(&sta32x_i2c_driver); | ||
766 | } | ||
767 | module_init(sta32x_init); | ||
768 | |||
769 | static void __exit sta32x_exit(void) | ||
770 | { | ||
771 | i2c_del_driver(&sta32x_i2c_driver); | ||
772 | } | ||
773 | module_exit(sta32x_exit); | ||
774 | |||
775 | MODULE_DESCRIPTION("ASoC STA32X driver"); | ||
776 | MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>"); | ||
777 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/sta32x.h b/sound/soc/codecs/sta32x.h new file mode 100644 index 000000000000..b97ee5a75667 --- /dev/null +++ b/sound/soc/codecs/sta32x.h | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system | ||
3 | * | ||
4 | * Copyright: 2011 Raumfeld GmbH | ||
5 | * Author: Johannes Stezenbach <js@sig21.net> | ||
6 | * | ||
7 | * based on code from: | ||
8 | * Wolfson Microelectronics PLC. | ||
9 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | #ifndef _ASOC_STA_32X_H | ||
17 | #define _ASOC_STA_32X_H | ||
18 | |||
19 | /* STA326 register addresses */ | ||
20 | |||
21 | #define STA32X_REGISTER_COUNT 0x2d | ||
22 | |||
23 | #define STA32X_CONFA 0x00 | ||
24 | #define STA32X_CONFB 0x01 | ||
25 | #define STA32X_CONFC 0x02 | ||
26 | #define STA32X_CONFD 0x03 | ||
27 | #define STA32X_CONFE 0x04 | ||
28 | #define STA32X_CONFF 0x05 | ||
29 | #define STA32X_MMUTE 0x06 | ||
30 | #define STA32X_MVOL 0x07 | ||
31 | #define STA32X_C1VOL 0x08 | ||
32 | #define STA32X_C2VOL 0x09 | ||
33 | #define STA32X_C3VOL 0x0a | ||
34 | #define STA32X_AUTO1 0x0b | ||
35 | #define STA32X_AUTO2 0x0c | ||
36 | #define STA32X_AUTO3 0x0d | ||
37 | #define STA32X_C1CFG 0x0e | ||
38 | #define STA32X_C2CFG 0x0f | ||
39 | #define STA32X_C3CFG 0x10 | ||
40 | #define STA32X_TONE 0x11 | ||
41 | #define STA32X_L1AR 0x12 | ||
42 | #define STA32X_L1ATRT 0x13 | ||
43 | #define STA32X_L2AR 0x14 | ||
44 | #define STA32X_L2ATRT 0x15 | ||
45 | #define STA32X_CFADDR2 0x16 | ||
46 | #define STA32X_B1CF1 0x17 | ||
47 | #define STA32X_B1CF2 0x18 | ||
48 | #define STA32X_B1CF3 0x19 | ||
49 | #define STA32X_B2CF1 0x1a | ||
50 | #define STA32X_B2CF2 0x1b | ||
51 | #define STA32X_B2CF3 0x1c | ||
52 | #define STA32X_A1CF1 0x1d | ||
53 | #define STA32X_A1CF2 0x1e | ||
54 | #define STA32X_A1CF3 0x1f | ||
55 | #define STA32X_A2CF1 0x20 | ||
56 | #define STA32X_A2CF2 0x21 | ||
57 | #define STA32X_A2CF3 0x22 | ||
58 | #define STA32X_B0CF1 0x23 | ||
59 | #define STA32X_B0CF2 0x24 | ||
60 | #define STA32X_B0CF3 0x25 | ||
61 | #define STA32X_CFUD 0x26 | ||
62 | #define STA32X_MPCC1 0x27 | ||
63 | #define STA32X_MPCC2 0x28 | ||
64 | /* Reserved 0x29 */ | ||
65 | /* Reserved 0x2a */ | ||
66 | #define STA32X_Reserved 0x2a | ||
67 | #define STA32X_FDRC1 0x2b | ||
68 | #define STA32X_FDRC2 0x2c | ||
69 | /* Reserved 0x2d */ | ||
70 | |||
71 | |||
72 | /* STA326 register field definitions */ | ||
73 | |||
74 | /* 0x00 CONFA */ | ||
75 | #define STA32X_CONFA_MCS_MASK 0x03 | ||
76 | #define STA32X_CONFA_MCS_SHIFT 0 | ||
77 | #define STA32X_CONFA_IR_MASK 0x18 | ||
78 | #define STA32X_CONFA_IR_SHIFT 3 | ||
79 | #define STA32X_CONFA_TWRB 0x20 | ||
80 | #define STA32X_CONFA_TWAB 0x40 | ||
81 | #define STA32X_CONFA_FDRB 0x80 | ||
82 | |||
83 | /* 0x01 CONFB */ | ||
84 | #define STA32X_CONFB_SAI_MASK 0x0f | ||
85 | #define STA32X_CONFB_SAI_SHIFT 0 | ||
86 | #define STA32X_CONFB_SAIFB 0x10 | ||
87 | #define STA32X_CONFB_DSCKE 0x20 | ||
88 | #define STA32X_CONFB_C1IM 0x40 | ||
89 | #define STA32X_CONFB_C2IM 0x80 | ||
90 | |||
91 | /* 0x02 CONFC */ | ||
92 | #define STA32X_CONFC_OM_MASK 0x03 | ||
93 | #define STA32X_CONFC_OM_SHIFT 0 | ||
94 | #define STA32X_CONFC_CSZ_MASK 0x7c | ||
95 | #define STA32X_CONFC_CSZ_SHIFT 2 | ||
96 | |||
97 | /* 0x03 CONFD */ | ||
98 | #define STA32X_CONFD_HPB 0x01 | ||
99 | #define STA32X_CONFD_HPB_SHIFT 0 | ||
100 | #define STA32X_CONFD_DEMP 0x02 | ||
101 | #define STA32X_CONFD_DEMP_SHIFT 1 | ||
102 | #define STA32X_CONFD_DSPB 0x04 | ||
103 | #define STA32X_CONFD_DSPB_SHIFT 2 | ||
104 | #define STA32X_CONFD_PSL 0x08 | ||
105 | #define STA32X_CONFD_PSL_SHIFT 3 | ||
106 | #define STA32X_CONFD_BQL 0x10 | ||
107 | #define STA32X_CONFD_BQL_SHIFT 4 | ||
108 | #define STA32X_CONFD_DRC 0x20 | ||
109 | #define STA32X_CONFD_DRC_SHIFT 5 | ||
110 | #define STA32X_CONFD_ZDE 0x40 | ||
111 | #define STA32X_CONFD_ZDE_SHIFT 6 | ||
112 | #define STA32X_CONFD_MME 0x80 | ||
113 | #define STA32X_CONFD_MME_SHIFT 7 | ||
114 | |||
115 | /* 0x04 CONFE */ | ||
116 | #define STA32X_CONFE_MPCV 0x01 | ||
117 | #define STA32X_CONFE_MPCV_SHIFT 0 | ||
118 | #define STA32X_CONFE_MPC 0x02 | ||
119 | #define STA32X_CONFE_MPC_SHIFT 1 | ||
120 | #define STA32X_CONFE_AME 0x08 | ||
121 | #define STA32X_CONFE_AME_SHIFT 3 | ||
122 | #define STA32X_CONFE_PWMS 0x10 | ||
123 | #define STA32X_CONFE_PWMS_SHIFT 4 | ||
124 | #define STA32X_CONFE_ZCE 0x40 | ||
125 | #define STA32X_CONFE_ZCE_SHIFT 6 | ||
126 | #define STA32X_CONFE_SVE 0x80 | ||
127 | #define STA32X_CONFE_SVE_SHIFT 7 | ||
128 | |||
129 | /* 0x05 CONFF */ | ||
130 | #define STA32X_CONFF_OCFG_MASK 0x03 | ||
131 | #define STA32X_CONFF_OCFG_SHIFT 0 | ||
132 | #define STA32X_CONFF_IDE 0x04 | ||
133 | #define STA32X_CONFF_IDE_SHIFT 3 | ||
134 | #define STA32X_CONFF_BCLE 0x08 | ||
135 | #define STA32X_CONFF_ECLE 0x20 | ||
136 | #define STA32X_CONFF_PWDN 0x40 | ||
137 | #define STA32X_CONFF_EAPD 0x80 | ||
138 | |||
139 | /* 0x06 MMUTE */ | ||
140 | #define STA32X_MMUTE_MMUTE 0x01 | ||
141 | |||
142 | /* 0x0b AUTO1 */ | ||
143 | #define STA32X_AUTO1_AMEQ_MASK 0x03 | ||
144 | #define STA32X_AUTO1_AMEQ_SHIFT 0 | ||
145 | #define STA32X_AUTO1_AMV_MASK 0xc0 | ||
146 | #define STA32X_AUTO1_AMV_SHIFT 2 | ||
147 | #define STA32X_AUTO1_AMGC_MASK 0x30 | ||
148 | #define STA32X_AUTO1_AMGC_SHIFT 4 | ||
149 | #define STA32X_AUTO1_AMPS 0x80 | ||
150 | |||
151 | /* 0x0c AUTO2 */ | ||
152 | #define STA32X_AUTO2_AMAME 0x01 | ||
153 | #define STA32X_AUTO2_AMAM_MASK 0x0e | ||
154 | #define STA32X_AUTO2_AMAM_SHIFT 1 | ||
155 | #define STA32X_AUTO2_XO_MASK 0xf0 | ||
156 | #define STA32X_AUTO2_XO_SHIFT 4 | ||
157 | |||
158 | /* 0x0d AUTO3 */ | ||
159 | #define STA32X_AUTO3_PEQ_MASK 0x1f | ||
160 | #define STA32X_AUTO3_PEQ_SHIFT 0 | ||
161 | |||
162 | /* 0x0e 0x0f 0x10 CxCFG */ | ||
163 | #define STA32X_CxCFG_TCB 0x01 /* only C1 and C2 */ | ||
164 | #define STA32X_CxCFG_TCB_SHIFT 0 | ||
165 | #define STA32X_CxCFG_EQBP 0x02 /* only C1 and C2 */ | ||
166 | #define STA32X_CxCFG_EQBP_SHIFT 1 | ||
167 | #define STA32X_CxCFG_VBP 0x03 | ||
168 | #define STA32X_CxCFG_VBP_SHIFT 2 | ||
169 | #define STA32X_CxCFG_BO 0x04 | ||
170 | #define STA32X_CxCFG_LS_MASK 0x30 | ||
171 | #define STA32X_CxCFG_LS_SHIFT 4 | ||
172 | #define STA32X_CxCFG_OM_MASK 0xc0 | ||
173 | #define STA32X_CxCFG_OM_SHIFT 6 | ||
174 | |||
175 | /* 0x11 TONE */ | ||
176 | #define STA32X_TONE_BTC_SHIFT 0 | ||
177 | #define STA32X_TONE_TTC_SHIFT 4 | ||
178 | |||
179 | /* 0x12 0x13 0x14 0x15 limiter attack/release */ | ||
180 | #define STA32X_LxA_SHIFT 0 | ||
181 | #define STA32X_LxR_SHIFT 4 | ||
182 | |||
183 | /* 0x26 CFUD */ | ||
184 | #define STA32X_CFUD_W1 0x01 | ||
185 | #define STA32X_CFUD_WA 0x02 | ||
186 | #define STA32X_CFUD_R1 0x04 | ||
187 | #define STA32X_CFUD_RA 0x08 | ||
188 | |||
189 | |||
190 | /* biquad filter coefficient table offsets */ | ||
191 | #define STA32X_C1_BQ_BASE 0 | ||
192 | #define STA32X_C2_BQ_BASE 20 | ||
193 | #define STA32X_CH_BQ_NUM 4 | ||
194 | #define STA32X_BQ_NUM_COEF 5 | ||
195 | #define STA32X_XO_HP_BQ_BASE 40 | ||
196 | #define STA32X_XO_LP_BQ_BASE 45 | ||
197 | #define STA32X_C1_PRESCALE 50 | ||
198 | #define STA32X_C2_PRESCALE 51 | ||
199 | #define STA32X_C1_POSTSCALE 52 | ||
200 | #define STA32X_C2_POSTSCALE 53 | ||
201 | #define STA32X_C3_POSTSCALE 54 | ||
202 | #define STA32X_TW_POSTSCALE 55 | ||
203 | #define STA32X_C1_MIX1 56 | ||
204 | #define STA32X_C1_MIX2 57 | ||
205 | #define STA32X_C2_MIX1 58 | ||
206 | #define STA32X_C2_MIX2 59 | ||
207 | #define STA32X_C3_MIX1 60 | ||
208 | #define STA32X_C3_MIX2 61 | ||
209 | |||
210 | #endif /* _ASOC_STA_32X_H */ | ||