diff options
author | Li Xu <li.xu@cirrus.com> | 2017-08-18 12:00:19 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-09-01 06:44:43 -0400 |
commit | 8f1e5bf9b4408e91942b94c76583eaf098f19382 (patch) | |
tree | 15c2c51830a828a4cebc457c0bbb2ce99aebe977 | |
parent | 5771a8c08880cdca3bfb4a3fc6d309d6bba20877 (diff) |
ASoC: cs43130: Add support for CS43130 codec
Add support for Cirrus Logic CS43130 codec.
Support:
I2S/DSP PCM playback.
DoP/DSD playback.
HP detection and DC/AC impedance measurement.
Signed-off-by: Li Xu <li.xu@cirrus.com>
Acked-by: Brian Austin <brian.austin@cirrus.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | sound/soc/codecs/Kconfig | 6 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/cs43130.c | 2690 | ||||
-rw-r--r-- | sound/soc/codecs/cs43130.h | 546 |
4 files changed, 3244 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6c78b0b49b81..ea7a2d540e5e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -60,6 +60,7 @@ config SND_SOC_ALL_CODECS | |||
60 | select SND_SOC_CS4271_I2C if I2C | 60 | select SND_SOC_CS4271_I2C if I2C |
61 | select SND_SOC_CS4271_SPI if SPI_MASTER | 61 | select SND_SOC_CS4271_SPI if SPI_MASTER |
62 | select SND_SOC_CS42XX8_I2C if I2C | 62 | select SND_SOC_CS42XX8_I2C if I2C |
63 | select SND_SOC_CS43130 if I2C | ||
63 | select SND_SOC_CS4349 if I2C | 64 | select SND_SOC_CS4349 if I2C |
64 | select SND_SOC_CS47L24 if MFD_CS47L24 | 65 | select SND_SOC_CS47L24 if MFD_CS47L24 |
65 | select SND_SOC_CS53L30 if I2C | 66 | select SND_SOC_CS53L30 if I2C |
@@ -486,6 +487,11 @@ config SND_SOC_CS42XX8_I2C | |||
486 | select SND_SOC_CS42XX8 | 487 | select SND_SOC_CS42XX8 |
487 | select REGMAP_I2C | 488 | select REGMAP_I2C |
488 | 489 | ||
490 | # Cirrus Logic CS43130 HiFi DAC | ||
491 | config SND_SOC_CS43130 | ||
492 | tristate "Cirrus Logic CS43130 CODEC" | ||
493 | depends on I2C | ||
494 | |||
489 | # Cirrus Logic CS4349 HiFi DAC | 495 | # Cirrus Logic CS4349 HiFi DAC |
490 | config SND_SOC_CS4349 | 496 | config SND_SOC_CS4349 |
491 | tristate "Cirrus Logic CS4349 CODEC" | 497 | tristate "Cirrus Logic CS4349 CODEC" |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1755a54e3dc9..5030e1f440d4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -53,6 +53,7 @@ snd-soc-cs4271-i2c-objs := cs4271-i2c.o | |||
53 | snd-soc-cs4271-spi-objs := cs4271-spi.o | 53 | snd-soc-cs4271-spi-objs := cs4271-spi.o |
54 | snd-soc-cs42xx8-objs := cs42xx8.o | 54 | snd-soc-cs42xx8-objs := cs42xx8.o |
55 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o | 55 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o |
56 | snd-soc-cs43130-objs := cs43130.o | ||
56 | snd-soc-cs4349-objs := cs4349.o | 57 | snd-soc-cs4349-objs := cs4349.o |
57 | snd-soc-cs47l24-objs := cs47l24.o | 58 | snd-soc-cs47l24-objs := cs47l24.o |
58 | snd-soc-cs53l30-objs := cs53l30.o | 59 | snd-soc-cs53l30-objs := cs53l30.o |
@@ -290,6 +291,7 @@ obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o | |||
290 | obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o | 291 | obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o |
291 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o | 292 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o |
292 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o | 293 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o |
294 | obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o | ||
293 | obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o | 295 | obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o |
294 | obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o | 296 | obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o |
295 | obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o | 297 | obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o |
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c new file mode 100644 index 000000000000..220e30199c5b --- /dev/null +++ b/sound/soc/codecs/cs43130.c | |||
@@ -0,0 +1,2690 @@ | |||
1 | /* | ||
2 | * cs43130.c -- CS43130 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2017 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Authors: Li Xu <li.xu@cirrus.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 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/gpio/consumer.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/pm.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/of_device.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <sound/core.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | #include <sound/initval.h> | ||
31 | #include <sound/tlv.h> | ||
32 | #include <linux/of_gpio.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/pm_runtime.h> | ||
35 | #include <linux/of_irq.h> | ||
36 | #include <linux/completion.h> | ||
37 | #include <linux/mutex.h> | ||
38 | #include <linux/workqueue.h> | ||
39 | #include <sound/jack.h> | ||
40 | |||
41 | #include "cs43130.h" | ||
42 | |||
43 | static const struct reg_default cs43130_reg_defaults[] = { | ||
44 | {CS43130_SYS_CLK_CTL_1, 0x06}, | ||
45 | {CS43130_SP_SRATE, 0x01}, | ||
46 | {CS43130_SP_BITSIZE, 0x05}, | ||
47 | {CS43130_PAD_INT_CFG, 0x03}, | ||
48 | {CS43130_PWDN_CTL, 0xFE}, | ||
49 | {CS43130_CRYSTAL_SET, 0x04}, | ||
50 | {CS43130_PLL_SET_1, 0x00}, | ||
51 | {CS43130_PLL_SET_2, 0x00}, | ||
52 | {CS43130_PLL_SET_3, 0x00}, | ||
53 | {CS43130_PLL_SET_4, 0x00}, | ||
54 | {CS43130_PLL_SET_5, 0x40}, | ||
55 | {CS43130_PLL_SET_6, 0x10}, | ||
56 | {CS43130_PLL_SET_7, 0x80}, | ||
57 | {CS43130_PLL_SET_8, 0x03}, | ||
58 | {CS43130_PLL_SET_9, 0x02}, | ||
59 | {CS43130_PLL_SET_10, 0x02}, | ||
60 | {CS43130_CLKOUT_CTL, 0x00}, | ||
61 | {CS43130_ASP_NUM_1, 0x01}, | ||
62 | {CS43130_ASP_NUM_2, 0x00}, | ||
63 | {CS43130_ASP_DEN_1, 0x08}, | ||
64 | {CS43130_ASP_DEN_2, 0x00}, | ||
65 | {CS43130_ASP_LRCK_HI_TIME_1, 0x1F}, | ||
66 | {CS43130_ASP_LRCK_HI_TIME_2, 0x00}, | ||
67 | {CS43130_ASP_LRCK_PERIOD_1, 0x3F}, | ||
68 | {CS43130_ASP_LRCK_PERIOD_2, 0x00}, | ||
69 | {CS43130_ASP_CLOCK_CONF, 0x0C}, | ||
70 | {CS43130_ASP_FRAME_CONF, 0x0A}, | ||
71 | {CS43130_XSP_NUM_1, 0x01}, | ||
72 | {CS43130_XSP_NUM_2, 0x00}, | ||
73 | {CS43130_XSP_DEN_1, 0x02}, | ||
74 | {CS43130_XSP_DEN_2, 0x00}, | ||
75 | {CS43130_XSP_LRCK_HI_TIME_1, 0x1F}, | ||
76 | {CS43130_XSP_LRCK_HI_TIME_2, 0x00}, | ||
77 | {CS43130_XSP_LRCK_PERIOD_1, 0x3F}, | ||
78 | {CS43130_XSP_LRCK_PERIOD_2, 0x00}, | ||
79 | {CS43130_XSP_CLOCK_CONF, 0x0C}, | ||
80 | {CS43130_XSP_FRAME_CONF, 0x0A}, | ||
81 | {CS43130_ASP_CH_1_LOC, 0x00}, | ||
82 | {CS43130_ASP_CH_2_LOC, 0x00}, | ||
83 | {CS43130_ASP_CH_1_SZ_EN, 0x06}, | ||
84 | {CS43130_ASP_CH_2_SZ_EN, 0x0E}, | ||
85 | {CS43130_XSP_CH_1_LOC, 0x00}, | ||
86 | {CS43130_XSP_CH_2_LOC, 0x00}, | ||
87 | {CS43130_XSP_CH_1_SZ_EN, 0x06}, | ||
88 | {CS43130_XSP_CH_2_SZ_EN, 0x0E}, | ||
89 | {CS43130_DSD_VOL_B, 0x78}, | ||
90 | {CS43130_DSD_VOL_A, 0x78}, | ||
91 | {CS43130_DSD_PATH_CTL_1, 0xA8}, | ||
92 | {CS43130_DSD_INT_CFG, 0x00}, | ||
93 | {CS43130_DSD_PATH_CTL_2, 0x02}, | ||
94 | {CS43130_DSD_PCM_MIX_CTL, 0x00}, | ||
95 | {CS43130_DSD_PATH_CTL_3, 0x40}, | ||
96 | {CS43130_HP_OUT_CTL_1, 0x30}, | ||
97 | {CS43130_PCM_FILT_OPT, 0x02}, | ||
98 | {CS43130_PCM_VOL_B, 0x78}, | ||
99 | {CS43130_PCM_VOL_A, 0x78}, | ||
100 | {CS43130_PCM_PATH_CTL_1, 0xA8}, | ||
101 | {CS43130_PCM_PATH_CTL_2, 0x00}, | ||
102 | {CS43130_CLASS_H_CTL, 0x1E}, | ||
103 | {CS43130_HP_DETECT, 0x04}, | ||
104 | {CS43130_HP_LOAD_1, 0x00}, | ||
105 | {CS43130_HP_MEAS_LOAD_1, 0x00}, | ||
106 | {CS43130_HP_MEAS_LOAD_2, 0x00}, | ||
107 | {CS43130_INT_MASK_1, 0xFF}, | ||
108 | {CS43130_INT_MASK_2, 0xFF}, | ||
109 | {CS43130_INT_MASK_3, 0xFF}, | ||
110 | {CS43130_INT_MASK_4, 0xFF}, | ||
111 | {CS43130_INT_MASK_5, 0xFF}, | ||
112 | }; | ||
113 | |||
114 | static bool cs43130_volatile_register(struct device *dev, unsigned int reg) | ||
115 | { | ||
116 | switch (reg) { | ||
117 | case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5: | ||
118 | case CS43130_HP_DC_STAT_1 ... CS43130_HP_DC_STAT_2: | ||
119 | case CS43130_HP_AC_STAT_1 ... CS43130_HP_AC_STAT_2: | ||
120 | return true; | ||
121 | default: | ||
122 | return false; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static bool cs43130_readable_register(struct device *dev, unsigned int reg) | ||
127 | { | ||
128 | switch (reg) { | ||
129 | case CS43130_DEVID_AB ... CS43130_SYS_CLK_CTL_1: | ||
130 | case CS43130_SP_SRATE ... CS43130_PAD_INT_CFG: | ||
131 | case CS43130_PWDN_CTL: | ||
132 | case CS43130_CRYSTAL_SET: | ||
133 | case CS43130_PLL_SET_1 ... CS43130_PLL_SET_5: | ||
134 | case CS43130_PLL_SET_6: | ||
135 | case CS43130_PLL_SET_7: | ||
136 | case CS43130_PLL_SET_8: | ||
137 | case CS43130_PLL_SET_9: | ||
138 | case CS43130_PLL_SET_10: | ||
139 | case CS43130_CLKOUT_CTL: | ||
140 | case CS43130_ASP_NUM_1 ... CS43130_ASP_FRAME_CONF: | ||
141 | case CS43130_XSP_NUM_1 ... CS43130_XSP_FRAME_CONF: | ||
142 | case CS43130_ASP_CH_1_LOC: | ||
143 | case CS43130_ASP_CH_2_LOC: | ||
144 | case CS43130_ASP_CH_1_SZ_EN: | ||
145 | case CS43130_ASP_CH_2_SZ_EN: | ||
146 | case CS43130_XSP_CH_1_LOC: | ||
147 | case CS43130_XSP_CH_2_LOC: | ||
148 | case CS43130_XSP_CH_1_SZ_EN: | ||
149 | case CS43130_XSP_CH_2_SZ_EN: | ||
150 | case CS43130_DSD_VOL_B ... CS43130_DSD_PATH_CTL_3: | ||
151 | case CS43130_HP_OUT_CTL_1: | ||
152 | case CS43130_PCM_FILT_OPT ... CS43130_PCM_PATH_CTL_2: | ||
153 | case CS43130_CLASS_H_CTL: | ||
154 | case CS43130_HP_DETECT: | ||
155 | case CS43130_HP_STATUS: | ||
156 | case CS43130_HP_LOAD_1: | ||
157 | case CS43130_HP_MEAS_LOAD_1: | ||
158 | case CS43130_HP_MEAS_LOAD_2: | ||
159 | case CS43130_HP_DC_STAT_1: | ||
160 | case CS43130_HP_DC_STAT_2: | ||
161 | case CS43130_HP_AC_STAT_1: | ||
162 | case CS43130_HP_AC_STAT_2: | ||
163 | case CS43130_HP_LOAD_STAT: | ||
164 | case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5: | ||
165 | case CS43130_INT_MASK_1 ... CS43130_INT_MASK_5: | ||
166 | return true; | ||
167 | default: | ||
168 | return false; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | static bool cs43130_precious_register(struct device *dev, unsigned int reg) | ||
173 | { | ||
174 | switch (reg) { | ||
175 | case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5: | ||
176 | return true; | ||
177 | default: | ||
178 | return false; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | struct cs43130_pll_params { | ||
183 | unsigned int pll_in; | ||
184 | u8 sclk_prediv; | ||
185 | u8 pll_div_int; | ||
186 | u32 pll_div_frac; | ||
187 | u8 pll_mode; | ||
188 | u8 pll_divout; | ||
189 | unsigned int pll_out; | ||
190 | u8 pll_cal_ratio; | ||
191 | }; | ||
192 | |||
193 | static const struct cs43130_pll_params pll_ratio_table[] = { | ||
194 | {9600000, 0x02, 0x49, 0x800000, 0x00, 0x08, 22579200, 151}, | ||
195 | {9600000, 0x02, 0x50, 0x000000, 0x00, 0x08, 24576000, 164}, | ||
196 | |||
197 | {11289600, 0x02, 0X40, 0, 0x01, 0x08, 22579200, 128}, | ||
198 | {11289600, 0x02, 0x44, 0x06F700, 0x0, 0x08, 24576000, 139}, | ||
199 | |||
200 | {12000000, 0x02, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120}, | ||
201 | {12000000, 0x02, 0x40, 0x000000, 0x00, 0x08, 24576000, 131}, | ||
202 | |||
203 | {12288000, 0x02, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118}, | ||
204 | {12288000, 0x02, 0x40, 0x000000, 0x01, 0x08, 24576000, 128}, | ||
205 | |||
206 | {13000000, 0x02, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111}, | ||
207 | {13000000, 0x02, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121}, | ||
208 | |||
209 | {19200000, 0x03, 0x49, 0x800000, 0x00, 0x08, 22579200, 151}, | ||
210 | {19200000, 0x03, 0x50, 0x000000, 0x00, 0x08, 24576000, 164}, | ||
211 | |||
212 | {22579200, 0, 0, 0, 0, 0, 22579200, 0}, | ||
213 | {22579200, 0x03, 0x44, 0x06F700, 0x00, 0x08, 24576000, 139}, | ||
214 | |||
215 | {24000000, 0x03, 0x49, 0x800000, 0x00, 0x0A, 22579200, 120}, | ||
216 | {24000000, 0x03, 0x40, 0x000000, 0x00, 0x08, 24576000, 131}, | ||
217 | |||
218 | {24576000, 0x03, 0x49, 0x800000, 0x01, 0x0A, 22579200, 118}, | ||
219 | {24576000, 0, 0, 0, 0, 0, 24576000, 0}, | ||
220 | |||
221 | {26000000, 0x03, 0x45, 0x797680, 0x01, 0x0A, 22579200, 111}, | ||
222 | {26000000, 0x03, 0x3C, 0x7EA940, 0x01, 0x08, 24576000, 121}, | ||
223 | }; | ||
224 | |||
225 | static const struct cs43130_pll_params *cs43130_get_pll_table( | ||
226 | unsigned int freq_in, unsigned int freq_out) | ||
227 | { | ||
228 | int i; | ||
229 | |||
230 | for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { | ||
231 | if (pll_ratio_table[i].pll_in == freq_in && | ||
232 | pll_ratio_table[i].pll_out == freq_out) | ||
233 | return &pll_ratio_table[i]; | ||
234 | } | ||
235 | |||
236 | return NULL; | ||
237 | } | ||
238 | |||
239 | static int cs43130_pll_config(struct snd_soc_codec *codec) | ||
240 | { | ||
241 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
242 | const struct cs43130_pll_params *pll_entry; | ||
243 | |||
244 | dev_dbg(codec->dev, "cs43130->mclk = %u, cs43130->mclk_int = %u\n", | ||
245 | cs43130->mclk, cs43130->mclk_int); | ||
246 | |||
247 | pll_entry = cs43130_get_pll_table(cs43130->mclk, cs43130->mclk_int); | ||
248 | if (!pll_entry) | ||
249 | return -EINVAL; | ||
250 | |||
251 | if (pll_entry->pll_cal_ratio == 0) { | ||
252 | regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1, | ||
253 | CS43130_PLL_START_MASK, 0); | ||
254 | |||
255 | cs43130->pll_bypass = true; | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | cs43130->pll_bypass = false; | ||
260 | |||
261 | regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_2, | ||
262 | CS43130_PLL_DIV_DATA_MASK, | ||
263 | pll_entry->pll_div_frac >> | ||
264 | CS43130_PLL_DIV_FRAC_0_DATA_SHIFT); | ||
265 | regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_3, | ||
266 | CS43130_PLL_DIV_DATA_MASK, | ||
267 | pll_entry->pll_div_frac >> | ||
268 | CS43130_PLL_DIV_FRAC_1_DATA_SHIFT); | ||
269 | regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_4, | ||
270 | CS43130_PLL_DIV_DATA_MASK, | ||
271 | pll_entry->pll_div_frac >> | ||
272 | CS43130_PLL_DIV_FRAC_2_DATA_SHIFT); | ||
273 | regmap_write(cs43130->regmap, CS43130_PLL_SET_5, | ||
274 | pll_entry->pll_div_int); | ||
275 | regmap_write(cs43130->regmap, CS43130_PLL_SET_6, pll_entry->pll_divout); | ||
276 | regmap_write(cs43130->regmap, CS43130_PLL_SET_7, | ||
277 | pll_entry->pll_cal_ratio); | ||
278 | regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_8, | ||
279 | CS43130_PLL_MODE_MASK, | ||
280 | pll_entry->pll_mode << CS43130_PLL_MODE_SHIFT); | ||
281 | regmap_write(cs43130->regmap, CS43130_PLL_SET_9, | ||
282 | pll_entry->sclk_prediv); | ||
283 | regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_1, | ||
284 | CS43130_PLL_START_MASK, 1); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int cs43130_set_pll(struct snd_soc_codec *codec, int pll_id, int source, | ||
290 | unsigned int freq_in, unsigned int freq_out) | ||
291 | { | ||
292 | int ret = 0; | ||
293 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
294 | |||
295 | switch (freq_in) { | ||
296 | case 9600000: | ||
297 | case 11289600: | ||
298 | case 12000000: | ||
299 | case 12288000: | ||
300 | case 13000000: | ||
301 | case 19200000: | ||
302 | case 22579200: | ||
303 | case 24000000: | ||
304 | case 24576000: | ||
305 | case 26000000: | ||
306 | cs43130->mclk = freq_in; | ||
307 | break; | ||
308 | default: | ||
309 | dev_err(codec->dev, | ||
310 | "unsupported pll input reference clock:%d\n", freq_in); | ||
311 | return -EINVAL; | ||
312 | } | ||
313 | |||
314 | switch (freq_out) { | ||
315 | case 22579200: | ||
316 | cs43130->mclk_int = freq_out; | ||
317 | break; | ||
318 | case 24576000: | ||
319 | cs43130->mclk_int = freq_out; | ||
320 | break; | ||
321 | default: | ||
322 | dev_err(codec->dev, | ||
323 | "unsupported pll output ref clock: %u\n", freq_out); | ||
324 | return -EINVAL; | ||
325 | } | ||
326 | |||
327 | ret = cs43130_pll_config(codec); | ||
328 | dev_dbg(codec->dev, "cs43130->pll_bypass = %d", cs43130->pll_bypass); | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | static int cs43130_change_clksrc(struct snd_soc_codec *codec, | ||
333 | enum cs43130_mclk_src_sel src) | ||
334 | { | ||
335 | int ret; | ||
336 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
337 | int mclk_int_decoded; | ||
338 | |||
339 | if (src == cs43130->mclk_int_src) { | ||
340 | /* clk source has not changed */ | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | switch (cs43130->mclk_int) { | ||
345 | case CS43130_MCLK_22M: | ||
346 | mclk_int_decoded = CS43130_MCLK_22P5; | ||
347 | break; | ||
348 | case CS43130_MCLK_24M: | ||
349 | mclk_int_decoded = CS43130_MCLK_24P5; | ||
350 | break; | ||
351 | default: | ||
352 | dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", cs43130->mclk_int); | ||
353 | return -EINVAL; | ||
354 | } | ||
355 | |||
356 | switch (src) { | ||
357 | case CS43130_MCLK_SRC_EXT: | ||
358 | cs43130->pll_bypass = true; | ||
359 | cs43130->mclk_int_src = CS43130_MCLK_SRC_EXT; | ||
360 | if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) { | ||
361 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
362 | CS43130_PDN_XTAL_MASK, | ||
363 | 1 << CS43130_PDN_XTAL_SHIFT); | ||
364 | } else { | ||
365 | reinit_completion(&cs43130->xtal_rdy); | ||
366 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
367 | CS43130_XTAL_RDY_INT_MASK, 0); | ||
368 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
369 | CS43130_PDN_XTAL_MASK, 0); | ||
370 | ret = wait_for_completion_timeout(&cs43130->xtal_rdy, | ||
371 | msecs_to_jiffies(100)); | ||
372 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
373 | CS43130_XTAL_RDY_INT_MASK, | ||
374 | 1 << CS43130_XTAL_RDY_INT_SHIFT); | ||
375 | if (ret == 0) { | ||
376 | dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n"); | ||
377 | return -ETIMEDOUT; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, | ||
382 | CS43130_MCLK_SRC_SEL_MASK, | ||
383 | src << CS43130_MCLK_SRC_SEL_SHIFT); | ||
384 | regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, | ||
385 | CS43130_MCLK_INT_MASK, | ||
386 | mclk_int_decoded << CS43130_MCLK_INT_SHIFT); | ||
387 | usleep_range(150, 200); | ||
388 | |||
389 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
390 | CS43130_PDN_PLL_MASK, | ||
391 | 1 << CS43130_PDN_PLL_SHIFT); | ||
392 | break; | ||
393 | case CS43130_MCLK_SRC_PLL: | ||
394 | cs43130->pll_bypass = false; | ||
395 | cs43130->mclk_int_src = CS43130_MCLK_SRC_PLL; | ||
396 | if (cs43130->xtal_ibias == CS43130_XTAL_UNUSED) { | ||
397 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
398 | CS43130_PDN_XTAL_MASK, | ||
399 | 1 << CS43130_PDN_XTAL_SHIFT); | ||
400 | } else { | ||
401 | reinit_completion(&cs43130->xtal_rdy); | ||
402 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
403 | CS43130_XTAL_RDY_INT_MASK, 0); | ||
404 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
405 | CS43130_PDN_XTAL_MASK, 0); | ||
406 | ret = wait_for_completion_timeout(&cs43130->xtal_rdy, | ||
407 | msecs_to_jiffies(100)); | ||
408 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
409 | CS43130_XTAL_RDY_INT_MASK, | ||
410 | 1 << CS43130_XTAL_RDY_INT_SHIFT); | ||
411 | if (ret == 0) { | ||
412 | dev_err(codec->dev, "Timeout waiting for XTAL_READY interrupt\n"); | ||
413 | return -ETIMEDOUT; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | reinit_completion(&cs43130->pll_rdy); | ||
418 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
419 | CS43130_PLL_RDY_INT_MASK, 0); | ||
420 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
421 | CS43130_PDN_PLL_MASK, 0); | ||
422 | ret = wait_for_completion_timeout(&cs43130->pll_rdy, | ||
423 | msecs_to_jiffies(100)); | ||
424 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
425 | CS43130_PLL_RDY_INT_MASK, | ||
426 | 1 << CS43130_PLL_RDY_INT_SHIFT); | ||
427 | if (ret == 0) { | ||
428 | dev_err(codec->dev, "Timeout waiting for PLL_READY interrupt\n"); | ||
429 | return -ETIMEDOUT; | ||
430 | } | ||
431 | |||
432 | regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, | ||
433 | CS43130_MCLK_SRC_SEL_MASK, | ||
434 | src << CS43130_MCLK_SRC_SEL_SHIFT); | ||
435 | regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, | ||
436 | CS43130_MCLK_INT_MASK, | ||
437 | mclk_int_decoded << CS43130_MCLK_INT_SHIFT); | ||
438 | usleep_range(150, 200); | ||
439 | break; | ||
440 | case CS43130_MCLK_SRC_RCO: | ||
441 | cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; | ||
442 | |||
443 | regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, | ||
444 | CS43130_MCLK_SRC_SEL_MASK, | ||
445 | src << CS43130_MCLK_SRC_SEL_SHIFT); | ||
446 | regmap_update_bits(cs43130->regmap, CS43130_SYS_CLK_CTL_1, | ||
447 | CS43130_MCLK_INT_MASK, | ||
448 | CS43130_MCLK_22P5 << CS43130_MCLK_INT_SHIFT); | ||
449 | usleep_range(150, 200); | ||
450 | |||
451 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
452 | CS43130_PDN_XTAL_MASK, | ||
453 | 1 << CS43130_PDN_XTAL_SHIFT); | ||
454 | regmap_update_bits(cs43130->regmap, CS43130_PWDN_CTL, | ||
455 | CS43130_PDN_PLL_MASK, | ||
456 | 1 << CS43130_PDN_PLL_SHIFT); | ||
457 | break; | ||
458 | default: | ||
459 | dev_err(codec->dev, "Invalid MCLK source value\n"); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static const struct cs43130_bitwidth_map cs43130_bitwidth_table[] = { | ||
467 | {8, CS43130_SP_BIT_SIZE_8, CS43130_CH_BIT_SIZE_8}, | ||
468 | {16, CS43130_SP_BIT_SIZE_16, CS43130_CH_BIT_SIZE_16}, | ||
469 | {24, CS43130_SP_BIT_SIZE_24, CS43130_CH_BIT_SIZE_24}, | ||
470 | {32, CS43130_SP_BIT_SIZE_32, CS43130_CH_BIT_SIZE_32}, | ||
471 | }; | ||
472 | |||
473 | static const struct cs43130_bitwidth_map *cs43130_get_bitwidth_table( | ||
474 | unsigned int bitwidth) | ||
475 | { | ||
476 | int i; | ||
477 | |||
478 | for (i = 0; i < ARRAY_SIZE(cs43130_bitwidth_table); i++) { | ||
479 | if (cs43130_bitwidth_table[i].bitwidth == bitwidth) | ||
480 | return &cs43130_bitwidth_table[i]; | ||
481 | } | ||
482 | |||
483 | return NULL; | ||
484 | } | ||
485 | |||
486 | static int cs43130_set_bitwidth(int dai_id, unsigned int bitwidth_dai, | ||
487 | struct regmap *regmap) | ||
488 | { | ||
489 | const struct cs43130_bitwidth_map *bw_map; | ||
490 | |||
491 | bw_map = cs43130_get_bitwidth_table(bitwidth_dai); | ||
492 | if (!bw_map) | ||
493 | return -EINVAL; | ||
494 | |||
495 | switch (dai_id) { | ||
496 | case CS43130_ASP_PCM_DAI: | ||
497 | case CS43130_ASP_DOP_DAI: | ||
498 | regmap_update_bits(regmap, CS43130_ASP_CH_1_SZ_EN, | ||
499 | CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); | ||
500 | regmap_update_bits(regmap, CS43130_ASP_CH_2_SZ_EN, | ||
501 | CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); | ||
502 | regmap_update_bits(regmap, CS43130_SP_BITSIZE, | ||
503 | CS43130_ASP_BITSIZE_MASK, bw_map->sp_bit); | ||
504 | break; | ||
505 | case CS43130_XSP_DOP_DAI: | ||
506 | regmap_update_bits(regmap, CS43130_XSP_CH_1_SZ_EN, | ||
507 | CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); | ||
508 | regmap_update_bits(regmap, CS43130_XSP_CH_2_SZ_EN, | ||
509 | CS43130_CH_BITSIZE_MASK, bw_map->ch_bit); | ||
510 | regmap_update_bits(regmap, CS43130_SP_BITSIZE, | ||
511 | CS43130_XSP_BITSIZE_MASK, bw_map->sp_bit << | ||
512 | CS43130_XSP_BITSIZE_SHIFT); | ||
513 | break; | ||
514 | default: | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static const struct cs43130_rate_map cs43130_rate_table[] = { | ||
522 | {32000, CS43130_ASP_SPRATE_32K}, | ||
523 | {44100, CS43130_ASP_SPRATE_44_1K}, | ||
524 | {48000, CS43130_ASP_SPRATE_48K}, | ||
525 | {88200, CS43130_ASP_SPRATE_88_2K}, | ||
526 | {96000, CS43130_ASP_SPRATE_96K}, | ||
527 | {176400, CS43130_ASP_SPRATE_176_4K}, | ||
528 | {192000, CS43130_ASP_SPRATE_192K}, | ||
529 | {352800, CS43130_ASP_SPRATE_352_8K}, | ||
530 | {384000, CS43130_ASP_SPRATE_384K}, | ||
531 | }; | ||
532 | |||
533 | static const struct cs43130_rate_map *cs43130_get_rate_table(int fs) | ||
534 | { | ||
535 | int i; | ||
536 | |||
537 | for (i = 0; i < ARRAY_SIZE(cs43130_rate_table); i++) { | ||
538 | if (cs43130_rate_table[i].fs == fs) | ||
539 | return &cs43130_rate_table[i]; | ||
540 | } | ||
541 | |||
542 | return NULL; | ||
543 | } | ||
544 | |||
545 | static const struct cs43130_clk_gen *cs43130_get_clk_gen(int mclk_int, int fs, | ||
546 | const struct cs43130_clk_gen *clk_gen_table, int len_clk_gen_table) | ||
547 | { | ||
548 | int i; | ||
549 | |||
550 | for (i = 0; i < len_clk_gen_table; i++) { | ||
551 | if (clk_gen_table[i].mclk_int == mclk_int && | ||
552 | clk_gen_table[i].fs == fs) | ||
553 | return &clk_gen_table[i]; | ||
554 | } | ||
555 | |||
556 | return NULL; | ||
557 | } | ||
558 | |||
559 | static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, | ||
560 | struct snd_pcm_hw_params *params, | ||
561 | struct cs43130_private *cs43130) | ||
562 | { | ||
563 | u16 frm_size; | ||
564 | u16 hi_size; | ||
565 | u8 frm_delay; | ||
566 | u8 frm_phase; | ||
567 | u8 frm_data; | ||
568 | u8 sclk_edge; | ||
569 | u8 lrck_edge; | ||
570 | u8 clk_data; | ||
571 | u8 loc_ch1; | ||
572 | u8 loc_ch2; | ||
573 | u8 dai_mode_val; | ||
574 | const struct cs43130_clk_gen *clk_gen; | ||
575 | |||
576 | switch (cs43130->dais[dai_id].dai_format) { | ||
577 | case SND_SOC_DAIFMT_I2S: | ||
578 | hi_size = bitwidth_sclk; | ||
579 | frm_delay = 2; | ||
580 | frm_phase = 0; | ||
581 | break; | ||
582 | case SND_SOC_DAIFMT_LEFT_J: | ||
583 | hi_size = bitwidth_sclk; | ||
584 | frm_delay = 2; | ||
585 | frm_phase = 1; | ||
586 | break; | ||
587 | case SND_SOC_DAIFMT_DSP_A: | ||
588 | hi_size = 1; | ||
589 | frm_delay = 2; | ||
590 | frm_phase = 1; | ||
591 | break; | ||
592 | case SND_SOC_DAIFMT_DSP_B: | ||
593 | hi_size = 1; | ||
594 | frm_delay = 0; | ||
595 | frm_phase = 1; | ||
596 | break; | ||
597 | default: | ||
598 | return -EINVAL; | ||
599 | } | ||
600 | |||
601 | switch (cs43130->dais[dai_id].dai_mode) { | ||
602 | case SND_SOC_DAIFMT_CBS_CFS: | ||
603 | dai_mode_val = 0; | ||
604 | break; | ||
605 | case SND_SOC_DAIFMT_CBM_CFM: | ||
606 | dai_mode_val = 1; | ||
607 | break; | ||
608 | default: | ||
609 | return -EINVAL; | ||
610 | } | ||
611 | |||
612 | frm_size = bitwidth_sclk * params_channels(params); | ||
613 | sclk_edge = 1; | ||
614 | lrck_edge = 0; | ||
615 | loc_ch1 = 0; | ||
616 | loc_ch2 = bitwidth_sclk * (params_channels(params) - 1); | ||
617 | |||
618 | frm_data = frm_delay & CS43130_SP_FSD_MASK; | ||
619 | frm_data |= (frm_phase << CS43130_SP_STP_SHIFT) & CS43130_SP_STP_MASK; | ||
620 | |||
621 | clk_data = lrck_edge & CS43130_SP_LCPOL_IN_MASK; | ||
622 | clk_data |= (lrck_edge << CS43130_SP_LCPOL_OUT_SHIFT) & | ||
623 | CS43130_SP_LCPOL_OUT_MASK; | ||
624 | clk_data |= (sclk_edge << CS43130_SP_SCPOL_IN_SHIFT) & | ||
625 | CS43130_SP_SCPOL_IN_MASK; | ||
626 | clk_data |= (sclk_edge << CS43130_SP_SCPOL_OUT_SHIFT) & | ||
627 | CS43130_SP_SCPOL_OUT_MASK; | ||
628 | clk_data |= (dai_mode_val << CS43130_SP_MODE_SHIFT) & | ||
629 | CS43130_SP_MODE_MASK; | ||
630 | |||
631 | switch (dai_id) { | ||
632 | case CS43130_ASP_PCM_DAI: | ||
633 | case CS43130_ASP_DOP_DAI: | ||
634 | regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_1, | ||
635 | CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> | ||
636 | CS43130_SP_LCPR_LSB_DATA_SHIFT); | ||
637 | regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_PERIOD_2, | ||
638 | CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> | ||
639 | CS43130_SP_LCPR_MSB_DATA_SHIFT); | ||
640 | regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_1, | ||
641 | CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> | ||
642 | CS43130_SP_LCHI_LSB_DATA_SHIFT); | ||
643 | regmap_update_bits(cs43130->regmap, CS43130_ASP_LRCK_HI_TIME_2, | ||
644 | CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> | ||
645 | CS43130_SP_LCHI_MSB_DATA_SHIFT); | ||
646 | regmap_write(cs43130->regmap, CS43130_ASP_FRAME_CONF, frm_data); | ||
647 | regmap_write(cs43130->regmap, CS43130_ASP_CH_1_LOC, loc_ch1); | ||
648 | regmap_write(cs43130->regmap, CS43130_ASP_CH_2_LOC, loc_ch2); | ||
649 | regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_1_SZ_EN, | ||
650 | CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); | ||
651 | regmap_update_bits(cs43130->regmap, CS43130_ASP_CH_2_SZ_EN, | ||
652 | CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); | ||
653 | regmap_write(cs43130->regmap, CS43130_ASP_CLOCK_CONF, clk_data); | ||
654 | break; | ||
655 | case CS43130_XSP_DOP_DAI: | ||
656 | regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_1, | ||
657 | CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> | ||
658 | CS43130_SP_LCPR_LSB_DATA_SHIFT); | ||
659 | regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_PERIOD_2, | ||
660 | CS43130_SP_LCPR_DATA_MASK, (frm_size - 1) >> | ||
661 | CS43130_SP_LCPR_MSB_DATA_SHIFT); | ||
662 | regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_1, | ||
663 | CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> | ||
664 | CS43130_SP_LCHI_LSB_DATA_SHIFT); | ||
665 | regmap_update_bits(cs43130->regmap, CS43130_XSP_LRCK_HI_TIME_2, | ||
666 | CS43130_SP_LCHI_DATA_MASK, (hi_size - 1) >> | ||
667 | CS43130_SP_LCHI_MSB_DATA_SHIFT); | ||
668 | regmap_write(cs43130->regmap, CS43130_XSP_FRAME_CONF, frm_data); | ||
669 | regmap_write(cs43130->regmap, CS43130_XSP_CH_1_LOC, loc_ch1); | ||
670 | regmap_write(cs43130->regmap, CS43130_XSP_CH_2_LOC, loc_ch2); | ||
671 | regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_1_SZ_EN, | ||
672 | CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); | ||
673 | regmap_update_bits(cs43130->regmap, CS43130_XSP_CH_2_SZ_EN, | ||
674 | CS43130_CH_EN_MASK, 1 << CS43130_CH_EN_SHIFT); | ||
675 | regmap_write(cs43130->regmap, CS43130_XSP_CLOCK_CONF, clk_data); | ||
676 | break; | ||
677 | default: | ||
678 | return -EINVAL; | ||
679 | } | ||
680 | |||
681 | switch (frm_size) { | ||
682 | case 16: | ||
683 | clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, | ||
684 | params_rate(params), | ||
685 | cs43130_16_clk_gen, | ||
686 | ARRAY_SIZE(cs43130_16_clk_gen)); | ||
687 | break; | ||
688 | case 32: | ||
689 | clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, | ||
690 | params_rate(params), | ||
691 | cs43130_32_clk_gen, | ||
692 | ARRAY_SIZE(cs43130_32_clk_gen)); | ||
693 | break; | ||
694 | case 48: | ||
695 | clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, | ||
696 | params_rate(params), | ||
697 | cs43130_48_clk_gen, | ||
698 | ARRAY_SIZE(cs43130_48_clk_gen)); | ||
699 | break; | ||
700 | case 64: | ||
701 | clk_gen = cs43130_get_clk_gen(cs43130->mclk_int, | ||
702 | params_rate(params), | ||
703 | cs43130_64_clk_gen, | ||
704 | ARRAY_SIZE(cs43130_64_clk_gen)); | ||
705 | break; | ||
706 | default: | ||
707 | return -EINVAL; | ||
708 | } | ||
709 | |||
710 | if (!clk_gen) | ||
711 | return -EINVAL; | ||
712 | |||
713 | switch (dai_id) { | ||
714 | case CS43130_ASP_PCM_DAI: | ||
715 | case CS43130_ASP_DOP_DAI: | ||
716 | regmap_write(cs43130->regmap, CS43130_ASP_DEN_1, | ||
717 | (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> | ||
718 | CS43130_SP_M_LSB_DATA_SHIFT); | ||
719 | regmap_write(cs43130->regmap, CS43130_ASP_DEN_2, | ||
720 | (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> | ||
721 | CS43130_SP_M_MSB_DATA_SHIFT); | ||
722 | regmap_write(cs43130->regmap, CS43130_ASP_NUM_1, | ||
723 | (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> | ||
724 | CS43130_SP_N_LSB_DATA_SHIFT); | ||
725 | regmap_write(cs43130->regmap, CS43130_ASP_NUM_2, | ||
726 | (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> | ||
727 | CS43130_SP_N_MSB_DATA_SHIFT); | ||
728 | break; | ||
729 | case CS43130_XSP_DOP_DAI: | ||
730 | regmap_write(cs43130->regmap, CS43130_XSP_DEN_1, | ||
731 | (clk_gen->den & CS43130_SP_M_LSB_DATA_MASK) >> | ||
732 | CS43130_SP_M_LSB_DATA_SHIFT); | ||
733 | regmap_write(cs43130->regmap, CS43130_XSP_DEN_2, | ||
734 | (clk_gen->den & CS43130_SP_M_MSB_DATA_MASK) >> | ||
735 | CS43130_SP_M_MSB_DATA_SHIFT); | ||
736 | regmap_write(cs43130->regmap, CS43130_XSP_NUM_1, | ||
737 | (clk_gen->num & CS43130_SP_N_LSB_DATA_MASK) >> | ||
738 | CS43130_SP_N_LSB_DATA_SHIFT); | ||
739 | regmap_write(cs43130->regmap, CS43130_XSP_NUM_2, | ||
740 | (clk_gen->num & CS43130_SP_N_MSB_DATA_MASK) >> | ||
741 | CS43130_SP_N_MSB_DATA_SHIFT); | ||
742 | break; | ||
743 | default: | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int cs43130_pcm_dsd_mix(bool en, struct regmap *regmap) | ||
751 | { | ||
752 | if (en) { | ||
753 | regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, | ||
754 | CS43130_MIX_PCM_PREP_MASK, | ||
755 | 1 << CS43130_MIX_PCM_PREP_SHIFT); | ||
756 | usleep_range(6000, 6050); | ||
757 | regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, | ||
758 | CS43130_MIX_PCM_DSD_MASK, | ||
759 | 1 << CS43130_MIX_PCM_DSD_SHIFT); | ||
760 | } else { | ||
761 | regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, | ||
762 | CS43130_MIX_PCM_DSD_MASK, | ||
763 | 0 << CS43130_MIX_PCM_DSD_SHIFT); | ||
764 | usleep_range(1600, 1650); | ||
765 | regmap_update_bits(regmap, CS43130_DSD_PCM_MIX_CTL, | ||
766 | CS43130_MIX_PCM_PREP_MASK, | ||
767 | 0 << CS43130_MIX_PCM_PREP_SHIFT); | ||
768 | } | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, | ||
774 | struct snd_pcm_hw_params *params, | ||
775 | struct snd_soc_dai *dai) | ||
776 | { | ||
777 | struct snd_soc_codec *codec = dai->codec; | ||
778 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
779 | unsigned int required_clk; | ||
780 | u8 dsd_speed; | ||
781 | |||
782 | mutex_lock(&cs43130->clk_mutex); | ||
783 | if (!cs43130->clk_req) { | ||
784 | /* no DAI is currently using clk */ | ||
785 | if (!(CS43130_MCLK_22M % params_rate(params))) | ||
786 | required_clk = CS43130_MCLK_22M; | ||
787 | else | ||
788 | required_clk = CS43130_MCLK_24M; | ||
789 | |||
790 | cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk); | ||
791 | if (cs43130->pll_bypass) | ||
792 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT); | ||
793 | else | ||
794 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL); | ||
795 | } | ||
796 | |||
797 | cs43130->clk_req++; | ||
798 | if (cs43130->clk_req == 2) | ||
799 | cs43130_pcm_dsd_mix(true, cs43130->regmap); | ||
800 | mutex_unlock(&cs43130->clk_mutex); | ||
801 | |||
802 | switch (params_rate(params)) { | ||
803 | case 176400: | ||
804 | dsd_speed = 0; | ||
805 | break; | ||
806 | case 352800: | ||
807 | dsd_speed = 1; | ||
808 | break; | ||
809 | default: | ||
810 | dev_err(codec->dev, "Rate(%u) not supported\n", | ||
811 | params_rate(params)); | ||
812 | return -EINVAL; | ||
813 | } | ||
814 | |||
815 | if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM) | ||
816 | regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG, | ||
817 | CS43130_DSD_MASTER, CS43130_DSD_MASTER); | ||
818 | else | ||
819 | regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG, | ||
820 | CS43130_DSD_MASTER, 0); | ||
821 | |||
822 | regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, | ||
823 | CS43130_DSD_SPEED_MASK, | ||
824 | dsd_speed << CS43130_DSD_SPEED_SHIFT); | ||
825 | regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, | ||
826 | CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_DSD << | ||
827 | CS43130_DSD_SRC_SHIFT); | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | static int cs43130_hw_params(struct snd_pcm_substream *substream, | ||
833 | struct snd_pcm_hw_params *params, | ||
834 | struct snd_soc_dai *dai) | ||
835 | { | ||
836 | struct snd_soc_codec *codec = dai->codec; | ||
837 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
838 | const struct cs43130_rate_map *rate_map; | ||
839 | unsigned int sclk = cs43130->dais[dai->id].sclk; | ||
840 | unsigned int bitwidth_sclk; | ||
841 | unsigned int bitwidth_dai = (unsigned int)(params_width(params)); | ||
842 | unsigned int required_clk; | ||
843 | u8 dsd_speed; | ||
844 | |||
845 | mutex_lock(&cs43130->clk_mutex); | ||
846 | if (!cs43130->clk_req) { | ||
847 | /* no DAI is currently using clk */ | ||
848 | if (!(CS43130_MCLK_22M % params_rate(params))) | ||
849 | required_clk = CS43130_MCLK_22M; | ||
850 | else | ||
851 | required_clk = CS43130_MCLK_24M; | ||
852 | |||
853 | cs43130_set_pll(codec, 0, 0, cs43130->mclk, required_clk); | ||
854 | if (cs43130->pll_bypass) | ||
855 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT); | ||
856 | else | ||
857 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL); | ||
858 | } | ||
859 | |||
860 | cs43130->clk_req++; | ||
861 | if (cs43130->clk_req == 2) | ||
862 | cs43130_pcm_dsd_mix(true, cs43130->regmap); | ||
863 | mutex_unlock(&cs43130->clk_mutex); | ||
864 | |||
865 | switch (dai->id) { | ||
866 | case CS43130_ASP_DOP_DAI: | ||
867 | case CS43130_XSP_DOP_DAI: | ||
868 | /* DoP bitwidth is always 24-bit */ | ||
869 | bitwidth_dai = 24; | ||
870 | sclk = params_rate(params) * bitwidth_dai * | ||
871 | params_channels(params); | ||
872 | |||
873 | switch (params_rate(params)) { | ||
874 | case 176400: | ||
875 | dsd_speed = 0; | ||
876 | break; | ||
877 | case 352800: | ||
878 | dsd_speed = 1; | ||
879 | break; | ||
880 | default: | ||
881 | dev_err(codec->dev, "Rate(%u) not supported\n", | ||
882 | params_rate(params)); | ||
883 | return -EINVAL; | ||
884 | } | ||
885 | |||
886 | regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, | ||
887 | CS43130_DSD_SPEED_MASK, | ||
888 | dsd_speed << CS43130_DSD_SPEED_SHIFT); | ||
889 | break; | ||
890 | case CS43130_ASP_PCM_DAI: | ||
891 | rate_map = cs43130_get_rate_table(params_rate(params)); | ||
892 | if (!rate_map) | ||
893 | return -EINVAL; | ||
894 | |||
895 | regmap_write(cs43130->regmap, CS43130_SP_SRATE, rate_map->val); | ||
896 | break; | ||
897 | default: | ||
898 | dev_err(codec->dev, "Invalid DAI (%d)\n", dai->id); | ||
899 | return -EINVAL; | ||
900 | } | ||
901 | |||
902 | switch (dai->id) { | ||
903 | case CS43130_ASP_DOP_DAI: | ||
904 | regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, | ||
905 | CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_ASP << | ||
906 | CS43130_DSD_SRC_SHIFT); | ||
907 | break; | ||
908 | case CS43130_XSP_DOP_DAI: | ||
909 | regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_2, | ||
910 | CS43130_DSD_SRC_MASK, CS43130_DSD_SRC_XSP << | ||
911 | CS43130_DSD_SRC_SHIFT); | ||
912 | } | ||
913 | |||
914 | if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM) | ||
915 | /* Calculate SCLK in master mode if unassigned */ | ||
916 | sclk = params_rate(params) * bitwidth_dai * | ||
917 | params_channels(params); | ||
918 | |||
919 | if (!sclk) { | ||
920 | /* at this point, SCLK must be set */ | ||
921 | dev_err(codec->dev, "SCLK freq is not set\n"); | ||
922 | return -EINVAL; | ||
923 | } | ||
924 | |||
925 | bitwidth_sclk = (sclk / params_rate(params)) / params_channels(params); | ||
926 | if (bitwidth_sclk < bitwidth_dai) { | ||
927 | dev_err(codec->dev, "Format not supported: SCLK freq is too low\n"); | ||
928 | return -EINVAL; | ||
929 | } | ||
930 | |||
931 | dev_dbg(codec->dev, | ||
932 | "sclk = %u, fs = %d, bitwidth_dai = %u\n", | ||
933 | sclk, params_rate(params), bitwidth_dai); | ||
934 | |||
935 | dev_dbg(codec->dev, | ||
936 | "bitwidth_sclk = %u, num_ch = %u\n", | ||
937 | bitwidth_sclk, params_channels(params)); | ||
938 | |||
939 | cs43130_set_bitwidth(dai->id, bitwidth_dai, cs43130->regmap); | ||
940 | cs43130_set_sp_fmt(dai->id, bitwidth_sclk, params, cs43130); | ||
941 | |||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | static int cs43130_hw_free(struct snd_pcm_substream *substream, | ||
946 | struct snd_soc_dai *dai) | ||
947 | { | ||
948 | struct snd_soc_codec *codec = dai->codec; | ||
949 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
950 | |||
951 | mutex_lock(&cs43130->clk_mutex); | ||
952 | cs43130->clk_req--; | ||
953 | if (!cs43130->clk_req) { | ||
954 | /* no DAI is currently using clk */ | ||
955 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO); | ||
956 | cs43130_pcm_dsd_mix(false, cs43130->regmap); | ||
957 | } | ||
958 | mutex_unlock(&cs43130->clk_mutex); | ||
959 | |||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | static const DECLARE_TLV_DB_SCALE(pcm_vol_tlv, -12750, 50, 1); | ||
964 | |||
965 | static const char * const pcm_ch_text[] = { | ||
966 | "Left-Right Ch", | ||
967 | "Left-Left Ch", | ||
968 | "Right-Left Ch", | ||
969 | "Right-Right Ch", | ||
970 | }; | ||
971 | |||
972 | static const struct reg_sequence pcm_ch_en_seq[] = { | ||
973 | {CS43130_DXD1, 0x99}, | ||
974 | {0x180005, 0x8C}, | ||
975 | {0x180007, 0xAB}, | ||
976 | {0x180015, 0x31}, | ||
977 | {0x180017, 0xB2}, | ||
978 | {0x180025, 0x30}, | ||
979 | {0x180027, 0x84}, | ||
980 | {0x180035, 0x9C}, | ||
981 | {0x180037, 0xAE}, | ||
982 | {0x18000D, 0x24}, | ||
983 | {0x18000F, 0xA3}, | ||
984 | {0x18001D, 0x05}, | ||
985 | {0x18001F, 0xD4}, | ||
986 | {0x18002D, 0x0B}, | ||
987 | {0x18002F, 0xC7}, | ||
988 | {0x18003D, 0x71}, | ||
989 | {0x18003F, 0xE7}, | ||
990 | {CS43130_DXD1, 0}, | ||
991 | }; | ||
992 | |||
993 | static const struct reg_sequence pcm_ch_dis_seq[] = { | ||
994 | {CS43130_DXD1, 0x99}, | ||
995 | {0x180005, 0x24}, | ||
996 | {0x180007, 0xA3}, | ||
997 | {0x180015, 0x05}, | ||
998 | {0x180017, 0xD4}, | ||
999 | {0x180025, 0x0B}, | ||
1000 | {0x180027, 0xC7}, | ||
1001 | {0x180035, 0x71}, | ||
1002 | {0x180037, 0xE7}, | ||
1003 | {0x18000D, 0x8C}, | ||
1004 | {0x18000F, 0xAB}, | ||
1005 | {0x18001D, 0x31}, | ||
1006 | {0x18001F, 0xB2}, | ||
1007 | {0x18002D, 0x30}, | ||
1008 | {0x18002F, 0x84}, | ||
1009 | {0x18003D, 0x9C}, | ||
1010 | {0x18003F, 0xAE}, | ||
1011 | {CS43130_DXD1, 0}, | ||
1012 | }; | ||
1013 | |||
1014 | static int cs43130_pcm_ch_get(struct snd_kcontrol *kcontrol, | ||
1015 | struct snd_ctl_elem_value *ucontrol) | ||
1016 | { | ||
1017 | return snd_soc_get_enum_double(kcontrol, ucontrol); | ||
1018 | } | ||
1019 | |||
1020 | static int cs43130_pcm_ch_put(struct snd_kcontrol *kcontrol, | ||
1021 | struct snd_ctl_elem_value *ucontrol) | ||
1022 | { | ||
1023 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1024 | unsigned int *item = ucontrol->value.enumerated.item; | ||
1025 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
1026 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1027 | unsigned int val; | ||
1028 | |||
1029 | if (item[0] >= e->items) | ||
1030 | return -EINVAL; | ||
1031 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; | ||
1032 | |||
1033 | switch (cs43130->dev_id) { | ||
1034 | case CS43131_CHIP_ID: | ||
1035 | case CS43198_CHIP_ID: | ||
1036 | if (val >= 2) | ||
1037 | regmap_multi_reg_write(cs43130->regmap, pcm_ch_en_seq, | ||
1038 | ARRAY_SIZE(pcm_ch_en_seq)); | ||
1039 | else | ||
1040 | regmap_multi_reg_write(cs43130->regmap, pcm_ch_dis_seq, | ||
1041 | ARRAY_SIZE(pcm_ch_dis_seq)); | ||
1042 | } | ||
1043 | |||
1044 | return snd_soc_put_enum_double(kcontrol, ucontrol); | ||
1045 | } | ||
1046 | |||
1047 | static SOC_ENUM_SINGLE_DECL(pcm_ch_enum, CS43130_PCM_PATH_CTL_2, 0, | ||
1048 | pcm_ch_text); | ||
1049 | |||
1050 | static const char * const pcm_spd_texts[] = { | ||
1051 | "Fast", | ||
1052 | "Slow", | ||
1053 | }; | ||
1054 | |||
1055 | static SOC_ENUM_SINGLE_DECL(pcm_spd_enum, CS43130_PCM_FILT_OPT, 7, | ||
1056 | pcm_spd_texts); | ||
1057 | |||
1058 | static const char * const dsd_texts[] = { | ||
1059 | "Off", | ||
1060 | "BCKA Mode", | ||
1061 | "BCKD Mode", | ||
1062 | }; | ||
1063 | |||
1064 | static const unsigned int dsd_values[] = { | ||
1065 | CS43130_DSD_SRC_DSD, | ||
1066 | CS43130_DSD_SRC_ASP, | ||
1067 | CS43130_DSD_SRC_XSP, | ||
1068 | }; | ||
1069 | |||
1070 | static SOC_VALUE_ENUM_SINGLE_DECL(dsd_enum, CS43130_DSD_INT_CFG, 0, 0x03, | ||
1071 | dsd_texts, dsd_values); | ||
1072 | |||
1073 | static const struct snd_kcontrol_new cs43130_snd_controls[] = { | ||
1074 | SOC_DOUBLE_R_TLV("Master Playback Volume", | ||
1075 | CS43130_PCM_VOL_A, CS43130_PCM_VOL_B, 0, 0xFF, 1, | ||
1076 | pcm_vol_tlv), | ||
1077 | SOC_DOUBLE_R_TLV("Master DSD Playback Volume", | ||
1078 | CS43130_DSD_VOL_A, CS43130_DSD_VOL_B, 0, 0xFF, 1, | ||
1079 | pcm_vol_tlv), | ||
1080 | SOC_ENUM_EXT("PCM Ch Select", pcm_ch_enum, cs43130_pcm_ch_get, | ||
1081 | cs43130_pcm_ch_put), | ||
1082 | SOC_ENUM("PCM Filter Speed", pcm_spd_enum), | ||
1083 | SOC_SINGLE("PCM Phase Compensation", CS43130_PCM_FILT_OPT, 6, 1, 0), | ||
1084 | SOC_SINGLE("PCM Nonoversample Emulate", CS43130_PCM_FILT_OPT, 5, 1, 0), | ||
1085 | SOC_SINGLE("PCM High-pass Filter", CS43130_PCM_FILT_OPT, 1, 1, 0), | ||
1086 | SOC_SINGLE("PCM De-emphasis Filter", CS43130_PCM_FILT_OPT, 0, 1, 0), | ||
1087 | SOC_ENUM("DSD Phase Modulation", dsd_enum), | ||
1088 | }; | ||
1089 | |||
1090 | static const struct reg_sequence pcm_seq[] = { | ||
1091 | {CS43130_DXD1, 0x99}, | ||
1092 | {CS43130_DXD7, 0x01}, | ||
1093 | {CS43130_DXD8, 0}, | ||
1094 | {CS43130_DXD9, 0x01}, | ||
1095 | {CS43130_DXD3, 0x12}, | ||
1096 | {CS43130_DXD4, 0}, | ||
1097 | {CS43130_DXD10, 0x28}, | ||
1098 | {CS43130_DXD11, 0x28}, | ||
1099 | {CS43130_DXD1, 0}, | ||
1100 | }; | ||
1101 | |||
1102 | static const struct reg_sequence dsd_seq[] = { | ||
1103 | {CS43130_DXD1, 0x99}, | ||
1104 | {CS43130_DXD7, 0x01}, | ||
1105 | {CS43130_DXD8, 0}, | ||
1106 | {CS43130_DXD9, 0x01}, | ||
1107 | {CS43130_DXD3, 0x12}, | ||
1108 | {CS43130_DXD4, 0}, | ||
1109 | {CS43130_DXD10, 0x1E}, | ||
1110 | {CS43130_DXD11, 0x20}, | ||
1111 | {CS43130_DXD1, 0}, | ||
1112 | }; | ||
1113 | |||
1114 | static const struct reg_sequence pop_free_seq[] = { | ||
1115 | {CS43130_DXD1, 0x99}, | ||
1116 | {CS43130_DXD12, 0x0A}, | ||
1117 | {CS43130_DXD1, 0}, | ||
1118 | }; | ||
1119 | |||
1120 | static const struct reg_sequence pop_free_seq2[] = { | ||
1121 | {CS43130_DXD1, 0x99}, | ||
1122 | {CS43130_DXD13, 0x20}, | ||
1123 | {CS43130_DXD1, 0}, | ||
1124 | }; | ||
1125 | |||
1126 | static const struct reg_sequence mute_seq[] = { | ||
1127 | {CS43130_DXD1, 0x99}, | ||
1128 | {CS43130_DXD3, 0x12}, | ||
1129 | {CS43130_DXD5, 0x02}, | ||
1130 | {CS43130_DXD4, 0x12}, | ||
1131 | {CS43130_DXD1, 0}, | ||
1132 | }; | ||
1133 | |||
1134 | static const struct reg_sequence unmute_seq[] = { | ||
1135 | {CS43130_DXD1, 0x99}, | ||
1136 | {CS43130_DXD3, 0x10}, | ||
1137 | {CS43130_DXD5, 0}, | ||
1138 | {CS43130_DXD4, 0x16}, | ||
1139 | {CS43130_DXD1, 0}, | ||
1140 | }; | ||
1141 | |||
1142 | static int cs43130_dsd_event(struct snd_soc_dapm_widget *w, | ||
1143 | struct snd_kcontrol *kcontrol, int event) | ||
1144 | { | ||
1145 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
1146 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1147 | |||
1148 | switch (event) { | ||
1149 | case SND_SOC_DAPM_PRE_PMU: | ||
1150 | switch (cs43130->dev_id) { | ||
1151 | case CS43130_CHIP_ID: | ||
1152 | case CS4399_CHIP_ID: | ||
1153 | regmap_multi_reg_write(cs43130->regmap, dsd_seq, | ||
1154 | ARRAY_SIZE(dsd_seq)); | ||
1155 | } | ||
1156 | break; | ||
1157 | case SND_SOC_DAPM_POST_PMU: | ||
1158 | regmap_update_bits(cs43130->regmap, CS43130_DSD_PATH_CTL_1, | ||
1159 | CS43130_MUTE_MASK, 0); | ||
1160 | switch (cs43130->dev_id) { | ||
1161 | case CS43130_CHIP_ID: | ||
1162 | case CS4399_CHIP_ID: | ||
1163 | regmap_multi_reg_write(cs43130->regmap, unmute_seq, | ||
1164 | ARRAY_SIZE(unmute_seq)); | ||
1165 | } | ||
1166 | break; | ||
1167 | case SND_SOC_DAPM_PRE_PMD: | ||
1168 | switch (cs43130->dev_id) { | ||
1169 | case CS43130_CHIP_ID: | ||
1170 | case CS4399_CHIP_ID: | ||
1171 | regmap_multi_reg_write(cs43130->regmap, mute_seq, | ||
1172 | ARRAY_SIZE(mute_seq)); | ||
1173 | regmap_update_bits(cs43130->regmap, | ||
1174 | CS43130_DSD_PATH_CTL_1, | ||
1175 | CS43130_MUTE_MASK, CS43130_MUTE_EN); | ||
1176 | /* | ||
1177 | * DSD Power Down Sequence | ||
1178 | * According to Design, 130ms is preferred. | ||
1179 | */ | ||
1180 | msleep(130); | ||
1181 | break; | ||
1182 | case CS43131_CHIP_ID: | ||
1183 | case CS43198_CHIP_ID: | ||
1184 | regmap_update_bits(cs43130->regmap, | ||
1185 | CS43130_DSD_PATH_CTL_1, | ||
1186 | CS43130_MUTE_MASK, CS43130_MUTE_EN); | ||
1187 | } | ||
1188 | break; | ||
1189 | default: | ||
1190 | dev_err(codec->dev, "Invalid event = 0x%x\n", event); | ||
1191 | return -EINVAL; | ||
1192 | } | ||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | static int cs43130_pcm_event(struct snd_soc_dapm_widget *w, | ||
1197 | struct snd_kcontrol *kcontrol, int event) | ||
1198 | { | ||
1199 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
1200 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1201 | |||
1202 | switch (event) { | ||
1203 | case SND_SOC_DAPM_PRE_PMU: | ||
1204 | switch (cs43130->dev_id) { | ||
1205 | case CS43130_CHIP_ID: | ||
1206 | case CS4399_CHIP_ID: | ||
1207 | regmap_multi_reg_write(cs43130->regmap, pcm_seq, | ||
1208 | ARRAY_SIZE(pcm_seq)); | ||
1209 | } | ||
1210 | break; | ||
1211 | case SND_SOC_DAPM_POST_PMU: | ||
1212 | regmap_update_bits(cs43130->regmap, CS43130_PCM_PATH_CTL_1, | ||
1213 | CS43130_MUTE_MASK, 0); | ||
1214 | switch (cs43130->dev_id) { | ||
1215 | case CS43130_CHIP_ID: | ||
1216 | case CS4399_CHIP_ID: | ||
1217 | regmap_multi_reg_write(cs43130->regmap, unmute_seq, | ||
1218 | ARRAY_SIZE(unmute_seq)); | ||
1219 | } | ||
1220 | break; | ||
1221 | case SND_SOC_DAPM_PRE_PMD: | ||
1222 | switch (cs43130->dev_id) { | ||
1223 | case CS43130_CHIP_ID: | ||
1224 | case CS4399_CHIP_ID: | ||
1225 | regmap_multi_reg_write(cs43130->regmap, mute_seq, | ||
1226 | ARRAY_SIZE(mute_seq)); | ||
1227 | regmap_update_bits(cs43130->regmap, | ||
1228 | CS43130_PCM_PATH_CTL_1, | ||
1229 | CS43130_MUTE_MASK, CS43130_MUTE_EN); | ||
1230 | /* | ||
1231 | * PCM Power Down Sequence | ||
1232 | * According to Design, 130ms is preferred. | ||
1233 | */ | ||
1234 | msleep(130); | ||
1235 | break; | ||
1236 | case CS43131_CHIP_ID: | ||
1237 | case CS43198_CHIP_ID: | ||
1238 | regmap_update_bits(cs43130->regmap, | ||
1239 | CS43130_PCM_PATH_CTL_1, | ||
1240 | CS43130_MUTE_MASK, CS43130_MUTE_EN); | ||
1241 | } | ||
1242 | break; | ||
1243 | default: | ||
1244 | dev_err(codec->dev, "Invalid event = 0x%x\n", event); | ||
1245 | return -EINVAL; | ||
1246 | } | ||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static const struct reg_sequence dac_postpmu_seq[] = { | ||
1251 | {CS43130_DXD9, 0x0C}, | ||
1252 | {CS43130_DXD3, 0x10}, | ||
1253 | {CS43130_DXD4, 0x20}, | ||
1254 | }; | ||
1255 | |||
1256 | static const struct reg_sequence dac_postpmd_seq[] = { | ||
1257 | {CS43130_DXD1, 0x99}, | ||
1258 | {CS43130_DXD6, 0x01}, | ||
1259 | {CS43130_DXD1, 0}, | ||
1260 | }; | ||
1261 | |||
1262 | static int cs43130_dac_event(struct snd_soc_dapm_widget *w, | ||
1263 | struct snd_kcontrol *kcontrol, int event) | ||
1264 | { | ||
1265 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
1266 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1267 | |||
1268 | switch (event) { | ||
1269 | case SND_SOC_DAPM_PRE_PMU: | ||
1270 | switch (cs43130->dev_id) { | ||
1271 | case CS43130_CHIP_ID: | ||
1272 | case CS4399_CHIP_ID: | ||
1273 | regmap_multi_reg_write(cs43130->regmap, pop_free_seq, | ||
1274 | ARRAY_SIZE(pop_free_seq)); | ||
1275 | break; | ||
1276 | case CS43131_CHIP_ID: | ||
1277 | case CS43198_CHIP_ID: | ||
1278 | regmap_multi_reg_write(cs43130->regmap, pop_free_seq2, | ||
1279 | ARRAY_SIZE(pop_free_seq2)); | ||
1280 | } | ||
1281 | break; | ||
1282 | case SND_SOC_DAPM_POST_PMU: | ||
1283 | usleep_range(10000, 10050); | ||
1284 | |||
1285 | regmap_write(cs43130->regmap, CS43130_DXD1, 0x99); | ||
1286 | |||
1287 | switch (cs43130->dev_id) { | ||
1288 | case CS43130_CHIP_ID: | ||
1289 | case CS4399_CHIP_ID: | ||
1290 | regmap_multi_reg_write(cs43130->regmap, dac_postpmu_seq, | ||
1291 | ARRAY_SIZE(dac_postpmu_seq)); | ||
1292 | /* | ||
1293 | * Per datasheet, Sec. PCM Power-Up Sequence. | ||
1294 | * According to Design, CS43130_DXD12 must be 0 to meet | ||
1295 | * THDN and Dynamic Range spec. | ||
1296 | */ | ||
1297 | msleep(1000); | ||
1298 | regmap_write(cs43130->regmap, CS43130_DXD12, 0); | ||
1299 | break; | ||
1300 | case CS43131_CHIP_ID: | ||
1301 | case CS43198_CHIP_ID: | ||
1302 | usleep_range(12000, 12010); | ||
1303 | regmap_write(cs43130->regmap, CS43130_DXD13, 0); | ||
1304 | } | ||
1305 | |||
1306 | regmap_write(cs43130->regmap, CS43130_DXD1, 0); | ||
1307 | break; | ||
1308 | case SND_SOC_DAPM_POST_PMD: | ||
1309 | switch (cs43130->dev_id) { | ||
1310 | case CS43130_CHIP_ID: | ||
1311 | case CS4399_CHIP_ID: | ||
1312 | regmap_multi_reg_write(cs43130->regmap, dac_postpmd_seq, | ||
1313 | ARRAY_SIZE(dac_postpmd_seq)); | ||
1314 | } | ||
1315 | break; | ||
1316 | default: | ||
1317 | dev_err(codec->dev, "Invalid DAC event = 0x%x\n", event); | ||
1318 | return -EINVAL; | ||
1319 | } | ||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | static const struct reg_sequence hpin_prepmd_seq[] = { | ||
1324 | {CS43130_DXD1, 0x99}, | ||
1325 | {CS43130_DXD15, 0x64}, | ||
1326 | {CS43130_DXD14, 0}, | ||
1327 | {CS43130_DXD2, 0}, | ||
1328 | {CS43130_DXD1, 0}, | ||
1329 | }; | ||
1330 | |||
1331 | static const struct reg_sequence hpin_postpmu_seq[] = { | ||
1332 | {CS43130_DXD1, 0x99}, | ||
1333 | {CS43130_DXD2, 1}, | ||
1334 | {CS43130_DXD14, 0xDC}, | ||
1335 | {CS43130_DXD15, 0xE4}, | ||
1336 | {CS43130_DXD1, 0}, | ||
1337 | }; | ||
1338 | |||
1339 | static int cs43130_hpin_event(struct snd_soc_dapm_widget *w, | ||
1340 | struct snd_kcontrol *kcontrol, int event) | ||
1341 | { | ||
1342 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
1343 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1344 | |||
1345 | switch (event) { | ||
1346 | case SND_SOC_DAPM_POST_PMD: | ||
1347 | regmap_multi_reg_write(cs43130->regmap, hpin_prepmd_seq, | ||
1348 | ARRAY_SIZE(hpin_prepmd_seq)); | ||
1349 | break; | ||
1350 | case SND_SOC_DAPM_PRE_PMU: | ||
1351 | regmap_multi_reg_write(cs43130->regmap, hpin_postpmu_seq, | ||
1352 | ARRAY_SIZE(hpin_postpmu_seq)); | ||
1353 | break; | ||
1354 | default: | ||
1355 | dev_err(codec->dev, "Invalid HPIN event = 0x%x\n", event); | ||
1356 | return -EINVAL; | ||
1357 | } | ||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | static const struct snd_soc_dapm_widget digital_hp_widgets[] = { | ||
1362 | SND_SOC_DAPM_OUTPUT("HPOUTA"), | ||
1363 | SND_SOC_DAPM_OUTPUT("HPOUTB"), | ||
1364 | |||
1365 | SND_SOC_DAPM_AIF_IN_E("ASPIN PCM", NULL, 0, CS43130_PWDN_CTL, | ||
1366 | CS43130_PDN_ASP_SHIFT, 1, cs43130_pcm_event, | ||
1367 | (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
1368 | SND_SOC_DAPM_PRE_PMD)), | ||
1369 | |||
1370 | SND_SOC_DAPM_AIF_IN_E("ASPIN DoP", NULL, 0, CS43130_PWDN_CTL, | ||
1371 | CS43130_PDN_ASP_SHIFT, 1, cs43130_dsd_event, | ||
1372 | (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
1373 | SND_SOC_DAPM_PRE_PMD)), | ||
1374 | |||
1375 | SND_SOC_DAPM_AIF_IN_E("XSPIN DoP", NULL, 0, CS43130_PWDN_CTL, | ||
1376 | CS43130_PDN_XSP_SHIFT, 1, cs43130_dsd_event, | ||
1377 | (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
1378 | SND_SOC_DAPM_PRE_PMD)), | ||
1379 | |||
1380 | SND_SOC_DAPM_AIF_IN_E("XSPIN DSD", NULL, 0, CS43130_PWDN_CTL, | ||
1381 | CS43130_PDN_DSDIF_SHIFT, 1, cs43130_dsd_event, | ||
1382 | (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
1383 | SND_SOC_DAPM_PRE_PMD)), | ||
1384 | |||
1385 | SND_SOC_DAPM_DAC("DSD", NULL, CS43130_DSD_PATH_CTL_2, | ||
1386 | CS43130_DSD_EN_SHIFT, 0), | ||
1387 | |||
1388 | SND_SOC_DAPM_DAC_E("HiFi DAC", NULL, CS43130_PWDN_CTL, | ||
1389 | CS43130_PDN_HP_SHIFT, 1, cs43130_dac_event, | ||
1390 | (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | ||
1391 | SND_SOC_DAPM_POST_PMD)), | ||
1392 | }; | ||
1393 | |||
1394 | static const struct snd_soc_dapm_widget analog_hp_widgets[] = { | ||
1395 | SND_SOC_DAPM_DAC_E("Analog Playback", NULL, CS43130_HP_OUT_CTL_1, | ||
1396 | CS43130_HP_IN_EN_SHIFT, 0, cs43130_hpin_event, | ||
1397 | (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)), | ||
1398 | }; | ||
1399 | |||
1400 | static struct snd_soc_dapm_widget all_hp_widgets[ | ||
1401 | ARRAY_SIZE(digital_hp_widgets) + | ||
1402 | ARRAY_SIZE(analog_hp_widgets)]; | ||
1403 | |||
1404 | static const struct snd_soc_dapm_route digital_hp_routes[] = { | ||
1405 | {"ASPIN PCM", NULL, "ASP PCM Playback"}, | ||
1406 | {"ASPIN DoP", NULL, "ASP DoP Playback"}, | ||
1407 | {"XSPIN DoP", NULL, "XSP DoP Playback"}, | ||
1408 | {"XSPIN DSD", NULL, "XSP DSD Playback"}, | ||
1409 | {"DSD", NULL, "ASPIN DoP"}, | ||
1410 | {"DSD", NULL, "XSPIN DoP"}, | ||
1411 | {"DSD", NULL, "XSPIN DSD"}, | ||
1412 | {"HiFi DAC", NULL, "ASPIN PCM"}, | ||
1413 | {"HiFi DAC", NULL, "DSD"}, | ||
1414 | {"HPOUTA", NULL, "HiFi DAC"}, | ||
1415 | {"HPOUTB", NULL, "HiFi DAC"}, | ||
1416 | }; | ||
1417 | |||
1418 | static const struct snd_soc_dapm_route analog_hp_routes[] = { | ||
1419 | {"HPOUTA", NULL, "Analog Playback"}, | ||
1420 | {"HPOUTB", NULL, "Analog Playback"}, | ||
1421 | }; | ||
1422 | |||
1423 | static struct snd_soc_dapm_route all_hp_routes[ | ||
1424 | ARRAY_SIZE(digital_hp_routes) + | ||
1425 | ARRAY_SIZE(analog_hp_routes)]; | ||
1426 | |||
1427 | static const unsigned int cs43130_asp_src_rates[] = { | ||
1428 | 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000 | ||
1429 | }; | ||
1430 | |||
1431 | static const struct snd_pcm_hw_constraint_list cs43130_asp_constraints = { | ||
1432 | .count = ARRAY_SIZE(cs43130_asp_src_rates), | ||
1433 | .list = cs43130_asp_src_rates, | ||
1434 | }; | ||
1435 | |||
1436 | static int cs43130_pcm_startup(struct snd_pcm_substream *substream, | ||
1437 | struct snd_soc_dai *dai) | ||
1438 | { | ||
1439 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
1440 | SNDRV_PCM_HW_PARAM_RATE, | ||
1441 | &cs43130_asp_constraints); | ||
1442 | } | ||
1443 | |||
1444 | static const unsigned int cs43130_dop_src_rates[] = { | ||
1445 | 176400, 352800, | ||
1446 | }; | ||
1447 | |||
1448 | static const struct snd_pcm_hw_constraint_list cs43130_dop_constraints = { | ||
1449 | .count = ARRAY_SIZE(cs43130_dop_src_rates), | ||
1450 | .list = cs43130_dop_src_rates, | ||
1451 | }; | ||
1452 | |||
1453 | static int cs43130_dop_startup(struct snd_pcm_substream *substream, | ||
1454 | struct snd_soc_dai *dai) | ||
1455 | { | ||
1456 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
1457 | SNDRV_PCM_HW_PARAM_RATE, | ||
1458 | &cs43130_dop_constraints); | ||
1459 | } | ||
1460 | |||
1461 | static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
1462 | { | ||
1463 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1464 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1465 | |||
1466 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1467 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1468 | cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS; | ||
1469 | break; | ||
1470 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1471 | cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; | ||
1472 | break; | ||
1473 | default: | ||
1474 | dev_err(codec->dev, "unsupported mode\n"); | ||
1475 | return -EINVAL; | ||
1476 | } | ||
1477 | |||
1478 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1479 | case SND_SOC_DAIFMT_I2S: | ||
1480 | cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_I2S; | ||
1481 | break; | ||
1482 | case SND_SOC_DAIFMT_LEFT_J: | ||
1483 | cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_LEFT_J; | ||
1484 | break; | ||
1485 | case SND_SOC_DAIFMT_DSP_A: | ||
1486 | cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_A; | ||
1487 | break; | ||
1488 | case SND_SOC_DAIFMT_DSP_B: | ||
1489 | cs43130->dais[codec_dai->id].dai_format = SND_SOC_DAIFMT_DSP_B; | ||
1490 | break; | ||
1491 | default: | ||
1492 | dev_err(codec->dev, | ||
1493 | "unsupported audio format\n"); | ||
1494 | return -EINVAL; | ||
1495 | } | ||
1496 | |||
1497 | dev_dbg(codec->dev, "dai_id = %d, dai_mode = %u, dai_format = %u\n", | ||
1498 | codec_dai->id, | ||
1499 | cs43130->dais[codec_dai->id].dai_mode, | ||
1500 | cs43130->dais[codec_dai->id].dai_format); | ||
1501 | |||
1502 | return 0; | ||
1503 | } | ||
1504 | |||
1505 | static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
1506 | { | ||
1507 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1508 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1509 | |||
1510 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1511 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1512 | cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS; | ||
1513 | break; | ||
1514 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1515 | cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; | ||
1516 | break; | ||
1517 | default: | ||
1518 | dev_err(codec->dev, "Unsupported DAI format.\n"); | ||
1519 | return -EINVAL; | ||
1520 | } | ||
1521 | |||
1522 | dev_dbg(codec->dev, "dai_mode = 0x%x\n", | ||
1523 | cs43130->dais[codec_dai->id].dai_mode); | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | static int cs43130_set_sysclk(struct snd_soc_dai *codec_dai, | ||
1529 | int clk_id, unsigned int freq, int dir) | ||
1530 | { | ||
1531 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1532 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1533 | |||
1534 | cs43130->dais[codec_dai->id].sclk = freq; | ||
1535 | dev_dbg(codec->dev, "dai_id = %d, sclk = %u\n", codec_dai->id, | ||
1536 | cs43130->dais[codec_dai->id].sclk); | ||
1537 | |||
1538 | return 0; | ||
1539 | } | ||
1540 | |||
1541 | static const struct snd_soc_dai_ops cs43130_pcm_ops = { | ||
1542 | .startup = cs43130_pcm_startup, | ||
1543 | .hw_params = cs43130_hw_params, | ||
1544 | .hw_free = cs43130_hw_free, | ||
1545 | .set_sysclk = cs43130_set_sysclk, | ||
1546 | .set_fmt = cs43130_pcm_set_fmt, | ||
1547 | }; | ||
1548 | |||
1549 | static const struct snd_soc_dai_ops cs43130_dop_ops = { | ||
1550 | .startup = cs43130_dop_startup, | ||
1551 | .hw_params = cs43130_hw_params, | ||
1552 | .hw_free = cs43130_hw_free, | ||
1553 | .set_sysclk = cs43130_set_sysclk, | ||
1554 | .set_fmt = cs43130_pcm_set_fmt, | ||
1555 | }; | ||
1556 | |||
1557 | static const struct snd_soc_dai_ops cs43130_dsd_ops = { | ||
1558 | .startup = cs43130_dop_startup, | ||
1559 | .hw_params = cs43130_dsd_hw_params, | ||
1560 | .hw_free = cs43130_hw_free, | ||
1561 | .set_fmt = cs43130_dsd_set_fmt, | ||
1562 | }; | ||
1563 | |||
1564 | static struct snd_soc_dai_driver cs43130_dai[] = { | ||
1565 | { | ||
1566 | .name = "cs43130-asp-pcm", | ||
1567 | .id = CS43130_ASP_PCM_DAI, | ||
1568 | .playback = { | ||
1569 | .stream_name = "ASP PCM Playback", | ||
1570 | .channels_min = 1, | ||
1571 | .channels_max = 2, | ||
1572 | .rates = SNDRV_PCM_RATE_KNOT, | ||
1573 | .formats = CS43130_PCM_FORMATS, | ||
1574 | }, | ||
1575 | .ops = &cs43130_pcm_ops, | ||
1576 | .symmetric_rates = 1, | ||
1577 | }, | ||
1578 | { | ||
1579 | .name = "cs43130-asp-dop", | ||
1580 | .id = CS43130_ASP_DOP_DAI, | ||
1581 | .playback = { | ||
1582 | .stream_name = "ASP DoP Playback", | ||
1583 | .channels_min = 1, | ||
1584 | .channels_max = 2, | ||
1585 | .rates = SNDRV_PCM_RATE_KNOT, | ||
1586 | .formats = CS43130_DOP_FORMATS, | ||
1587 | }, | ||
1588 | .ops = &cs43130_dop_ops, | ||
1589 | .symmetric_rates = 1, | ||
1590 | }, | ||
1591 | { | ||
1592 | .name = "cs43130-xsp-dop", | ||
1593 | .id = CS43130_XSP_DOP_DAI, | ||
1594 | .playback = { | ||
1595 | .stream_name = "XSP DoP Playback", | ||
1596 | .channels_min = 1, | ||
1597 | .channels_max = 2, | ||
1598 | .rates = SNDRV_PCM_RATE_KNOT, | ||
1599 | .formats = CS43130_DOP_FORMATS, | ||
1600 | }, | ||
1601 | .ops = &cs43130_dop_ops, | ||
1602 | .symmetric_rates = 1, | ||
1603 | }, | ||
1604 | { | ||
1605 | .name = "cs43130-xsp-dsd", | ||
1606 | .id = CS43130_XSP_DSD_DAI, | ||
1607 | .playback = { | ||
1608 | .stream_name = "XSP DSD Playback", | ||
1609 | .channels_min = 1, | ||
1610 | .channels_max = 2, | ||
1611 | .rates = SNDRV_PCM_RATE_KNOT, | ||
1612 | .formats = CS43130_DOP_FORMATS, | ||
1613 | }, | ||
1614 | .ops = &cs43130_dsd_ops, | ||
1615 | }, | ||
1616 | |||
1617 | }; | ||
1618 | |||
1619 | static int cs43130_codec_set_sysclk(struct snd_soc_codec *codec, | ||
1620 | int clk_id, int source, unsigned int freq, | ||
1621 | int dir) | ||
1622 | { | ||
1623 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
1624 | |||
1625 | dev_dbg(codec->dev, "clk_id = %d, source = %d, freq = %d, dir = %d\n", | ||
1626 | clk_id, source, freq, dir); | ||
1627 | |||
1628 | switch (freq) { | ||
1629 | case CS43130_MCLK_22M: | ||
1630 | case CS43130_MCLK_24M: | ||
1631 | cs43130->mclk = freq; | ||
1632 | break; | ||
1633 | default: | ||
1634 | dev_err(codec->dev, "Invalid MCLK INT freq: %u\n", freq); | ||
1635 | return -EINVAL; | ||
1636 | } | ||
1637 | |||
1638 | if (source == CS43130_MCLK_SRC_EXT) { | ||
1639 | cs43130->pll_bypass = true; | ||
1640 | } else { | ||
1641 | dev_err(codec->dev, "Invalid MCLK source\n"); | ||
1642 | return -EINVAL; | ||
1643 | } | ||
1644 | |||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | static inline u16 cs43130_get_ac_reg_val(u16 ac_freq) | ||
1649 | { | ||
1650 | /* AC freq is counted in 5.94Hz step. */ | ||
1651 | return ac_freq / 6; | ||
1652 | } | ||
1653 | |||
1654 | static int cs43130_show_dc(struct device *dev, char *buf, u8 ch) | ||
1655 | { | ||
1656 | struct i2c_client *client = to_i2c_client(dev); | ||
1657 | struct cs43130_private *cs43130 = i2c_get_clientdata(client); | ||
1658 | |||
1659 | if (!cs43130->hpload_done) | ||
1660 | return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); | ||
1661 | else | ||
1662 | return scnprintf(buf, PAGE_SIZE, "%u\n", | ||
1663 | cs43130->hpload_dc[ch]); | ||
1664 | } | ||
1665 | |||
1666 | static ssize_t cs43130_show_dc_l(struct device *dev, | ||
1667 | struct device_attribute *attr, char *buf) | ||
1668 | { | ||
1669 | return cs43130_show_dc(dev, buf, HP_LEFT); | ||
1670 | } | ||
1671 | |||
1672 | static ssize_t cs43130_show_dc_r(struct device *dev, | ||
1673 | struct device_attribute *attr, char *buf) | ||
1674 | { | ||
1675 | return cs43130_show_dc(dev, buf, HP_RIGHT); | ||
1676 | } | ||
1677 | |||
1678 | static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = { | ||
1679 | 24, | ||
1680 | 43, | ||
1681 | 93, | ||
1682 | 200, | ||
1683 | 431, | ||
1684 | 928, | ||
1685 | 2000, | ||
1686 | 4309, | ||
1687 | 9283, | ||
1688 | 20000, | ||
1689 | }; | ||
1690 | |||
1691 | static int cs43130_show_ac(struct device *dev, char *buf, u8 ch) | ||
1692 | { | ||
1693 | int i, j = 0, tmp; | ||
1694 | struct i2c_client *client = to_i2c_client(dev); | ||
1695 | struct cs43130_private *cs43130 = i2c_get_clientdata(client); | ||
1696 | |||
1697 | if (cs43130->hpload_done && cs43130->ac_meas) { | ||
1698 | for (i = 0; i < ARRAY_SIZE(cs43130_ac_freq); i++) { | ||
1699 | tmp = scnprintf(buf + j, PAGE_SIZE - j, "%u\n", | ||
1700 | cs43130->hpload_ac[i][ch]); | ||
1701 | if (!tmp) | ||
1702 | break; | ||
1703 | |||
1704 | j += tmp; | ||
1705 | } | ||
1706 | |||
1707 | return j; | ||
1708 | } else { | ||
1709 | return scnprintf(buf, PAGE_SIZE, "NO_HPLOAD\n"); | ||
1710 | } | ||
1711 | } | ||
1712 | |||
1713 | static ssize_t cs43130_show_ac_l(struct device *dev, | ||
1714 | struct device_attribute *attr, char *buf) | ||
1715 | { | ||
1716 | return cs43130_show_ac(dev, buf, HP_LEFT); | ||
1717 | } | ||
1718 | |||
1719 | static ssize_t cs43130_show_ac_r(struct device *dev, | ||
1720 | struct device_attribute *attr, char *buf) | ||
1721 | { | ||
1722 | return cs43130_show_ac(dev, buf, HP_RIGHT); | ||
1723 | } | ||
1724 | |||
1725 | static DEVICE_ATTR(hpload_dc_l, S_IRUGO, cs43130_show_dc_l, NULL); | ||
1726 | static DEVICE_ATTR(hpload_dc_r, S_IRUGO, cs43130_show_dc_r, NULL); | ||
1727 | static DEVICE_ATTR(hpload_ac_l, S_IRUGO, cs43130_show_ac_l, NULL); | ||
1728 | static DEVICE_ATTR(hpload_ac_r, S_IRUGO, cs43130_show_ac_r, NULL); | ||
1729 | |||
1730 | static struct reg_sequence hp_en_cal_seq[] = { | ||
1731 | {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, | ||
1732 | {CS43130_HP_MEAS_LOAD_1, 0}, | ||
1733 | {CS43130_HP_MEAS_LOAD_2, 0}, | ||
1734 | {CS43130_INT_MASK_4, 0}, | ||
1735 | {CS43130_DXD1, 0x99}, | ||
1736 | {CS43130_DXD16, 0xBB}, | ||
1737 | {CS43130_DXD12, 0x01}, | ||
1738 | {CS43130_DXD19, 0xCB}, | ||
1739 | {CS43130_DXD17, 0x95}, | ||
1740 | {CS43130_DXD18, 0x0B}, | ||
1741 | {CS43130_DXD1, 0}, | ||
1742 | {CS43130_HP_LOAD_1, 0x80}, | ||
1743 | }; | ||
1744 | |||
1745 | static struct reg_sequence hp_en_cal_seq2[] = { | ||
1746 | {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, | ||
1747 | {CS43130_HP_MEAS_LOAD_1, 0}, | ||
1748 | {CS43130_HP_MEAS_LOAD_2, 0}, | ||
1749 | {CS43130_INT_MASK_4, 0}, | ||
1750 | {CS43130_HP_LOAD_1, 0x80}, | ||
1751 | }; | ||
1752 | |||
1753 | static struct reg_sequence hp_dis_cal_seq[] = { | ||
1754 | {CS43130_HP_LOAD_1, 0x80}, | ||
1755 | {CS43130_DXD1, 0x99}, | ||
1756 | {CS43130_DXD12, 0}, | ||
1757 | {CS43130_DXD1, 0}, | ||
1758 | {CS43130_HP_LOAD_1, 0}, | ||
1759 | }; | ||
1760 | |||
1761 | static struct reg_sequence hp_dis_cal_seq2[] = { | ||
1762 | {CS43130_HP_LOAD_1, 0x80}, | ||
1763 | {CS43130_HP_LOAD_1, 0}, | ||
1764 | }; | ||
1765 | |||
1766 | static struct reg_sequence hp_dc_ch_l_seq[] = { | ||
1767 | {CS43130_DXD1, 0x99}, | ||
1768 | {CS43130_DXD19, 0x0A}, | ||
1769 | {CS43130_DXD17, 0x93}, | ||
1770 | {CS43130_DXD18, 0x0A}, | ||
1771 | {CS43130_DXD1, 0}, | ||
1772 | {CS43130_HP_LOAD_1, 0x80}, | ||
1773 | {CS43130_HP_LOAD_1, 0x81}, | ||
1774 | }; | ||
1775 | |||
1776 | static struct reg_sequence hp_dc_ch_l_seq2[] = { | ||
1777 | {CS43130_HP_LOAD_1, 0x80}, | ||
1778 | {CS43130_HP_LOAD_1, 0x81}, | ||
1779 | }; | ||
1780 | |||
1781 | static struct reg_sequence hp_dc_ch_r_seq[] = { | ||
1782 | {CS43130_DXD1, 0x99}, | ||
1783 | {CS43130_DXD19, 0x8A}, | ||
1784 | {CS43130_DXD17, 0x15}, | ||
1785 | {CS43130_DXD18, 0x06}, | ||
1786 | {CS43130_DXD1, 0}, | ||
1787 | {CS43130_HP_LOAD_1, 0x90}, | ||
1788 | {CS43130_HP_LOAD_1, 0x91}, | ||
1789 | }; | ||
1790 | |||
1791 | static struct reg_sequence hp_dc_ch_r_seq2[] = { | ||
1792 | {CS43130_HP_LOAD_1, 0x90}, | ||
1793 | {CS43130_HP_LOAD_1, 0x91}, | ||
1794 | }; | ||
1795 | |||
1796 | static struct reg_sequence hp_ac_ch_l_seq[] = { | ||
1797 | {CS43130_DXD1, 0x99}, | ||
1798 | {CS43130_DXD19, 0x0A}, | ||
1799 | {CS43130_DXD17, 0x93}, | ||
1800 | {CS43130_DXD18, 0x0A}, | ||
1801 | {CS43130_DXD1, 0}, | ||
1802 | {CS43130_HP_LOAD_1, 0x80}, | ||
1803 | {CS43130_HP_LOAD_1, 0x82}, | ||
1804 | }; | ||
1805 | |||
1806 | static struct reg_sequence hp_ac_ch_l_seq2[] = { | ||
1807 | {CS43130_HP_LOAD_1, 0x80}, | ||
1808 | {CS43130_HP_LOAD_1, 0x82}, | ||
1809 | }; | ||
1810 | |||
1811 | static struct reg_sequence hp_ac_ch_r_seq[] = { | ||
1812 | {CS43130_DXD1, 0x99}, | ||
1813 | {CS43130_DXD19, 0x8A}, | ||
1814 | {CS43130_DXD17, 0x15}, | ||
1815 | {CS43130_DXD18, 0x06}, | ||
1816 | {CS43130_DXD1, 0}, | ||
1817 | {CS43130_HP_LOAD_1, 0x90}, | ||
1818 | {CS43130_HP_LOAD_1, 0x92}, | ||
1819 | }; | ||
1820 | |||
1821 | static struct reg_sequence hp_ac_ch_r_seq2[] = { | ||
1822 | {CS43130_HP_LOAD_1, 0x90}, | ||
1823 | {CS43130_HP_LOAD_1, 0x92}, | ||
1824 | }; | ||
1825 | |||
1826 | static struct reg_sequence hp_cln_seq[] = { | ||
1827 | {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, | ||
1828 | {CS43130_HP_MEAS_LOAD_1, 0}, | ||
1829 | {CS43130_HP_MEAS_LOAD_2, 0}, | ||
1830 | }; | ||
1831 | |||
1832 | struct reg_sequences { | ||
1833 | struct reg_sequence *seq; | ||
1834 | int size; | ||
1835 | unsigned int msk; | ||
1836 | }; | ||
1837 | |||
1838 | static struct reg_sequences hpload_seq1[] = { | ||
1839 | { | ||
1840 | .seq = hp_en_cal_seq, | ||
1841 | .size = ARRAY_SIZE(hp_en_cal_seq), | ||
1842 | .msk = CS43130_HPLOAD_ON_INT, | ||
1843 | }, | ||
1844 | { | ||
1845 | .seq = hp_dc_ch_l_seq, | ||
1846 | .size = ARRAY_SIZE(hp_dc_ch_l_seq), | ||
1847 | .msk = CS43130_HPLOAD_DC_INT, | ||
1848 | }, | ||
1849 | { | ||
1850 | .seq = hp_ac_ch_l_seq, | ||
1851 | .size = ARRAY_SIZE(hp_ac_ch_l_seq), | ||
1852 | .msk = CS43130_HPLOAD_AC_INT, | ||
1853 | }, | ||
1854 | { | ||
1855 | .seq = hp_dis_cal_seq, | ||
1856 | .size = ARRAY_SIZE(hp_dis_cal_seq), | ||
1857 | .msk = CS43130_HPLOAD_OFF_INT, | ||
1858 | }, | ||
1859 | { | ||
1860 | .seq = hp_en_cal_seq, | ||
1861 | .size = ARRAY_SIZE(hp_en_cal_seq), | ||
1862 | .msk = CS43130_HPLOAD_ON_INT, | ||
1863 | }, | ||
1864 | { | ||
1865 | .seq = hp_dc_ch_r_seq, | ||
1866 | .size = ARRAY_SIZE(hp_dc_ch_r_seq), | ||
1867 | .msk = CS43130_HPLOAD_DC_INT, | ||
1868 | }, | ||
1869 | { | ||
1870 | .seq = hp_ac_ch_r_seq, | ||
1871 | .size = ARRAY_SIZE(hp_ac_ch_r_seq), | ||
1872 | .msk = CS43130_HPLOAD_AC_INT, | ||
1873 | }, | ||
1874 | }; | ||
1875 | |||
1876 | static struct reg_sequences hpload_seq2[] = { | ||
1877 | { | ||
1878 | .seq = hp_en_cal_seq2, | ||
1879 | .size = ARRAY_SIZE(hp_en_cal_seq2), | ||
1880 | .msk = CS43130_HPLOAD_ON_INT, | ||
1881 | }, | ||
1882 | { | ||
1883 | .seq = hp_dc_ch_l_seq2, | ||
1884 | .size = ARRAY_SIZE(hp_dc_ch_l_seq2), | ||
1885 | .msk = CS43130_HPLOAD_DC_INT, | ||
1886 | }, | ||
1887 | { | ||
1888 | .seq = hp_ac_ch_l_seq2, | ||
1889 | .size = ARRAY_SIZE(hp_ac_ch_l_seq2), | ||
1890 | .msk = CS43130_HPLOAD_AC_INT, | ||
1891 | }, | ||
1892 | { | ||
1893 | .seq = hp_dis_cal_seq2, | ||
1894 | .size = ARRAY_SIZE(hp_dis_cal_seq2), | ||
1895 | .msk = CS43130_HPLOAD_OFF_INT, | ||
1896 | }, | ||
1897 | { | ||
1898 | .seq = hp_en_cal_seq2, | ||
1899 | .size = ARRAY_SIZE(hp_en_cal_seq2), | ||
1900 | .msk = CS43130_HPLOAD_ON_INT, | ||
1901 | }, | ||
1902 | { | ||
1903 | .seq = hp_dc_ch_r_seq2, | ||
1904 | .size = ARRAY_SIZE(hp_dc_ch_r_seq2), | ||
1905 | .msk = CS43130_HPLOAD_DC_INT, | ||
1906 | }, | ||
1907 | { | ||
1908 | .seq = hp_ac_ch_r_seq2, | ||
1909 | .size = ARRAY_SIZE(hp_ac_ch_r_seq2), | ||
1910 | .msk = CS43130_HPLOAD_AC_INT, | ||
1911 | }, | ||
1912 | }; | ||
1913 | |||
1914 | static int cs43130_update_hpload(unsigned int msk, int ac_idx, | ||
1915 | struct cs43130_private *cs43130) | ||
1916 | { | ||
1917 | bool left_ch = true; | ||
1918 | unsigned int reg; | ||
1919 | u32 addr; | ||
1920 | u16 impedance; | ||
1921 | struct snd_soc_codec *codec = cs43130->codec; | ||
1922 | |||
1923 | switch (msk) { | ||
1924 | case CS43130_HPLOAD_DC_INT: | ||
1925 | case CS43130_HPLOAD_AC_INT: | ||
1926 | break; | ||
1927 | default: | ||
1928 | return 0; | ||
1929 | } | ||
1930 | |||
1931 | regmap_read(cs43130->regmap, CS43130_HP_LOAD_1, ®); | ||
1932 | if (reg & CS43130_HPLOAD_CHN_SEL) | ||
1933 | left_ch = false; | ||
1934 | |||
1935 | if (msk == CS43130_HPLOAD_DC_INT) | ||
1936 | addr = CS43130_HP_DC_STAT_1; | ||
1937 | else | ||
1938 | addr = CS43130_HP_AC_STAT_1; | ||
1939 | |||
1940 | regmap_read(cs43130->regmap, addr, ®); | ||
1941 | impedance = reg >> 3; | ||
1942 | regmap_read(cs43130->regmap, addr + 1, ®); | ||
1943 | impedance |= reg << 5; | ||
1944 | |||
1945 | if (msk == CS43130_HPLOAD_DC_INT) { | ||
1946 | if (left_ch) | ||
1947 | cs43130->hpload_dc[HP_LEFT] = impedance; | ||
1948 | else | ||
1949 | cs43130->hpload_dc[HP_RIGHT] = impedance; | ||
1950 | |||
1951 | dev_dbg(codec->dev, "HP DC impedance (Ch %u): %u\n", !left_ch, | ||
1952 | impedance); | ||
1953 | } else { | ||
1954 | if (left_ch) | ||
1955 | cs43130->hpload_ac[ac_idx][HP_LEFT] = impedance; | ||
1956 | else | ||
1957 | cs43130->hpload_ac[ac_idx][HP_RIGHT] = impedance; | ||
1958 | |||
1959 | dev_dbg(codec->dev, "HP AC (%u Hz) impedance (Ch %u): %u\n", | ||
1960 | cs43130->ac_freq[ac_idx], !left_ch, impedance); | ||
1961 | } | ||
1962 | |||
1963 | return 0; | ||
1964 | } | ||
1965 | |||
1966 | static int cs43130_hpload_proc(struct cs43130_private *cs43130, | ||
1967 | struct reg_sequence *seq, int seq_size, | ||
1968 | unsigned int rslt_msk, int ac_idx) | ||
1969 | { | ||
1970 | int ret; | ||
1971 | unsigned int msk; | ||
1972 | u16 ac_reg_val; | ||
1973 | struct snd_soc_codec *codec = cs43130->codec; | ||
1974 | |||
1975 | reinit_completion(&cs43130->hpload_evt); | ||
1976 | |||
1977 | if (rslt_msk == CS43130_HPLOAD_AC_INT) { | ||
1978 | ac_reg_val = cs43130_get_ac_reg_val(cs43130->ac_freq[ac_idx]); | ||
1979 | regmap_update_bits(cs43130->regmap, CS43130_HP_LOAD_1, | ||
1980 | CS43130_HPLOAD_AC_START, 0); | ||
1981 | regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_1, | ||
1982 | CS43130_HP_MEAS_LOAD_MASK, | ||
1983 | ac_reg_val >> CS43130_HP_MEAS_LOAD_1_SHIFT); | ||
1984 | regmap_update_bits(cs43130->regmap, CS43130_HP_MEAS_LOAD_2, | ||
1985 | CS43130_HP_MEAS_LOAD_MASK, | ||
1986 | ac_reg_val >> CS43130_HP_MEAS_LOAD_2_SHIFT); | ||
1987 | } | ||
1988 | |||
1989 | regmap_multi_reg_write(cs43130->regmap, seq, | ||
1990 | seq_size); | ||
1991 | |||
1992 | ret = wait_for_completion_timeout(&cs43130->hpload_evt, | ||
1993 | msecs_to_jiffies(1000)); | ||
1994 | regmap_read(cs43130->regmap, CS43130_INT_MASK_4, &msk); | ||
1995 | if (!ret) { | ||
1996 | dev_err(codec->dev, "Timeout waiting for HPLOAD interrupt\n"); | ||
1997 | return -1; | ||
1998 | } | ||
1999 | |||
2000 | dev_dbg(codec->dev, "HP load stat: %x, INT_MASK_4: %x\n", | ||
2001 | cs43130->hpload_stat, msk); | ||
2002 | if ((cs43130->hpload_stat & (CS43130_HPLOAD_NO_DC_INT | | ||
2003 | CS43130_HPLOAD_UNPLUG_INT | | ||
2004 | CS43130_HPLOAD_OOR_INT)) || | ||
2005 | !(cs43130->hpload_stat & rslt_msk)) { | ||
2006 | dev_dbg(codec->dev, "HP load measure failed\n"); | ||
2007 | return -1; | ||
2008 | } | ||
2009 | |||
2010 | return 0; | ||
2011 | } | ||
2012 | |||
2013 | static const struct reg_sequence hv_seq[][2] = { | ||
2014 | { | ||
2015 | {CS43130_CLASS_H_CTL, 0x1C}, | ||
2016 | {CS43130_HP_OUT_CTL_1, 0x10}, | ||
2017 | }, | ||
2018 | { | ||
2019 | {CS43130_CLASS_H_CTL, 0x1E}, | ||
2020 | {CS43130_HP_OUT_CTL_1, 0x20}, | ||
2021 | }, | ||
2022 | { | ||
2023 | {CS43130_CLASS_H_CTL, 0x1E}, | ||
2024 | {CS43130_HP_OUT_CTL_1, 0x30}, | ||
2025 | }, | ||
2026 | }; | ||
2027 | |||
2028 | static int cs43130_set_hv(struct regmap *regmap, u16 hpload_dc, | ||
2029 | const u16 *dc_threshold) | ||
2030 | { | ||
2031 | int i; | ||
2032 | |||
2033 | for (i = 0; i < CS43130_DC_THRESHOLD; i++) { | ||
2034 | if (hpload_dc <= dc_threshold[i]) | ||
2035 | break; | ||
2036 | } | ||
2037 | |||
2038 | regmap_multi_reg_write(regmap, hv_seq[i], ARRAY_SIZE(hv_seq[i])); | ||
2039 | |||
2040 | return 0; | ||
2041 | } | ||
2042 | |||
2043 | static void cs43130_imp_meas(struct work_struct *wk) | ||
2044 | { | ||
2045 | unsigned int reg, seq_size; | ||
2046 | int i, ret, ac_idx; | ||
2047 | struct cs43130_private *cs43130; | ||
2048 | struct snd_soc_codec *codec; | ||
2049 | struct reg_sequences *hpload_seq; | ||
2050 | |||
2051 | cs43130 = container_of(wk, struct cs43130_private, work); | ||
2052 | codec = cs43130->codec; | ||
2053 | |||
2054 | if (!cs43130->mclk) | ||
2055 | return; | ||
2056 | |||
2057 | cs43130->hpload_done = false; | ||
2058 | |||
2059 | mutex_lock(&cs43130->clk_mutex); | ||
2060 | if (!cs43130->clk_req) { | ||
2061 | /* clk not in use */ | ||
2062 | cs43130_set_pll(codec, 0, 0, cs43130->mclk, CS43130_MCLK_22M); | ||
2063 | if (cs43130->pll_bypass) | ||
2064 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_EXT); | ||
2065 | else | ||
2066 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL); | ||
2067 | } | ||
2068 | |||
2069 | cs43130->clk_req++; | ||
2070 | mutex_unlock(&cs43130->clk_mutex); | ||
2071 | |||
2072 | regmap_read(cs43130->regmap, CS43130_INT_STATUS_4, ®); | ||
2073 | |||
2074 | switch (cs43130->dev_id) { | ||
2075 | case CS43130_CHIP_ID: | ||
2076 | hpload_seq = hpload_seq1; | ||
2077 | seq_size = ARRAY_SIZE(hpload_seq1); | ||
2078 | break; | ||
2079 | case CS43131_CHIP_ID: | ||
2080 | hpload_seq = hpload_seq2; | ||
2081 | seq_size = ARRAY_SIZE(hpload_seq2); | ||
2082 | } | ||
2083 | |||
2084 | i = 0; | ||
2085 | ac_idx = 0; | ||
2086 | while (i < seq_size) { | ||
2087 | ret = cs43130_hpload_proc(cs43130, hpload_seq[i].seq, | ||
2088 | hpload_seq[i].size, | ||
2089 | hpload_seq[i].msk, ac_idx); | ||
2090 | if (ret < 0) | ||
2091 | goto exit; | ||
2092 | |||
2093 | cs43130_update_hpload(hpload_seq[i].msk, ac_idx, cs43130); | ||
2094 | |||
2095 | if (cs43130->ac_meas && | ||
2096 | hpload_seq[i].msk == CS43130_HPLOAD_AC_INT && | ||
2097 | ac_idx < CS43130_AC_FREQ - 1) { | ||
2098 | ac_idx++; | ||
2099 | } else { | ||
2100 | ac_idx = 0; | ||
2101 | i++; | ||
2102 | } | ||
2103 | } | ||
2104 | cs43130->hpload_done = true; | ||
2105 | |||
2106 | if (cs43130->hpload_dc[HP_LEFT] >= CS43130_LINEOUT_LOAD) | ||
2107 | snd_soc_jack_report(&cs43130->jack, CS43130_JACK_LINEOUT, | ||
2108 | CS43130_JACK_MASK); | ||
2109 | else | ||
2110 | snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE, | ||
2111 | CS43130_JACK_MASK); | ||
2112 | |||
2113 | dev_dbg(codec->dev, "Set HP output control. DC threshold\n"); | ||
2114 | for (i = 0; i < CS43130_DC_THRESHOLD; i++) | ||
2115 | dev_dbg(codec->dev, "DC threshold[%d]: %u.\n", i, | ||
2116 | cs43130->dc_threshold[i]); | ||
2117 | |||
2118 | cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT], | ||
2119 | cs43130->dc_threshold); | ||
2120 | |||
2121 | exit: | ||
2122 | switch (cs43130->dev_id) { | ||
2123 | case CS43130_CHIP_ID: | ||
2124 | cs43130_hpload_proc(cs43130, hp_dis_cal_seq, | ||
2125 | ARRAY_SIZE(hp_dis_cal_seq), | ||
2126 | CS43130_HPLOAD_OFF_INT, ac_idx); | ||
2127 | break; | ||
2128 | case CS43131_CHIP_ID: | ||
2129 | cs43130_hpload_proc(cs43130, hp_dis_cal_seq2, | ||
2130 | ARRAY_SIZE(hp_dis_cal_seq2), | ||
2131 | CS43130_HPLOAD_OFF_INT, ac_idx); | ||
2132 | } | ||
2133 | |||
2134 | regmap_multi_reg_write(cs43130->regmap, hp_cln_seq, | ||
2135 | ARRAY_SIZE(hp_cln_seq)); | ||
2136 | |||
2137 | mutex_lock(&cs43130->clk_mutex); | ||
2138 | cs43130->clk_req--; | ||
2139 | /* clk not in use */ | ||
2140 | if (!cs43130->clk_req) | ||
2141 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO); | ||
2142 | mutex_unlock(&cs43130->clk_mutex); | ||
2143 | } | ||
2144 | |||
2145 | static irqreturn_t cs43130_irq_thread(int irq, void *data) | ||
2146 | { | ||
2147 | struct cs43130_private *cs43130 = (struct cs43130_private *)data; | ||
2148 | struct snd_soc_codec *codec = cs43130->codec; | ||
2149 | unsigned int stickies[CS43130_NUM_INT]; | ||
2150 | unsigned int irq_occurrance = 0; | ||
2151 | unsigned int masks[CS43130_NUM_INT]; | ||
2152 | int i, j; | ||
2153 | |||
2154 | for (i = 0; i < ARRAY_SIZE(stickies); i++) { | ||
2155 | regmap_read(cs43130->regmap, CS43130_INT_STATUS_1 + i, | ||
2156 | &stickies[i]); | ||
2157 | regmap_read(cs43130->regmap, CS43130_INT_MASK_1 + i, | ||
2158 | &masks[i]); | ||
2159 | } | ||
2160 | |||
2161 | for (i = 0; i < ARRAY_SIZE(stickies); i++) { | ||
2162 | stickies[i] = stickies[i] & (~masks[i]); | ||
2163 | for (j = 0; j < 8; j++) | ||
2164 | irq_occurrance += (stickies[i] >> j) & 1; | ||
2165 | } | ||
2166 | dev_dbg(codec->dev, "number of interrupts occurred (%u)\n", | ||
2167 | irq_occurrance); | ||
2168 | |||
2169 | if (!irq_occurrance) | ||
2170 | return IRQ_NONE; | ||
2171 | |||
2172 | if (stickies[0] & CS43130_XTAL_RDY_INT) { | ||
2173 | complete(&cs43130->xtal_rdy); | ||
2174 | return IRQ_HANDLED; | ||
2175 | } | ||
2176 | |||
2177 | if (stickies[0] & CS43130_PLL_RDY_INT) { | ||
2178 | complete(&cs43130->pll_rdy); | ||
2179 | return IRQ_HANDLED; | ||
2180 | } | ||
2181 | |||
2182 | if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) { | ||
2183 | cs43130->hpload_stat = stickies[3]; | ||
2184 | dev_err(codec->dev, | ||
2185 | "DC load has not completed before AC load (%x)\n", | ||
2186 | cs43130->hpload_stat); | ||
2187 | complete(&cs43130->hpload_evt); | ||
2188 | return IRQ_HANDLED; | ||
2189 | } | ||
2190 | |||
2191 | if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) { | ||
2192 | cs43130->hpload_stat = stickies[3]; | ||
2193 | dev_err(codec->dev, "HP unplugged during measurement (%x)\n", | ||
2194 | cs43130->hpload_stat); | ||
2195 | complete(&cs43130->hpload_evt); | ||
2196 | return IRQ_HANDLED; | ||
2197 | } | ||
2198 | |||
2199 | if (stickies[3] & CS43130_HPLOAD_OOR_INT) { | ||
2200 | cs43130->hpload_stat = stickies[3]; | ||
2201 | dev_err(codec->dev, "HP load out of range (%x)\n", | ||
2202 | cs43130->hpload_stat); | ||
2203 | complete(&cs43130->hpload_evt); | ||
2204 | return IRQ_HANDLED; | ||
2205 | } | ||
2206 | |||
2207 | if (stickies[3] & CS43130_HPLOAD_AC_INT) { | ||
2208 | cs43130->hpload_stat = stickies[3]; | ||
2209 | dev_dbg(codec->dev, "HP AC load measurement done (%x)\n", | ||
2210 | cs43130->hpload_stat); | ||
2211 | complete(&cs43130->hpload_evt); | ||
2212 | return IRQ_HANDLED; | ||
2213 | } | ||
2214 | |||
2215 | if (stickies[3] & CS43130_HPLOAD_DC_INT) { | ||
2216 | cs43130->hpload_stat = stickies[3]; | ||
2217 | dev_dbg(codec->dev, "HP DC load measurement done (%x)\n", | ||
2218 | cs43130->hpload_stat); | ||
2219 | complete(&cs43130->hpload_evt); | ||
2220 | return IRQ_HANDLED; | ||
2221 | } | ||
2222 | |||
2223 | if (stickies[3] & CS43130_HPLOAD_ON_INT) { | ||
2224 | cs43130->hpload_stat = stickies[3]; | ||
2225 | dev_dbg(codec->dev, "HP load state machine on done (%x)\n", | ||
2226 | cs43130->hpload_stat); | ||
2227 | complete(&cs43130->hpload_evt); | ||
2228 | return IRQ_HANDLED; | ||
2229 | } | ||
2230 | |||
2231 | if (stickies[3] & CS43130_HPLOAD_OFF_INT) { | ||
2232 | cs43130->hpload_stat = stickies[3]; | ||
2233 | dev_dbg(codec->dev, "HP load state machine off done (%x)\n", | ||
2234 | cs43130->hpload_stat); | ||
2235 | complete(&cs43130->hpload_evt); | ||
2236 | return IRQ_HANDLED; | ||
2237 | } | ||
2238 | |||
2239 | if (stickies[0] & CS43130_XTAL_ERR_INT) { | ||
2240 | dev_err(codec->dev, "Crystal err: clock is not running\n"); | ||
2241 | return IRQ_HANDLED; | ||
2242 | } | ||
2243 | |||
2244 | if (stickies[0] & CS43130_HP_UNPLUG_INT) { | ||
2245 | dev_dbg(codec->dev, "HP unplugged\n"); | ||
2246 | cs43130->hpload_done = false; | ||
2247 | snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK); | ||
2248 | return IRQ_HANDLED; | ||
2249 | } | ||
2250 | |||
2251 | if (stickies[0] & CS43130_HP_PLUG_INT) { | ||
2252 | if (cs43130->dc_meas && !cs43130->hpload_done && | ||
2253 | !work_busy(&cs43130->work)) { | ||
2254 | dev_dbg(codec->dev, "HP load queue work\n"); | ||
2255 | queue_work(cs43130->wq, &cs43130->work); | ||
2256 | } | ||
2257 | |||
2258 | snd_soc_jack_report(&cs43130->jack, SND_JACK_MECHANICAL, | ||
2259 | CS43130_JACK_MASK); | ||
2260 | return IRQ_HANDLED; | ||
2261 | } | ||
2262 | |||
2263 | return IRQ_NONE; | ||
2264 | } | ||
2265 | |||
2266 | static int cs43130_probe(struct snd_soc_codec *codec) | ||
2267 | { | ||
2268 | int ret; | ||
2269 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | ||
2270 | struct snd_soc_card *card = codec->component.card; | ||
2271 | unsigned int reg; | ||
2272 | |||
2273 | cs43130->codec = codec; | ||
2274 | |||
2275 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) { | ||
2276 | regmap_update_bits(cs43130->regmap, CS43130_CRYSTAL_SET, | ||
2277 | CS43130_XTAL_IBIAS_MASK, | ||
2278 | cs43130->xtal_ibias); | ||
2279 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
2280 | CS43130_XTAL_ERR_INT, 0); | ||
2281 | } | ||
2282 | |||
2283 | ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK, | ||
2284 | &cs43130->jack, NULL, 0); | ||
2285 | if (ret < 0) { | ||
2286 | dev_err(codec->dev, "Cannot create jack\n"); | ||
2287 | return ret; | ||
2288 | } | ||
2289 | |||
2290 | cs43130->hpload_done = false; | ||
2291 | if (cs43130->dc_meas) { | ||
2292 | ret = device_create_file(codec->dev, &dev_attr_hpload_dc_l); | ||
2293 | if (ret < 0) | ||
2294 | return ret; | ||
2295 | |||
2296 | ret = device_create_file(codec->dev, &dev_attr_hpload_dc_r); | ||
2297 | if (ret < 0) | ||
2298 | return ret; | ||
2299 | |||
2300 | ret = device_create_file(codec->dev, &dev_attr_hpload_ac_l); | ||
2301 | if (ret < 0) | ||
2302 | return ret; | ||
2303 | |||
2304 | ret = device_create_file(codec->dev, &dev_attr_hpload_ac_r); | ||
2305 | if (ret < 0) | ||
2306 | return ret; | ||
2307 | |||
2308 | cs43130->wq = create_singlethread_workqueue("cs43130_hp"); | ||
2309 | INIT_WORK(&cs43130->work, cs43130_imp_meas); | ||
2310 | } | ||
2311 | |||
2312 | regmap_read(cs43130->regmap, CS43130_INT_STATUS_1, ®); | ||
2313 | regmap_read(cs43130->regmap, CS43130_HP_STATUS, ®); | ||
2314 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
2315 | CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, 0); | ||
2316 | regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT, | ||
2317 | CS43130_HP_DETECT_CTRL_MASK, 0); | ||
2318 | regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT, | ||
2319 | CS43130_HP_DETECT_CTRL_MASK, | ||
2320 | CS43130_HP_DETECT_CTRL_MASK); | ||
2321 | |||
2322 | return 0; | ||
2323 | } | ||
2324 | |||
2325 | static struct snd_soc_codec_driver soc_codec_dev_cs43130 = { | ||
2326 | .probe = cs43130_probe, | ||
2327 | .component_driver = { | ||
2328 | .controls = cs43130_snd_controls, | ||
2329 | .num_controls = ARRAY_SIZE(cs43130_snd_controls), | ||
2330 | }, | ||
2331 | .set_sysclk = cs43130_codec_set_sysclk, | ||
2332 | .set_pll = cs43130_set_pll, | ||
2333 | }; | ||
2334 | |||
2335 | static const struct regmap_config cs43130_regmap = { | ||
2336 | .reg_bits = 24, | ||
2337 | .pad_bits = 8, | ||
2338 | .val_bits = 8, | ||
2339 | |||
2340 | .max_register = CS43130_LASTREG, | ||
2341 | .reg_defaults = cs43130_reg_defaults, | ||
2342 | .num_reg_defaults = ARRAY_SIZE(cs43130_reg_defaults), | ||
2343 | .readable_reg = cs43130_readable_register, | ||
2344 | .precious_reg = cs43130_precious_register, | ||
2345 | .volatile_reg = cs43130_volatile_register, | ||
2346 | .cache_type = REGCACHE_RBTREE, | ||
2347 | .use_single_rw = true, /* needed for regcache_sync */ | ||
2348 | }; | ||
2349 | |||
2350 | static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = { | ||
2351 | 50, | ||
2352 | 120, | ||
2353 | }; | ||
2354 | |||
2355 | static int cs43130_handle_device_data(struct i2c_client *i2c_client, | ||
2356 | struct cs43130_private *cs43130) | ||
2357 | { | ||
2358 | struct device_node *np = i2c_client->dev.of_node; | ||
2359 | unsigned int val; | ||
2360 | int i; | ||
2361 | |||
2362 | if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) { | ||
2363 | /* Crystal is unused. System clock is used for external MCLK */ | ||
2364 | cs43130->xtal_ibias = CS43130_XTAL_UNUSED; | ||
2365 | return 0; | ||
2366 | } | ||
2367 | |||
2368 | switch (val) { | ||
2369 | case 1: | ||
2370 | cs43130->xtal_ibias = CS43130_XTAL_IBIAS_7_5UA; | ||
2371 | break; | ||
2372 | case 2: | ||
2373 | cs43130->xtal_ibias = CS43130_XTAL_IBIAS_12_5UA; | ||
2374 | break; | ||
2375 | case 3: | ||
2376 | cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA; | ||
2377 | break; | ||
2378 | default: | ||
2379 | dev_err(&i2c_client->dev, | ||
2380 | "Invalid cirrus,xtal-ibias value: %d\n", val); | ||
2381 | return -EINVAL; | ||
2382 | } | ||
2383 | |||
2384 | cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure"); | ||
2385 | cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure"); | ||
2386 | |||
2387 | if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq, | ||
2388 | CS43130_AC_FREQ) < 0) { | ||
2389 | for (i = 0; i < CS43130_AC_FREQ; i++) | ||
2390 | cs43130->ac_freq[i] = cs43130_ac_freq[i]; | ||
2391 | } | ||
2392 | |||
2393 | if (of_property_read_u16_array(np, "cirrus,dc-threshold", | ||
2394 | cs43130->dc_threshold, | ||
2395 | CS43130_DC_THRESHOLD) < 0) { | ||
2396 | for (i = 0; i < CS43130_DC_THRESHOLD; i++) | ||
2397 | cs43130->dc_threshold[i] = cs43130_dc_threshold[i]; | ||
2398 | } | ||
2399 | |||
2400 | return 0; | ||
2401 | } | ||
2402 | |||
2403 | static int cs43130_i2c_probe(struct i2c_client *client, | ||
2404 | const struct i2c_device_id *id) | ||
2405 | { | ||
2406 | struct cs43130_private *cs43130; | ||
2407 | int ret; | ||
2408 | unsigned int devid = 0; | ||
2409 | unsigned int reg; | ||
2410 | int i; | ||
2411 | |||
2412 | cs43130 = devm_kzalloc(&client->dev, sizeof(*cs43130), GFP_KERNEL); | ||
2413 | if (!cs43130) | ||
2414 | return -ENOMEM; | ||
2415 | |||
2416 | i2c_set_clientdata(client, cs43130); | ||
2417 | |||
2418 | cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap); | ||
2419 | if (IS_ERR(cs43130->regmap)) { | ||
2420 | ret = PTR_ERR(cs43130->regmap); | ||
2421 | return ret; | ||
2422 | } | ||
2423 | |||
2424 | if (client->dev.of_node) { | ||
2425 | ret = cs43130_handle_device_data(client, cs43130); | ||
2426 | if (ret != 0) | ||
2427 | return ret; | ||
2428 | } | ||
2429 | for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++) | ||
2430 | cs43130->supplies[i].supply = cs43130_supply_names[i]; | ||
2431 | |||
2432 | ret = devm_regulator_bulk_get(&client->dev, | ||
2433 | ARRAY_SIZE(cs43130->supplies), | ||
2434 | cs43130->supplies); | ||
2435 | if (ret != 0) { | ||
2436 | dev_err(&client->dev, "Failed to request supplies: %d\n", ret); | ||
2437 | return ret; | ||
2438 | } | ||
2439 | ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies), | ||
2440 | cs43130->supplies); | ||
2441 | if (ret != 0) { | ||
2442 | dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); | ||
2443 | return ret; | ||
2444 | } | ||
2445 | |||
2446 | cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev, | ||
2447 | "reset", GPIOD_OUT_LOW); | ||
2448 | if (IS_ERR(cs43130->reset_gpio)) | ||
2449 | return PTR_ERR(cs43130->reset_gpio); | ||
2450 | |||
2451 | gpiod_set_value_cansleep(cs43130->reset_gpio, 1); | ||
2452 | |||
2453 | usleep_range(2000, 2050); | ||
2454 | |||
2455 | ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, ®); | ||
2456 | |||
2457 | devid = (reg & 0xFF) << 12; | ||
2458 | ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, ®); | ||
2459 | devid |= (reg & 0xFF) << 4; | ||
2460 | ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, ®); | ||
2461 | devid |= (reg & 0xF0) >> 4; | ||
2462 | |||
2463 | switch (devid) { | ||
2464 | case CS43130_CHIP_ID: | ||
2465 | case CS4399_CHIP_ID: | ||
2466 | case CS43131_CHIP_ID: | ||
2467 | case CS43198_CHIP_ID: | ||
2468 | break; | ||
2469 | default: | ||
2470 | dev_err(&client->dev, | ||
2471 | "CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n", | ||
2472 | devid, CS43130_CHIP_ID, CS4399_CHIP_ID, | ||
2473 | CS43131_CHIP_ID, CS43198_CHIP_ID); | ||
2474 | ret = -ENODEV; | ||
2475 | goto err; | ||
2476 | } | ||
2477 | |||
2478 | cs43130->dev_id = devid; | ||
2479 | ret = regmap_read(cs43130->regmap, CS43130_REV_ID, ®); | ||
2480 | if (ret < 0) { | ||
2481 | dev_err(&client->dev, "Get Revision ID failed\n"); | ||
2482 | goto err; | ||
2483 | } | ||
2484 | |||
2485 | dev_info(&client->dev, | ||
2486 | "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid, | ||
2487 | reg & 0xFF); | ||
2488 | |||
2489 | mutex_init(&cs43130->clk_mutex); | ||
2490 | |||
2491 | init_completion(&cs43130->xtal_rdy); | ||
2492 | init_completion(&cs43130->pll_rdy); | ||
2493 | init_completion(&cs43130->hpload_evt); | ||
2494 | |||
2495 | ret = devm_request_threaded_irq(&client->dev, client->irq, | ||
2496 | NULL, cs43130_irq_thread, | ||
2497 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, | ||
2498 | "cs43130", cs43130); | ||
2499 | if (ret != 0) { | ||
2500 | dev_err(&client->dev, "Failed to request IRQ: %d\n", ret); | ||
2501 | return ret; | ||
2502 | } | ||
2503 | |||
2504 | cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; | ||
2505 | |||
2506 | pm_runtime_set_autosuspend_delay(&client->dev, 100); | ||
2507 | pm_runtime_use_autosuspend(&client->dev); | ||
2508 | pm_runtime_set_active(&client->dev); | ||
2509 | pm_runtime_enable(&client->dev); | ||
2510 | |||
2511 | switch (cs43130->dev_id) { | ||
2512 | case CS43130_CHIP_ID: | ||
2513 | case CS43131_CHIP_ID: | ||
2514 | memcpy(all_hp_widgets, digital_hp_widgets, | ||
2515 | sizeof(digital_hp_widgets)); | ||
2516 | memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets), | ||
2517 | analog_hp_widgets, sizeof(analog_hp_widgets)); | ||
2518 | memcpy(all_hp_routes, digital_hp_routes, | ||
2519 | sizeof(digital_hp_routes)); | ||
2520 | memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes), | ||
2521 | analog_hp_routes, sizeof(analog_hp_routes)); | ||
2522 | |||
2523 | soc_codec_dev_cs43130.component_driver.dapm_widgets = | ||
2524 | all_hp_widgets; | ||
2525 | soc_codec_dev_cs43130.component_driver.num_dapm_widgets = | ||
2526 | ARRAY_SIZE(all_hp_widgets); | ||
2527 | soc_codec_dev_cs43130.component_driver.dapm_routes = | ||
2528 | all_hp_routes; | ||
2529 | soc_codec_dev_cs43130.component_driver.num_dapm_routes = | ||
2530 | ARRAY_SIZE(all_hp_routes); | ||
2531 | break; | ||
2532 | case CS43198_CHIP_ID: | ||
2533 | case CS4399_CHIP_ID: | ||
2534 | soc_codec_dev_cs43130.component_driver.dapm_widgets = | ||
2535 | digital_hp_widgets; | ||
2536 | soc_codec_dev_cs43130.component_driver.num_dapm_widgets = | ||
2537 | ARRAY_SIZE(digital_hp_widgets); | ||
2538 | soc_codec_dev_cs43130.component_driver.dapm_routes = | ||
2539 | digital_hp_routes; | ||
2540 | soc_codec_dev_cs43130.component_driver.num_dapm_routes = | ||
2541 | ARRAY_SIZE(digital_hp_routes); | ||
2542 | } | ||
2543 | |||
2544 | ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_cs43130, | ||
2545 | cs43130_dai, ARRAY_SIZE(cs43130_dai)); | ||
2546 | if (ret < 0) { | ||
2547 | dev_err(&client->dev, | ||
2548 | "snd_soc_register_codec failed with ret = %d\n", ret); | ||
2549 | goto err; | ||
2550 | } | ||
2551 | |||
2552 | regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG, | ||
2553 | CS43130_ASP_3ST_MASK, 0); | ||
2554 | regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG, | ||
2555 | CS43130_XSP_3ST_MASK, 0); | ||
2556 | |||
2557 | return 0; | ||
2558 | err: | ||
2559 | return ret; | ||
2560 | } | ||
2561 | |||
2562 | static int cs43130_i2c_remove(struct i2c_client *client) | ||
2563 | { | ||
2564 | struct cs43130_private *cs43130 = i2c_get_clientdata(client); | ||
2565 | |||
2566 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) | ||
2567 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
2568 | CS43130_XTAL_ERR_INT, | ||
2569 | 1 << CS43130_XTAL_ERR_INT_SHIFT); | ||
2570 | |||
2571 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
2572 | CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, | ||
2573 | CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT); | ||
2574 | |||
2575 | if (cs43130->dc_meas) { | ||
2576 | cancel_work_sync(&cs43130->work); | ||
2577 | flush_workqueue(cs43130->wq); | ||
2578 | |||
2579 | device_remove_file(&client->dev, &dev_attr_hpload_dc_l); | ||
2580 | device_remove_file(&client->dev, &dev_attr_hpload_dc_r); | ||
2581 | device_remove_file(&client->dev, &dev_attr_hpload_ac_l); | ||
2582 | device_remove_file(&client->dev, &dev_attr_hpload_ac_r); | ||
2583 | } | ||
2584 | |||
2585 | if (cs43130->reset_gpio) | ||
2586 | gpiod_set_value_cansleep(cs43130->reset_gpio, 0); | ||
2587 | |||
2588 | pm_runtime_disable(&client->dev); | ||
2589 | regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); | ||
2590 | |||
2591 | snd_soc_unregister_codec(&client->dev); | ||
2592 | |||
2593 | return 0; | ||
2594 | } | ||
2595 | |||
2596 | static int cs43130_runtime_suspend(struct device *dev) | ||
2597 | { | ||
2598 | struct cs43130_private *cs43130 = dev_get_drvdata(dev); | ||
2599 | |||
2600 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) | ||
2601 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
2602 | CS43130_XTAL_ERR_INT, | ||
2603 | 1 << CS43130_XTAL_ERR_INT_SHIFT); | ||
2604 | |||
2605 | regcache_cache_only(cs43130->regmap, true); | ||
2606 | regcache_mark_dirty(cs43130->regmap); | ||
2607 | |||
2608 | gpiod_set_value_cansleep(cs43130->reset_gpio, 0); | ||
2609 | |||
2610 | regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); | ||
2611 | |||
2612 | return 0; | ||
2613 | } | ||
2614 | |||
2615 | static int cs43130_runtime_resume(struct device *dev) | ||
2616 | { | ||
2617 | struct cs43130_private *cs43130 = dev_get_drvdata(dev); | ||
2618 | int ret; | ||
2619 | |||
2620 | ret = regulator_bulk_enable(CS43130_NUM_SUPPLIES, cs43130->supplies); | ||
2621 | if (ret != 0) { | ||
2622 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
2623 | return ret; | ||
2624 | } | ||
2625 | |||
2626 | regcache_cache_only(cs43130->regmap, false); | ||
2627 | |||
2628 | gpiod_set_value_cansleep(cs43130->reset_gpio, 1); | ||
2629 | |||
2630 | usleep_range(2000, 2050); | ||
2631 | |||
2632 | ret = regcache_sync(cs43130->regmap); | ||
2633 | if (ret != 0) { | ||
2634 | dev_err(dev, "Failed to restore register cache\n"); | ||
2635 | goto err; | ||
2636 | } | ||
2637 | |||
2638 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) | ||
2639 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | ||
2640 | CS43130_XTAL_ERR_INT, 0); | ||
2641 | |||
2642 | return 0; | ||
2643 | err: | ||
2644 | regcache_cache_only(cs43130->regmap, true); | ||
2645 | regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); | ||
2646 | |||
2647 | return ret; | ||
2648 | } | ||
2649 | |||
2650 | static const struct dev_pm_ops cs43130_runtime_pm = { | ||
2651 | SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume, | ||
2652 | NULL) | ||
2653 | }; | ||
2654 | |||
2655 | static const struct of_device_id cs43130_of_match[] = { | ||
2656 | {.compatible = "cirrus,cs43130",}, | ||
2657 | {.compatible = "cirrus,cs4399",}, | ||
2658 | {.compatible = "cirrus,cs43131",}, | ||
2659 | {.compatible = "cirrus,cs43198",}, | ||
2660 | {}, | ||
2661 | }; | ||
2662 | |||
2663 | MODULE_DEVICE_TABLE(of, cs43130_of_match); | ||
2664 | |||
2665 | static const struct i2c_device_id cs43130_i2c_id[] = { | ||
2666 | {"cs43130", 0}, | ||
2667 | {"cs4399", 0}, | ||
2668 | {"cs43131", 0}, | ||
2669 | {"cs43198", 0}, | ||
2670 | {} | ||
2671 | }; | ||
2672 | |||
2673 | MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id); | ||
2674 | |||
2675 | static struct i2c_driver cs43130_i2c_driver = { | ||
2676 | .driver = { | ||
2677 | .name = "cs43130", | ||
2678 | .of_match_table = cs43130_of_match, | ||
2679 | .pm = &cs43130_runtime_pm, | ||
2680 | }, | ||
2681 | .id_table = cs43130_i2c_id, | ||
2682 | .probe = cs43130_i2c_probe, | ||
2683 | .remove = cs43130_i2c_remove, | ||
2684 | }; | ||
2685 | |||
2686 | module_i2c_driver(cs43130_i2c_driver); | ||
2687 | |||
2688 | MODULE_AUTHOR("Li Xu <li.xu@cirrus.com>"); | ||
2689 | MODULE_DESCRIPTION("Cirrus Logic CS43130 ALSA SoC Codec Driver"); | ||
2690 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs43130.h b/sound/soc/codecs/cs43130.h new file mode 100644 index 000000000000..781258418d89 --- /dev/null +++ b/sound/soc/codecs/cs43130.h | |||
@@ -0,0 +1,546 @@ | |||
1 | /* | ||
2 | * ALSA SoC CS43130 codec driver | ||
3 | * | ||
4 | * Copyright 2017 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Author: Li Xu <li.xu@cirrus.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef __CS43130_H__ | ||
20 | #define __CS43130_H__ | ||
21 | |||
22 | /* CS43130 registers addresses */ | ||
23 | /* all reg address is shifted by a byte for control byte to be LSB */ | ||
24 | #define CS43130_FIRSTREG 0x010000 | ||
25 | #define CS43130_LASTREG 0x190000 | ||
26 | #define CS43130_CHIP_ID 0x00043130 | ||
27 | #define CS4399_CHIP_ID 0x00043990 | ||
28 | #define CS43131_CHIP_ID 0x00043131 | ||
29 | #define CS43198_CHIP_ID 0x00043198 | ||
30 | #define CS43130_DEVID_AB 0x010000 /* Device ID A & B [RO] */ | ||
31 | #define CS43130_DEVID_CD 0x010001 /* Device ID C & D [RO] */ | ||
32 | #define CS43130_DEVID_E 0x010002 /* Device ID E [RO] */ | ||
33 | #define CS43130_FAB_ID 0x010003 /* Fab ID [RO] */ | ||
34 | #define CS43130_REV_ID 0x010004 /* Revision ID [RO] */ | ||
35 | #define CS43130_SUBREV_ID 0x010005 /* Subrevision ID */ | ||
36 | #define CS43130_SYS_CLK_CTL_1 0x010006 /* System Clocking Ctl 1 */ | ||
37 | #define CS43130_SP_SRATE 0x01000B /* Serial Port Sample Rate */ | ||
38 | #define CS43130_SP_BITSIZE 0x01000C /* Serial Port Bit Size */ | ||
39 | #define CS43130_PAD_INT_CFG 0x01000D /* Pad Interface Config */ | ||
40 | #define CS43130_DXD1 0x010010 /* DXD1 */ | ||
41 | #define CS43130_DXD7 0x010025 /* DXD7 */ | ||
42 | #define CS43130_DXD19 0x010026 /* DXD19 */ | ||
43 | #define CS43130_DXD17 0x010027 /* DXD17 */ | ||
44 | #define CS43130_DXD18 0x010028 /* DXD18 */ | ||
45 | #define CS43130_DXD12 0x01002C /* DXD12 */ | ||
46 | #define CS43130_DXD8 0x01002E /* DXD8 */ | ||
47 | #define CS43130_PWDN_CTL 0x020000 /* Power Down Ctl */ | ||
48 | #define CS43130_DXD2 0x020019 /* DXD2 */ | ||
49 | #define CS43130_CRYSTAL_SET 0x020052 /* Crystal Setting */ | ||
50 | #define CS43130_PLL_SET_1 0x030001 /* PLL Setting 1 */ | ||
51 | #define CS43130_PLL_SET_2 0x030002 /* PLL Setting 2 */ | ||
52 | #define CS43130_PLL_SET_3 0x030003 /* PLL Setting 3 */ | ||
53 | #define CS43130_PLL_SET_4 0x030004 /* PLL Setting 4 */ | ||
54 | #define CS43130_PLL_SET_5 0x030005 /* PLL Setting 5 */ | ||
55 | #define CS43130_PLL_SET_6 0x030008 /* PLL Setting 6 */ | ||
56 | #define CS43130_PLL_SET_7 0x03000A /* PLL Setting 7 */ | ||
57 | #define CS43130_PLL_SET_8 0x03001B /* PLL Setting 8 */ | ||
58 | #define CS43130_PLL_SET_9 0x040002 /* PLL Setting 9 */ | ||
59 | #define CS43130_PLL_SET_10 0x040003 /* PLL Setting 10 */ | ||
60 | #define CS43130_CLKOUT_CTL 0x040004 /* CLKOUT Ctl */ | ||
61 | #define CS43130_ASP_NUM_1 0x040010 /* ASP Numerator 1 */ | ||
62 | #define CS43130_ASP_NUM_2 0x040011 /* ASP Numerator 2 */ | ||
63 | #define CS43130_ASP_DEN_1 0x040012 /* ASP Denominator 1 */ | ||
64 | #define CS43130_ASP_DEN_2 0x040013 /* ASP Denominator 2 */ | ||
65 | #define CS43130_ASP_LRCK_HI_TIME_1 0x040014 /* ASP LRCK High Time 1 */ | ||
66 | #define CS43130_ASP_LRCK_HI_TIME_2 0x040015 /* ASP LRCK High Time 2 */ | ||
67 | #define CS43130_ASP_LRCK_PERIOD_1 0x040016 /* ASP LRCK Period 1 */ | ||
68 | #define CS43130_ASP_LRCK_PERIOD_2 0x040017 /* ASP LRCK Period 2 */ | ||
69 | #define CS43130_ASP_CLOCK_CONF 0x040018 /* ASP Clock Config */ | ||
70 | #define CS43130_ASP_FRAME_CONF 0x040019 /* ASP Frame Config */ | ||
71 | #define CS43130_XSP_NUM_1 0x040020 /* XSP Numerator 1 */ | ||
72 | #define CS43130_XSP_NUM_2 0x040021 /* XSP Numerator 2 */ | ||
73 | #define CS43130_XSP_DEN_1 0x040022 /* XSP Denominator 1 */ | ||
74 | #define CS43130_XSP_DEN_2 0x040023 /* XSP Denominator 2 */ | ||
75 | #define CS43130_XSP_LRCK_HI_TIME_1 0x040024 /* XSP LRCK High Time 1 */ | ||
76 | #define CS43130_XSP_LRCK_HI_TIME_2 0x040025 /* XSP LRCK High Time 2 */ | ||
77 | #define CS43130_XSP_LRCK_PERIOD_1 0x040026 /* XSP LRCK Period 1 */ | ||
78 | #define CS43130_XSP_LRCK_PERIOD_2 0x040027 /* XSP LRCK Period 2 */ | ||
79 | #define CS43130_XSP_CLOCK_CONF 0x040028 /* XSP Clock Config */ | ||
80 | #define CS43130_XSP_FRAME_CONF 0x040029 /* XSP Frame Config */ | ||
81 | #define CS43130_ASP_CH_1_LOC 0x050000 /* ASP Chan 1 Location */ | ||
82 | #define CS43130_ASP_CH_2_LOC 0x050001 /* ASP Chan 2 Location */ | ||
83 | #define CS43130_ASP_CH_1_SZ_EN 0x05000A /* ASP Chan 1 Size, Enable */ | ||
84 | #define CS43130_ASP_CH_2_SZ_EN 0x05000B /* ASP Chan 2 Size, Enable */ | ||
85 | #define CS43130_XSP_CH_1_LOC 0x060000 /* XSP Chan 1 Location */ | ||
86 | #define CS43130_XSP_CH_2_LOC 0x060001 /* XSP Chan 2 Location */ | ||
87 | #define CS43130_XSP_CH_1_SZ_EN 0x06000A /* XSP Chan 1 Size, Enable */ | ||
88 | #define CS43130_XSP_CH_2_SZ_EN 0x06000B /* XSP Chan 2 Size, Enable */ | ||
89 | #define CS43130_DSD_VOL_B 0x070000 /* DSD Volume B */ | ||
90 | #define CS43130_DSD_VOL_A 0x070001 /* DSD Volume A */ | ||
91 | #define CS43130_DSD_PATH_CTL_1 0x070002 /* DSD Proc Path Sig Ctl 1 */ | ||
92 | #define CS43130_DSD_INT_CFG 0x070003 /* DSD Interface Config */ | ||
93 | #define CS43130_DSD_PATH_CTL_2 0x070004 /* DSD Proc Path Sig Ctl 2 */ | ||
94 | #define CS43130_DSD_PCM_MIX_CTL 0x070005 /* DSD and PCM Mixing Ctl */ | ||
95 | #define CS43130_DSD_PATH_CTL_3 0x070006 /* DSD Proc Path Sig Ctl 3 */ | ||
96 | #define CS43130_HP_OUT_CTL_1 0x080000 /* HP Output Ctl 1 */ | ||
97 | #define CS43130_DXD16 0x080024 /* DXD16 */ | ||
98 | #define CS43130_DXD13 0x080032 /* DXD13 */ | ||
99 | #define CS43130_PCM_FILT_OPT 0x090000 /* PCM Filter Option */ | ||
100 | #define CS43130_PCM_VOL_B 0x090001 /* PCM Volume B */ | ||
101 | #define CS43130_PCM_VOL_A 0x090002 /* PCM Volume A */ | ||
102 | #define CS43130_PCM_PATH_CTL_1 0x090003 /* PCM Path Signal Ctl 1 */ | ||
103 | #define CS43130_PCM_PATH_CTL_2 0x090004 /* PCM Path Signal Ctl 2 */ | ||
104 | #define CS43130_DXD6 0x090097 /* DXD6 */ | ||
105 | #define CS43130_CLASS_H_CTL 0x0B0000 /* Class H Ctl */ | ||
106 | #define CS43130_DXD15 0x0B0005 /* DXD15 */ | ||
107 | #define CS43130_DXD14 0x0B0006 /* DXD14 */ | ||
108 | #define CS43130_DXD3 0x0C0002 /* DXD3 */ | ||
109 | #define CS43130_DXD10 0x0C0003 /* DXD10 */ | ||
110 | #define CS43130_DXD11 0x0C0005 /* DXD11 */ | ||
111 | #define CS43130_DXD9 0x0C0006 /* DXD9 */ | ||
112 | #define CS43130_DXD4 0x0C0009 /* DXD4 */ | ||
113 | #define CS43130_DXD5 0x0C000E /* DXD5 */ | ||
114 | #define CS43130_HP_DETECT 0x0D0000 /* HP Detect */ | ||
115 | #define CS43130_HP_STATUS 0x0D0001 /* HP Status [RO] */ | ||
116 | #define CS43130_HP_LOAD_1 0x0E0000 /* HP Load 1 */ | ||
117 | #define CS43130_HP_MEAS_LOAD_1 0x0E0003 /* HP Load Measurement 1 */ | ||
118 | #define CS43130_HP_MEAS_LOAD_2 0x0E0004 /* HP Load Measurement 2 */ | ||
119 | #define CS43130_HP_DC_STAT_1 0x0E000D /* HP DC Load Status 0 [RO] */ | ||
120 | #define CS43130_HP_DC_STAT_2 0x0E000E /* HP DC Load Status 1 [RO] */ | ||
121 | #define CS43130_HP_AC_STAT_1 0x0E0010 /* HP AC Load Status 0 [RO] */ | ||
122 | #define CS43130_HP_AC_STAT_2 0x0E0011 /* HP AC Load Status 1 [RO] */ | ||
123 | #define CS43130_HP_LOAD_STAT 0x0E001A /* HP Load Status [RO] */ | ||
124 | #define CS43130_INT_STATUS_1 0x0F0000 /* Interrupt Status 1 */ | ||
125 | #define CS43130_INT_STATUS_2 0x0F0001 /* Interrupt Status 2 */ | ||
126 | #define CS43130_INT_STATUS_3 0x0F0002 /* Interrupt Status 3 */ | ||
127 | #define CS43130_INT_STATUS_4 0x0F0003 /* Interrupt Status 4 */ | ||
128 | #define CS43130_INT_STATUS_5 0x0F0004 /* Interrupt Status 5 */ | ||
129 | #define CS43130_INT_MASK_1 0x0F0010 /* Interrupt Mask 1 */ | ||
130 | #define CS43130_INT_MASK_2 0x0F0011 /* Interrupt Mask 2 */ | ||
131 | #define CS43130_INT_MASK_3 0x0F0012 /* Interrupt Mask 3 */ | ||
132 | #define CS43130_INT_MASK_4 0x0F0013 /* Interrupt Mask 4 */ | ||
133 | #define CS43130_INT_MASK_5 0x0F0014 /* Interrupt Mask 5 */ | ||
134 | |||
135 | #define CS43130_MCLK_SRC_SEL_MASK 0x03 | ||
136 | #define CS43130_MCLK_SRC_SEL_SHIFT 0 | ||
137 | #define CS43130_MCLK_INT_MASK 0x04 | ||
138 | #define CS43130_MCLK_INT_SHIFT 2 | ||
139 | #define CS43130_CH_BITSIZE_MASK 0x03 | ||
140 | #define CS43130_CH_EN_MASK 0x04 | ||
141 | #define CS43130_CH_EN_SHIFT 2 | ||
142 | #define CS43130_ASP_BITSIZE_MASK 0x03 | ||
143 | #define CS43130_XSP_BITSIZE_MASK 0x0C | ||
144 | #define CS43130_XSP_BITSIZE_SHIFT 2 | ||
145 | #define CS43130_SP_BITSIZE_ASP_SHIFT 0 | ||
146 | #define CS43130_HP_DETECT_CTRL_SHIFT 6 | ||
147 | #define CS43130_HP_DETECT_CTRL_MASK (0x03 << CS43130_HP_DETECT_CTRL_SHIFT) | ||
148 | #define CS43130_HP_DETECT_INV_SHIFT 5 | ||
149 | #define CS43130_HP_DETECT_INV_MASK (1 << CS43130_HP_DETECT_INV_SHIFT) | ||
150 | |||
151 | /* CS43130_INT_MASK_1 */ | ||
152 | #define CS43130_HP_PLUG_INT_SHIFT 6 | ||
153 | #define CS43130_HP_PLUG_INT (1 << CS43130_HP_PLUG_INT_SHIFT) | ||
154 | #define CS43130_HP_UNPLUG_INT_SHIFT 5 | ||
155 | #define CS43130_HP_UNPLUG_INT (1 << CS43130_HP_UNPLUG_INT_SHIFT) | ||
156 | #define CS43130_XTAL_RDY_INT_SHIFT 4 | ||
157 | #define CS43130_XTAL_RDY_INT_MASK 0x10 | ||
158 | #define CS43130_XTAL_RDY_INT (1 << CS43130_XTAL_RDY_INT_SHIFT) | ||
159 | #define CS43130_XTAL_ERR_INT_SHIFT 3 | ||
160 | #define CS43130_XTAL_ERR_INT (1 << CS43130_XTAL_ERR_INT_SHIFT) | ||
161 | #define CS43130_PLL_RDY_INT_MASK 0x04 | ||
162 | #define CS43130_PLL_RDY_INT_SHIFT 2 | ||
163 | #define CS43130_PLL_RDY_INT (1 << CS43130_PLL_RDY_INT_SHIFT) | ||
164 | |||
165 | /* CS43130_INT_MASK_4 */ | ||
166 | #define CS43130_INT_MASK_ALL 0xFF | ||
167 | #define CS43130_HPLOAD_NO_DC_INT_SHIFT 7 | ||
168 | #define CS43130_HPLOAD_NO_DC_INT (1 << CS43130_HPLOAD_NO_DC_INT_SHIFT) | ||
169 | #define CS43130_HPLOAD_UNPLUG_INT_SHIFT 6 | ||
170 | #define CS43130_HPLOAD_UNPLUG_INT (1 << CS43130_HPLOAD_UNPLUG_INT_SHIFT) | ||
171 | #define CS43130_HPLOAD_OOR_INT_SHIFT 4 | ||
172 | #define CS43130_HPLOAD_OOR_INT (1 << CS43130_HPLOAD_OOR_INT_SHIFT) | ||
173 | #define CS43130_HPLOAD_AC_INT_SHIFT 3 | ||
174 | #define CS43130_HPLOAD_AC_INT (1 << CS43130_HPLOAD_AC_INT_SHIFT) | ||
175 | #define CS43130_HPLOAD_DC_INT_SHIFT 2 | ||
176 | #define CS43130_HPLOAD_DC_INT (1 << CS43130_HPLOAD_DC_INT_SHIFT) | ||
177 | #define CS43130_HPLOAD_OFF_INT_SHIFT 1 | ||
178 | #define CS43130_HPLOAD_OFF_INT (1 << CS43130_HPLOAD_OFF_INT_SHIFT) | ||
179 | #define CS43130_HPLOAD_ON_INT 1 | ||
180 | |||
181 | /* CS43130_HP_LOAD_1 */ | ||
182 | #define CS43130_HPLOAD_EN_SHIFT 7 | ||
183 | #define CS43130_HPLOAD_EN (1 << CS43130_HPLOAD_EN_SHIFT) | ||
184 | #define CS43130_HPLOAD_CHN_SEL_SHIFT 4 | ||
185 | #define CS43130_HPLOAD_CHN_SEL (1 << CS43130_HPLOAD_CHN_SEL_SHIFT) | ||
186 | #define CS43130_HPLOAD_AC_START_SHIFT 1 | ||
187 | #define CS43130_HPLOAD_AC_START (1 << CS43130_HPLOAD_AC_START_SHIFT) | ||
188 | #define CS43130_HPLOAD_DC_START 1 | ||
189 | |||
190 | /* Reg CS43130_SP_BITSIZE */ | ||
191 | #define CS43130_SP_BIT_SIZE_8 0x03 | ||
192 | #define CS43130_SP_BIT_SIZE_16 0x02 | ||
193 | #define CS43130_SP_BIT_SIZE_24 0x01 | ||
194 | #define CS43130_SP_BIT_SIZE_32 0x00 | ||
195 | |||
196 | /* Reg CS43130_SP_CH_SZ_EN */ | ||
197 | #define CS43130_CH_BIT_SIZE_8 0x00 | ||
198 | #define CS43130_CH_BIT_SIZE_16 0x01 | ||
199 | #define CS43130_CH_BIT_SIZE_24 0x02 | ||
200 | #define CS43130_CH_BIT_SIZE_32 0x03 | ||
201 | |||
202 | /* PLL */ | ||
203 | #define CS43130_PLL_START_MASK 0x01 | ||
204 | #define CS43130_PLL_MODE_MASK 0x02 | ||
205 | #define CS43130_PLL_MODE_SHIFT 1 | ||
206 | |||
207 | #define CS43130_PLL_REF_PREDIV_MASK 0x3 | ||
208 | |||
209 | #define CS43130_SP_STP_MASK 0x10 | ||
210 | #define CS43130_SP_STP_SHIFT 4 | ||
211 | #define CS43130_SP_5050_MASK 0x08 | ||
212 | #define CS43130_SP_5050_SHIFT 3 | ||
213 | #define CS43130_SP_FSD_MASK 0x07 | ||
214 | |||
215 | #define CS43130_SP_MODE_MASK 0x10 | ||
216 | #define CS43130_SP_MODE_SHIFT 4 | ||
217 | #define CS43130_SP_SCPOL_OUT_MASK 0x08 | ||
218 | #define CS43130_SP_SCPOL_OUT_SHIFT 3 | ||
219 | #define CS43130_SP_SCPOL_IN_MASK 0x04 | ||
220 | #define CS43130_SP_SCPOL_IN_SHIFT 2 | ||
221 | #define CS43130_SP_LCPOL_OUT_MASK 0x02 | ||
222 | #define CS43130_SP_LCPOL_OUT_SHIFT 1 | ||
223 | #define CS43130_SP_LCPOL_IN_MASK 0x01 | ||
224 | #define CS43130_SP_LCPOL_IN_SHIFT 0 | ||
225 | |||
226 | /* Reg CS43130_PWDN_CTL */ | ||
227 | #define CS43130_PDN_XSP_MASK 0x80 | ||
228 | #define CS43130_PDN_XSP_SHIFT 7 | ||
229 | #define CS43130_PDN_ASP_MASK 0x40 | ||
230 | #define CS43130_PDN_ASP_SHIFT 6 | ||
231 | #define CS43130_PDN_DSPIF_MASK 0x20 | ||
232 | #define CS43130_PDN_DSDIF_SHIFT 5 | ||
233 | #define CS43130_PDN_HP_MASK 0x10 | ||
234 | #define CS43130_PDN_HP_SHIFT 4 | ||
235 | #define CS43130_PDN_XTAL_MASK 0x08 | ||
236 | #define CS43130_PDN_XTAL_SHIFT 3 | ||
237 | #define CS43130_PDN_PLL_MASK 0x04 | ||
238 | #define CS43130_PDN_PLL_SHIFT 2 | ||
239 | #define CS43130_PDN_CLKOUT_MASK 0x02 | ||
240 | #define CS43130_PDN_CLKOUT_SHIFT 1 | ||
241 | |||
242 | /* Reg CS43130_HP_OUT_CTL_1 */ | ||
243 | #define CS43130_HP_IN_EN_SHIFT 3 | ||
244 | #define CS43130_HP_IN_EN_MASK 0x08 | ||
245 | |||
246 | /* Reg CS43130_PAD_INT_CFG */ | ||
247 | #define CS43130_ASP_3ST_MASK 0x01 | ||
248 | #define CS43130_XSP_3ST_MASK 0x02 | ||
249 | |||
250 | /* Reg CS43130_PLL_SET_2 */ | ||
251 | #define CS43130_PLL_DIV_DATA_MASK 0x000000FF | ||
252 | #define CS43130_PLL_DIV_FRAC_0_DATA_SHIFT 0 | ||
253 | |||
254 | /* Reg CS43130_PLL_SET_3 */ | ||
255 | #define CS43130_PLL_DIV_FRAC_1_DATA_SHIFT 8 | ||
256 | |||
257 | /* Reg CS43130_PLL_SET_4 */ | ||
258 | #define CS43130_PLL_DIV_FRAC_2_DATA_SHIFT 16 | ||
259 | |||
260 | /* Reg CS43130_SP_DEN_1 */ | ||
261 | #define CS43130_SP_M_LSB_DATA_MASK 0x00FF | ||
262 | #define CS43130_SP_M_LSB_DATA_SHIFT 0 | ||
263 | |||
264 | /* Reg CS43130_SP_DEN_2 */ | ||
265 | #define CS43130_SP_M_MSB_DATA_MASK 0xFF00 | ||
266 | #define CS43130_SP_M_MSB_DATA_SHIFT 8 | ||
267 | |||
268 | /* Reg CS43130_SP_NUM_1 */ | ||
269 | #define CS43130_SP_N_LSB_DATA_MASK 0x00FF | ||
270 | #define CS43130_SP_N_LSB_DATA_SHIFT 0 | ||
271 | |||
272 | /* Reg CS43130_SP_NUM_2 */ | ||
273 | #define CS43130_SP_N_MSB_DATA_MASK 0xFF00 | ||
274 | #define CS43130_SP_N_MSB_DATA_SHIFT 8 | ||
275 | |||
276 | /* Reg CS43130_SP_LRCK_HI_TIME_1 */ | ||
277 | #define CS43130_SP_LCHI_DATA_MASK 0x00FF | ||
278 | #define CS43130_SP_LCHI_LSB_DATA_SHIFT 0 | ||
279 | |||
280 | /* Reg CS43130_SP_LRCK_HI_TIME_2 */ | ||
281 | #define CS43130_SP_LCHI_MSB_DATA_SHIFT 8 | ||
282 | |||
283 | /* Reg CS43130_SP_LRCK_PERIOD_1 */ | ||
284 | #define CS43130_SP_LCPR_DATA_MASK 0x00FF | ||
285 | #define CS43130_SP_LCPR_LSB_DATA_SHIFT 0 | ||
286 | |||
287 | /* Reg CS43130_SP_LRCK_PERIOD_2 */ | ||
288 | #define CS43130_SP_LCPR_MSB_DATA_SHIFT 8 | ||
289 | |||
290 | #define CS43130_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ | ||
291 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
292 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
293 | SNDRV_PCM_FMTBIT_S32_LE) | ||
294 | |||
295 | #define CS43130_DOP_FORMATS (SNDRV_PCM_FMTBIT_DSD_U16_LE | \ | ||
296 | SNDRV_PCM_FMTBIT_DSD_U16_BE | \ | ||
297 | SNDRV_PCM_FMTBIT_S24_LE) | ||
298 | |||
299 | /* Reg CS43130_CRYSTAL_SET */ | ||
300 | #define CS43130_XTAL_IBIAS_MASK 0x07 | ||
301 | |||
302 | /* Reg CS43130_PATH_CTL_1 */ | ||
303 | #define CS43130_MUTE_MASK 0x03 | ||
304 | #define CS43130_MUTE_EN 0x03 | ||
305 | |||
306 | /* Reg CS43130_DSD_INT_CFG */ | ||
307 | #define CS43130_DSD_MASTER 0x04 | ||
308 | |||
309 | /* Reg CS43130_DSD_PATH_CTL_2 */ | ||
310 | #define CS43130_DSD_SRC_MASK 0x60 | ||
311 | #define CS43130_DSD_SRC_SHIFT 5 | ||
312 | #define CS43130_DSD_EN_SHIFT 4 | ||
313 | #define CS43130_DSD_SPEED_MASK 0x04 | ||
314 | #define CS43130_DSD_SPEED_SHIFT 2 | ||
315 | |||
316 | /* Reg CS43130_DSD_PCM_MIX_CTL */ | ||
317 | #define CS43130_MIX_PCM_PREP_SHIFT 1 | ||
318 | #define CS43130_MIX_PCM_PREP_MASK 0x02 | ||
319 | |||
320 | #define CS43130_MIX_PCM_DSD_SHIFT 0 | ||
321 | #define CS43130_MIX_PCM_DSD_MASK 0x01 | ||
322 | |||
323 | /* Reg CS43130_HP_MEAS_LOAD */ | ||
324 | #define CS43130_HP_MEAS_LOAD_MASK 0x000000FF | ||
325 | #define CS43130_HP_MEAS_LOAD_1_SHIFT 0 | ||
326 | #define CS43130_HP_MEAS_LOAD_2_SHIFT 8 | ||
327 | |||
328 | #define CS43130_MCLK_22M 22579200 | ||
329 | #define CS43130_MCLK_24M 24576000 | ||
330 | |||
331 | #define CS43130_LINEOUT_LOAD 5000 | ||
332 | #define CS43130_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT) | ||
333 | #define CS43130_JACK_HEADPHONE (SND_JACK_MECHANICAL | \ | ||
334 | SND_JACK_HEADPHONE) | ||
335 | #define CS43130_JACK_MASK (SND_JACK_MECHANICAL | \ | ||
336 | SND_JACK_LINEOUT | \ | ||
337 | SND_JACK_HEADPHONE) | ||
338 | |||
339 | enum cs43130_dsd_src { | ||
340 | CS43130_DSD_SRC_DSD = 0, | ||
341 | CS43130_DSD_SRC_ASP = 2, | ||
342 | CS43130_DSD_SRC_XSP = 3, | ||
343 | }; | ||
344 | |||
345 | enum cs43130_asp_rate { | ||
346 | CS43130_ASP_SPRATE_32K = 0, | ||
347 | CS43130_ASP_SPRATE_44_1K, | ||
348 | CS43130_ASP_SPRATE_48K, | ||
349 | CS43130_ASP_SPRATE_88_2K, | ||
350 | CS43130_ASP_SPRATE_96K, | ||
351 | CS43130_ASP_SPRATE_176_4K, | ||
352 | CS43130_ASP_SPRATE_192K, | ||
353 | CS43130_ASP_SPRATE_352_8K, | ||
354 | CS43130_ASP_SPRATE_384K, | ||
355 | }; | ||
356 | |||
357 | enum cs43130_mclk_src_sel { | ||
358 | CS43130_MCLK_SRC_EXT = 0, | ||
359 | CS43130_MCLK_SRC_PLL, | ||
360 | CS43130_MCLK_SRC_RCO | ||
361 | }; | ||
362 | |||
363 | enum cs43130_mclk_int_freq { | ||
364 | CS43130_MCLK_24P5 = 0, | ||
365 | CS43130_MCLK_22P5, | ||
366 | }; | ||
367 | |||
368 | enum cs43130_xtal_ibias { | ||
369 | CS43130_XTAL_UNUSED = -1, | ||
370 | CS43130_XTAL_IBIAS_15UA = 2, | ||
371 | CS43130_XTAL_IBIAS_12_5UA = 4, | ||
372 | CS43130_XTAL_IBIAS_7_5UA = 6, | ||
373 | }; | ||
374 | |||
375 | enum cs43130_dai_id { | ||
376 | CS43130_ASP_PCM_DAI = 0, | ||
377 | CS43130_ASP_DOP_DAI, | ||
378 | CS43130_XSP_DOP_DAI, | ||
379 | CS43130_XSP_DSD_DAI, | ||
380 | CS43130_DAI_ID_MAX, | ||
381 | }; | ||
382 | |||
383 | struct cs43130_clk_gen { | ||
384 | unsigned int mclk_int; | ||
385 | int fs; | ||
386 | u16 den; | ||
387 | u16 num; | ||
388 | }; | ||
389 | |||
390 | /* frm_size = 16 */ | ||
391 | static const struct cs43130_clk_gen cs43130_16_clk_gen[] = { | ||
392 | {22579200, 32000, 441, 10,}, | ||
393 | {22579200, 44100, 32, 1,}, | ||
394 | {22579200, 48000, 147, 5,}, | ||
395 | {22579200, 88200, 16, 1,}, | ||
396 | {22579200, 96000, 147, 10,}, | ||
397 | {22579200, 176400, 8, 1,}, | ||
398 | {22579200, 192000, 147, 20,}, | ||
399 | {22579200, 352800, 4, 1,}, | ||
400 | {22579200, 384000, 147, 40,}, | ||
401 | {24576000, 32000, 48, 1,}, | ||
402 | {24576000, 44100, 5120, 147,}, | ||
403 | {24576000, 48000, 32, 1,}, | ||
404 | {24576000, 88200, 2560, 147,}, | ||
405 | {24576000, 96000, 16, 1,}, | ||
406 | {24576000, 176400, 1280, 147,}, | ||
407 | {24576000, 192000, 8, 1,}, | ||
408 | {24576000, 352800, 640, 147,}, | ||
409 | {24576000, 384000, 4, 1,}, | ||
410 | }; | ||
411 | |||
412 | /* frm_size = 32 */ | ||
413 | static const struct cs43130_clk_gen cs43130_32_clk_gen[] = { | ||
414 | {22579200, 32000, 441, 20,}, | ||
415 | {22579200, 44100, 16, 1,}, | ||
416 | {22579200, 48000, 147, 10,}, | ||
417 | {22579200, 88200, 8, 1,}, | ||
418 | {22579200, 96000, 147, 20,}, | ||
419 | {22579200, 176400, 4, 1,}, | ||
420 | {22579200, 192000, 147, 40,}, | ||
421 | {22579200, 352800, 2, 1,}, | ||
422 | {22579200, 384000, 147, 80,}, | ||
423 | {24576000, 32000, 24, 1,}, | ||
424 | {24576000, 44100, 2560, 147,}, | ||
425 | {24576000, 48000, 16, 1,}, | ||
426 | {24576000, 88200, 1280, 147,}, | ||
427 | {24576000, 96000, 8, 1,}, | ||
428 | {24576000, 176400, 640, 147,}, | ||
429 | {24576000, 192000, 4, 1,}, | ||
430 | {24576000, 352800, 320, 147,}, | ||
431 | {24576000, 384000, 2, 1,}, | ||
432 | }; | ||
433 | |||
434 | /* frm_size = 48 */ | ||
435 | static const struct cs43130_clk_gen cs43130_48_clk_gen[] = { | ||
436 | {22579200, 32000, 147, 100,}, | ||
437 | {22579200, 44100, 32, 3,}, | ||
438 | {22579200, 48000, 49, 5,}, | ||
439 | {22579200, 88200, 16, 3,}, | ||
440 | {22579200, 96000, 49, 10,}, | ||
441 | {22579200, 176400, 8, 3,}, | ||
442 | {22579200, 192000, 49, 20,}, | ||
443 | {22579200, 352800, 4, 3,}, | ||
444 | {22579200, 384000, 49, 40,}, | ||
445 | {24576000, 32000, 16, 1,}, | ||
446 | {24576000, 44100, 5120, 441,}, | ||
447 | {24576000, 48000, 32, 3,}, | ||
448 | {24576000, 88200, 2560, 441,}, | ||
449 | {24576000, 96000, 16, 3,}, | ||
450 | {24576000, 176400, 1280, 441,}, | ||
451 | {24576000, 192000, 8, 3,}, | ||
452 | {24576000, 352800, 640, 441,}, | ||
453 | {24576000, 384000, 4, 3,}, | ||
454 | }; | ||
455 | |||
456 | /* frm_size = 64 */ | ||
457 | static const struct cs43130_clk_gen cs43130_64_clk_gen[] = { | ||
458 | {22579200, 32000, 441, 40,}, | ||
459 | {22579200, 44100, 8, 1,}, | ||
460 | {22579200, 48000, 147, 20,}, | ||
461 | {22579200, 88200, 4, 1,}, | ||
462 | {22579200, 96000, 147, 40,}, | ||
463 | {22579200, 176400, 2, 1,}, | ||
464 | {22579200, 192000, 147, 80,}, | ||
465 | {22579200, 352800, 1, 1,}, | ||
466 | {24576000, 32000, 12, 1,}, | ||
467 | {24576000, 44100, 1280, 147,}, | ||
468 | {24576000, 48000, 8, 1,}, | ||
469 | {24576000, 88200, 640, 147,}, | ||
470 | {24576000, 96000, 4, 1,}, | ||
471 | {24576000, 176400, 320, 147,}, | ||
472 | {24576000, 192000, 2, 1,}, | ||
473 | {24576000, 352800, 160, 147,}, | ||
474 | {24576000, 384000, 1, 1,}, | ||
475 | }; | ||
476 | |||
477 | struct cs43130_bitwidth_map { | ||
478 | unsigned int bitwidth; | ||
479 | u8 sp_bit; | ||
480 | u8 ch_bit; | ||
481 | }; | ||
482 | |||
483 | struct cs43130_rate_map { | ||
484 | int fs; | ||
485 | int val; | ||
486 | }; | ||
487 | |||
488 | #define HP_LEFT 0 | ||
489 | #define HP_RIGHT 1 | ||
490 | #define CS43130_AC_FREQ 10 | ||
491 | #define CS43130_DC_THRESHOLD 2 | ||
492 | |||
493 | #define CS43130_NUM_SUPPLIES 5 | ||
494 | static const char *const cs43130_supply_names[CS43130_NUM_SUPPLIES] = { | ||
495 | "VA", | ||
496 | "VP", | ||
497 | "VCP", | ||
498 | "VD", | ||
499 | "VL", | ||
500 | }; | ||
501 | |||
502 | #define CS43130_NUM_INT 5 /* number of interrupt status reg */ | ||
503 | |||
504 | struct cs43130_dai { | ||
505 | unsigned int sclk; | ||
506 | unsigned int dai_format; | ||
507 | unsigned int dai_mode; | ||
508 | }; | ||
509 | |||
510 | struct cs43130_private { | ||
511 | struct snd_soc_codec *codec; | ||
512 | struct regmap *regmap; | ||
513 | struct regulator_bulk_data supplies[CS43130_NUM_SUPPLIES]; | ||
514 | struct gpio_desc *reset_gpio; | ||
515 | unsigned int dev_id; /* codec device ID */ | ||
516 | int xtal_ibias; | ||
517 | |||
518 | /* shared by both DAIs */ | ||
519 | struct mutex clk_mutex; | ||
520 | int clk_req; | ||
521 | bool pll_bypass; | ||
522 | struct completion xtal_rdy; | ||
523 | struct completion pll_rdy; | ||
524 | unsigned int mclk; | ||
525 | unsigned int mclk_int; | ||
526 | int mclk_int_src; | ||
527 | |||
528 | /* DAI specific */ | ||
529 | struct cs43130_dai dais[CS43130_DAI_ID_MAX]; | ||
530 | |||
531 | /* HP load specific */ | ||
532 | bool dc_meas; | ||
533 | bool ac_meas; | ||
534 | bool hpload_done; | ||
535 | struct completion hpload_evt; | ||
536 | unsigned int hpload_stat; | ||
537 | u16 hpload_dc[2]; | ||
538 | u16 dc_threshold[CS43130_DC_THRESHOLD]; | ||
539 | u16 ac_freq[CS43130_AC_FREQ]; | ||
540 | u16 hpload_ac[CS43130_AC_FREQ][2]; | ||
541 | struct workqueue_struct *wq; | ||
542 | struct work_struct work; | ||
543 | struct snd_soc_jack jack; | ||
544 | }; | ||
545 | |||
546 | #endif /* __CS43130_H__ */ | ||