]>
Commit | Line | Data |
---|---|---|
8f1e5bf9 LX |
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); | |
f31877a1 TI |
2082 | break; |
2083 | default: | |
2084 | WARN(1, "Invalid dev_id for meas: %d", cs43130->dev_id); | |
2085 | return; | |
8f1e5bf9 LX |
2086 | } |
2087 | ||
2088 | i = 0; | |
2089 | ac_idx = 0; | |
2090 | while (i < seq_size) { | |
2091 | ret = cs43130_hpload_proc(cs43130, hpload_seq[i].seq, | |
2092 | hpload_seq[i].size, | |
2093 | hpload_seq[i].msk, ac_idx); | |
2094 | if (ret < 0) | |
2095 | goto exit; | |
2096 | ||
2097 | cs43130_update_hpload(hpload_seq[i].msk, ac_idx, cs43130); | |
2098 | ||
2099 | if (cs43130->ac_meas && | |
2100 | hpload_seq[i].msk == CS43130_HPLOAD_AC_INT && | |
2101 | ac_idx < CS43130_AC_FREQ - 1) { | |
2102 | ac_idx++; | |
2103 | } else { | |
2104 | ac_idx = 0; | |
2105 | i++; | |
2106 | } | |
2107 | } | |
2108 | cs43130->hpload_done = true; | |
2109 | ||
2110 | if (cs43130->hpload_dc[HP_LEFT] >= CS43130_LINEOUT_LOAD) | |
2111 | snd_soc_jack_report(&cs43130->jack, CS43130_JACK_LINEOUT, | |
2112 | CS43130_JACK_MASK); | |
2113 | else | |
2114 | snd_soc_jack_report(&cs43130->jack, CS43130_JACK_HEADPHONE, | |
2115 | CS43130_JACK_MASK); | |
2116 | ||
2117 | dev_dbg(codec->dev, "Set HP output control. DC threshold\n"); | |
2118 | for (i = 0; i < CS43130_DC_THRESHOLD; i++) | |
2119 | dev_dbg(codec->dev, "DC threshold[%d]: %u.\n", i, | |
2120 | cs43130->dc_threshold[i]); | |
2121 | ||
2122 | cs43130_set_hv(cs43130->regmap, cs43130->hpload_dc[HP_LEFT], | |
2123 | cs43130->dc_threshold); | |
2124 | ||
2125 | exit: | |
2126 | switch (cs43130->dev_id) { | |
2127 | case CS43130_CHIP_ID: | |
2128 | cs43130_hpload_proc(cs43130, hp_dis_cal_seq, | |
2129 | ARRAY_SIZE(hp_dis_cal_seq), | |
2130 | CS43130_HPLOAD_OFF_INT, ac_idx); | |
2131 | break; | |
2132 | case CS43131_CHIP_ID: | |
2133 | cs43130_hpload_proc(cs43130, hp_dis_cal_seq2, | |
2134 | ARRAY_SIZE(hp_dis_cal_seq2), | |
2135 | CS43130_HPLOAD_OFF_INT, ac_idx); | |
2136 | } | |
2137 | ||
2138 | regmap_multi_reg_write(cs43130->regmap, hp_cln_seq, | |
2139 | ARRAY_SIZE(hp_cln_seq)); | |
2140 | ||
2141 | mutex_lock(&cs43130->clk_mutex); | |
2142 | cs43130->clk_req--; | |
2143 | /* clk not in use */ | |
2144 | if (!cs43130->clk_req) | |
2145 | cs43130_change_clksrc(codec, CS43130_MCLK_SRC_RCO); | |
2146 | mutex_unlock(&cs43130->clk_mutex); | |
2147 | } | |
2148 | ||
2149 | static irqreturn_t cs43130_irq_thread(int irq, void *data) | |
2150 | { | |
2151 | struct cs43130_private *cs43130 = (struct cs43130_private *)data; | |
2152 | struct snd_soc_codec *codec = cs43130->codec; | |
2153 | unsigned int stickies[CS43130_NUM_INT]; | |
83ef26ac | 2154 | unsigned int irq_occurrence = 0; |
8f1e5bf9 LX |
2155 | unsigned int masks[CS43130_NUM_INT]; |
2156 | int i, j; | |
2157 | ||
2158 | for (i = 0; i < ARRAY_SIZE(stickies); i++) { | |
2159 | regmap_read(cs43130->regmap, CS43130_INT_STATUS_1 + i, | |
2160 | &stickies[i]); | |
2161 | regmap_read(cs43130->regmap, CS43130_INT_MASK_1 + i, | |
2162 | &masks[i]); | |
2163 | } | |
2164 | ||
2165 | for (i = 0; i < ARRAY_SIZE(stickies); i++) { | |
2166 | stickies[i] = stickies[i] & (~masks[i]); | |
2167 | for (j = 0; j < 8; j++) | |
83ef26ac | 2168 | irq_occurrence += (stickies[i] >> j) & 1; |
8f1e5bf9 LX |
2169 | } |
2170 | dev_dbg(codec->dev, "number of interrupts occurred (%u)\n", | |
83ef26ac | 2171 | irq_occurrence); |
8f1e5bf9 | 2172 | |
83ef26ac | 2173 | if (!irq_occurrence) |
8f1e5bf9 LX |
2174 | return IRQ_NONE; |
2175 | ||
2176 | if (stickies[0] & CS43130_XTAL_RDY_INT) { | |
2177 | complete(&cs43130->xtal_rdy); | |
2178 | return IRQ_HANDLED; | |
2179 | } | |
2180 | ||
2181 | if (stickies[0] & CS43130_PLL_RDY_INT) { | |
2182 | complete(&cs43130->pll_rdy); | |
2183 | return IRQ_HANDLED; | |
2184 | } | |
2185 | ||
2186 | if (stickies[3] & CS43130_HPLOAD_NO_DC_INT) { | |
2187 | cs43130->hpload_stat = stickies[3]; | |
2188 | dev_err(codec->dev, | |
2189 | "DC load has not completed before AC load (%x)\n", | |
2190 | cs43130->hpload_stat); | |
2191 | complete(&cs43130->hpload_evt); | |
2192 | return IRQ_HANDLED; | |
2193 | } | |
2194 | ||
2195 | if (stickies[3] & CS43130_HPLOAD_UNPLUG_INT) { | |
2196 | cs43130->hpload_stat = stickies[3]; | |
2197 | dev_err(codec->dev, "HP unplugged during measurement (%x)\n", | |
2198 | cs43130->hpload_stat); | |
2199 | complete(&cs43130->hpload_evt); | |
2200 | return IRQ_HANDLED; | |
2201 | } | |
2202 | ||
2203 | if (stickies[3] & CS43130_HPLOAD_OOR_INT) { | |
2204 | cs43130->hpload_stat = stickies[3]; | |
2205 | dev_err(codec->dev, "HP load out of range (%x)\n", | |
2206 | cs43130->hpload_stat); | |
2207 | complete(&cs43130->hpload_evt); | |
2208 | return IRQ_HANDLED; | |
2209 | } | |
2210 | ||
2211 | if (stickies[3] & CS43130_HPLOAD_AC_INT) { | |
2212 | cs43130->hpload_stat = stickies[3]; | |
2213 | dev_dbg(codec->dev, "HP AC load measurement done (%x)\n", | |
2214 | cs43130->hpload_stat); | |
2215 | complete(&cs43130->hpload_evt); | |
2216 | return IRQ_HANDLED; | |
2217 | } | |
2218 | ||
2219 | if (stickies[3] & CS43130_HPLOAD_DC_INT) { | |
2220 | cs43130->hpload_stat = stickies[3]; | |
2221 | dev_dbg(codec->dev, "HP DC load measurement done (%x)\n", | |
2222 | cs43130->hpload_stat); | |
2223 | complete(&cs43130->hpload_evt); | |
2224 | return IRQ_HANDLED; | |
2225 | } | |
2226 | ||
2227 | if (stickies[3] & CS43130_HPLOAD_ON_INT) { | |
2228 | cs43130->hpload_stat = stickies[3]; | |
2229 | dev_dbg(codec->dev, "HP load state machine on done (%x)\n", | |
2230 | cs43130->hpload_stat); | |
2231 | complete(&cs43130->hpload_evt); | |
2232 | return IRQ_HANDLED; | |
2233 | } | |
2234 | ||
2235 | if (stickies[3] & CS43130_HPLOAD_OFF_INT) { | |
2236 | cs43130->hpload_stat = stickies[3]; | |
2237 | dev_dbg(codec->dev, "HP load state machine off done (%x)\n", | |
2238 | cs43130->hpload_stat); | |
2239 | complete(&cs43130->hpload_evt); | |
2240 | return IRQ_HANDLED; | |
2241 | } | |
2242 | ||
2243 | if (stickies[0] & CS43130_XTAL_ERR_INT) { | |
2244 | dev_err(codec->dev, "Crystal err: clock is not running\n"); | |
2245 | return IRQ_HANDLED; | |
2246 | } | |
2247 | ||
2248 | if (stickies[0] & CS43130_HP_UNPLUG_INT) { | |
2249 | dev_dbg(codec->dev, "HP unplugged\n"); | |
2250 | cs43130->hpload_done = false; | |
2251 | snd_soc_jack_report(&cs43130->jack, 0, CS43130_JACK_MASK); | |
2252 | return IRQ_HANDLED; | |
2253 | } | |
2254 | ||
2255 | if (stickies[0] & CS43130_HP_PLUG_INT) { | |
2256 | if (cs43130->dc_meas && !cs43130->hpload_done && | |
2257 | !work_busy(&cs43130->work)) { | |
2258 | dev_dbg(codec->dev, "HP load queue work\n"); | |
2259 | queue_work(cs43130->wq, &cs43130->work); | |
2260 | } | |
2261 | ||
2262 | snd_soc_jack_report(&cs43130->jack, SND_JACK_MECHANICAL, | |
2263 | CS43130_JACK_MASK); | |
2264 | return IRQ_HANDLED; | |
2265 | } | |
2266 | ||
2267 | return IRQ_NONE; | |
2268 | } | |
2269 | ||
2270 | static int cs43130_probe(struct snd_soc_codec *codec) | |
2271 | { | |
2272 | int ret; | |
2273 | struct cs43130_private *cs43130 = snd_soc_codec_get_drvdata(codec); | |
2274 | struct snd_soc_card *card = codec->component.card; | |
2275 | unsigned int reg; | |
2276 | ||
2277 | cs43130->codec = codec; | |
2278 | ||
2279 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) { | |
2280 | regmap_update_bits(cs43130->regmap, CS43130_CRYSTAL_SET, | |
2281 | CS43130_XTAL_IBIAS_MASK, | |
2282 | cs43130->xtal_ibias); | |
2283 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | |
2284 | CS43130_XTAL_ERR_INT, 0); | |
2285 | } | |
2286 | ||
2287 | ret = snd_soc_card_jack_new(card, "Headphone", CS43130_JACK_MASK, | |
2288 | &cs43130->jack, NULL, 0); | |
2289 | if (ret < 0) { | |
2290 | dev_err(codec->dev, "Cannot create jack\n"); | |
2291 | return ret; | |
2292 | } | |
2293 | ||
2294 | cs43130->hpload_done = false; | |
2295 | if (cs43130->dc_meas) { | |
2296 | ret = device_create_file(codec->dev, &dev_attr_hpload_dc_l); | |
2297 | if (ret < 0) | |
2298 | return ret; | |
2299 | ||
2300 | ret = device_create_file(codec->dev, &dev_attr_hpload_dc_r); | |
2301 | if (ret < 0) | |
2302 | return ret; | |
2303 | ||
2304 | ret = device_create_file(codec->dev, &dev_attr_hpload_ac_l); | |
2305 | if (ret < 0) | |
2306 | return ret; | |
2307 | ||
2308 | ret = device_create_file(codec->dev, &dev_attr_hpload_ac_r); | |
2309 | if (ret < 0) | |
2310 | return ret; | |
2311 | ||
2312 | cs43130->wq = create_singlethread_workqueue("cs43130_hp"); | |
2313 | INIT_WORK(&cs43130->work, cs43130_imp_meas); | |
2314 | } | |
2315 | ||
2316 | regmap_read(cs43130->regmap, CS43130_INT_STATUS_1, ®); | |
2317 | regmap_read(cs43130->regmap, CS43130_HP_STATUS, ®); | |
2318 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | |
2319 | CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, 0); | |
2320 | regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT, | |
2321 | CS43130_HP_DETECT_CTRL_MASK, 0); | |
2322 | regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT, | |
2323 | CS43130_HP_DETECT_CTRL_MASK, | |
2324 | CS43130_HP_DETECT_CTRL_MASK); | |
2325 | ||
2326 | return 0; | |
2327 | } | |
2328 | ||
2329 | static struct snd_soc_codec_driver soc_codec_dev_cs43130 = { | |
2330 | .probe = cs43130_probe, | |
2331 | .component_driver = { | |
2332 | .controls = cs43130_snd_controls, | |
2333 | .num_controls = ARRAY_SIZE(cs43130_snd_controls), | |
2334 | }, | |
2335 | .set_sysclk = cs43130_codec_set_sysclk, | |
2336 | .set_pll = cs43130_set_pll, | |
2337 | }; | |
2338 | ||
2339 | static const struct regmap_config cs43130_regmap = { | |
2340 | .reg_bits = 24, | |
2341 | .pad_bits = 8, | |
2342 | .val_bits = 8, | |
2343 | ||
2344 | .max_register = CS43130_LASTREG, | |
2345 | .reg_defaults = cs43130_reg_defaults, | |
2346 | .num_reg_defaults = ARRAY_SIZE(cs43130_reg_defaults), | |
2347 | .readable_reg = cs43130_readable_register, | |
2348 | .precious_reg = cs43130_precious_register, | |
2349 | .volatile_reg = cs43130_volatile_register, | |
2350 | .cache_type = REGCACHE_RBTREE, | |
2351 | .use_single_rw = true, /* needed for regcache_sync */ | |
2352 | }; | |
2353 | ||
2354 | static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = { | |
2355 | 50, | |
2356 | 120, | |
2357 | }; | |
2358 | ||
2359 | static int cs43130_handle_device_data(struct i2c_client *i2c_client, | |
2360 | struct cs43130_private *cs43130) | |
2361 | { | |
2362 | struct device_node *np = i2c_client->dev.of_node; | |
2363 | unsigned int val; | |
2364 | int i; | |
2365 | ||
2366 | if (of_property_read_u32(np, "cirrus,xtal-ibias", &val) < 0) { | |
2367 | /* Crystal is unused. System clock is used for external MCLK */ | |
2368 | cs43130->xtal_ibias = CS43130_XTAL_UNUSED; | |
2369 | return 0; | |
2370 | } | |
2371 | ||
2372 | switch (val) { | |
2373 | case 1: | |
2374 | cs43130->xtal_ibias = CS43130_XTAL_IBIAS_7_5UA; | |
2375 | break; | |
2376 | case 2: | |
2377 | cs43130->xtal_ibias = CS43130_XTAL_IBIAS_12_5UA; | |
2378 | break; | |
2379 | case 3: | |
2380 | cs43130->xtal_ibias = CS43130_XTAL_IBIAS_15UA; | |
2381 | break; | |
2382 | default: | |
2383 | dev_err(&i2c_client->dev, | |
2384 | "Invalid cirrus,xtal-ibias value: %d\n", val); | |
2385 | return -EINVAL; | |
2386 | } | |
2387 | ||
2388 | cs43130->dc_meas = of_property_read_bool(np, "cirrus,dc-measure"); | |
2389 | cs43130->ac_meas = of_property_read_bool(np, "cirrus,ac-measure"); | |
2390 | ||
2391 | if (of_property_read_u16_array(np, "cirrus,ac-freq", cs43130->ac_freq, | |
2392 | CS43130_AC_FREQ) < 0) { | |
2393 | for (i = 0; i < CS43130_AC_FREQ; i++) | |
2394 | cs43130->ac_freq[i] = cs43130_ac_freq[i]; | |
2395 | } | |
2396 | ||
2397 | if (of_property_read_u16_array(np, "cirrus,dc-threshold", | |
2398 | cs43130->dc_threshold, | |
2399 | CS43130_DC_THRESHOLD) < 0) { | |
2400 | for (i = 0; i < CS43130_DC_THRESHOLD; i++) | |
2401 | cs43130->dc_threshold[i] = cs43130_dc_threshold[i]; | |
2402 | } | |
2403 | ||
2404 | return 0; | |
2405 | } | |
2406 | ||
2407 | static int cs43130_i2c_probe(struct i2c_client *client, | |
2408 | const struct i2c_device_id *id) | |
2409 | { | |
2410 | struct cs43130_private *cs43130; | |
2411 | int ret; | |
2412 | unsigned int devid = 0; | |
2413 | unsigned int reg; | |
2414 | int i; | |
2415 | ||
2416 | cs43130 = devm_kzalloc(&client->dev, sizeof(*cs43130), GFP_KERNEL); | |
2417 | if (!cs43130) | |
2418 | return -ENOMEM; | |
2419 | ||
2420 | i2c_set_clientdata(client, cs43130); | |
2421 | ||
2422 | cs43130->regmap = devm_regmap_init_i2c(client, &cs43130_regmap); | |
2423 | if (IS_ERR(cs43130->regmap)) { | |
2424 | ret = PTR_ERR(cs43130->regmap); | |
2425 | return ret; | |
2426 | } | |
2427 | ||
2428 | if (client->dev.of_node) { | |
2429 | ret = cs43130_handle_device_data(client, cs43130); | |
2430 | if (ret != 0) | |
2431 | return ret; | |
2432 | } | |
2433 | for (i = 0; i < ARRAY_SIZE(cs43130->supplies); i++) | |
2434 | cs43130->supplies[i].supply = cs43130_supply_names[i]; | |
2435 | ||
2436 | ret = devm_regulator_bulk_get(&client->dev, | |
2437 | ARRAY_SIZE(cs43130->supplies), | |
2438 | cs43130->supplies); | |
2439 | if (ret != 0) { | |
2440 | dev_err(&client->dev, "Failed to request supplies: %d\n", ret); | |
2441 | return ret; | |
2442 | } | |
2443 | ret = regulator_bulk_enable(ARRAY_SIZE(cs43130->supplies), | |
2444 | cs43130->supplies); | |
2445 | if (ret != 0) { | |
2446 | dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); | |
2447 | return ret; | |
2448 | } | |
2449 | ||
2450 | cs43130->reset_gpio = devm_gpiod_get_optional(&client->dev, | |
2451 | "reset", GPIOD_OUT_LOW); | |
2452 | if (IS_ERR(cs43130->reset_gpio)) | |
2453 | return PTR_ERR(cs43130->reset_gpio); | |
2454 | ||
2455 | gpiod_set_value_cansleep(cs43130->reset_gpio, 1); | |
2456 | ||
2457 | usleep_range(2000, 2050); | |
2458 | ||
2459 | ret = regmap_read(cs43130->regmap, CS43130_DEVID_AB, ®); | |
2460 | ||
2461 | devid = (reg & 0xFF) << 12; | |
2462 | ret = regmap_read(cs43130->regmap, CS43130_DEVID_CD, ®); | |
2463 | devid |= (reg & 0xFF) << 4; | |
2464 | ret = regmap_read(cs43130->regmap, CS43130_DEVID_E, ®); | |
2465 | devid |= (reg & 0xF0) >> 4; | |
2466 | ||
2467 | switch (devid) { | |
2468 | case CS43130_CHIP_ID: | |
2469 | case CS4399_CHIP_ID: | |
2470 | case CS43131_CHIP_ID: | |
2471 | case CS43198_CHIP_ID: | |
2472 | break; | |
2473 | default: | |
2474 | dev_err(&client->dev, | |
2475 | "CS43130 Device ID %X. Expected ID %X, %X, %X or %X\n", | |
2476 | devid, CS43130_CHIP_ID, CS4399_CHIP_ID, | |
2477 | CS43131_CHIP_ID, CS43198_CHIP_ID); | |
2478 | ret = -ENODEV; | |
2479 | goto err; | |
2480 | } | |
2481 | ||
2482 | cs43130->dev_id = devid; | |
2483 | ret = regmap_read(cs43130->regmap, CS43130_REV_ID, ®); | |
2484 | if (ret < 0) { | |
2485 | dev_err(&client->dev, "Get Revision ID failed\n"); | |
2486 | goto err; | |
2487 | } | |
2488 | ||
2489 | dev_info(&client->dev, | |
2490 | "Cirrus Logic CS43130 (%x), Revision: %02X\n", devid, | |
2491 | reg & 0xFF); | |
2492 | ||
2493 | mutex_init(&cs43130->clk_mutex); | |
2494 | ||
2495 | init_completion(&cs43130->xtal_rdy); | |
2496 | init_completion(&cs43130->pll_rdy); | |
2497 | init_completion(&cs43130->hpload_evt); | |
2498 | ||
2499 | ret = devm_request_threaded_irq(&client->dev, client->irq, | |
2500 | NULL, cs43130_irq_thread, | |
2501 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, | |
2502 | "cs43130", cs43130); | |
2503 | if (ret != 0) { | |
2504 | dev_err(&client->dev, "Failed to request IRQ: %d\n", ret); | |
2505 | return ret; | |
2506 | } | |
2507 | ||
2508 | cs43130->mclk_int_src = CS43130_MCLK_SRC_RCO; | |
2509 | ||
2510 | pm_runtime_set_autosuspend_delay(&client->dev, 100); | |
2511 | pm_runtime_use_autosuspend(&client->dev); | |
2512 | pm_runtime_set_active(&client->dev); | |
2513 | pm_runtime_enable(&client->dev); | |
2514 | ||
2515 | switch (cs43130->dev_id) { | |
2516 | case CS43130_CHIP_ID: | |
2517 | case CS43131_CHIP_ID: | |
2518 | memcpy(all_hp_widgets, digital_hp_widgets, | |
2519 | sizeof(digital_hp_widgets)); | |
2520 | memcpy(all_hp_widgets + ARRAY_SIZE(digital_hp_widgets), | |
2521 | analog_hp_widgets, sizeof(analog_hp_widgets)); | |
2522 | memcpy(all_hp_routes, digital_hp_routes, | |
2523 | sizeof(digital_hp_routes)); | |
2524 | memcpy(all_hp_routes + ARRAY_SIZE(digital_hp_routes), | |
2525 | analog_hp_routes, sizeof(analog_hp_routes)); | |
2526 | ||
2527 | soc_codec_dev_cs43130.component_driver.dapm_widgets = | |
2528 | all_hp_widgets; | |
2529 | soc_codec_dev_cs43130.component_driver.num_dapm_widgets = | |
2530 | ARRAY_SIZE(all_hp_widgets); | |
2531 | soc_codec_dev_cs43130.component_driver.dapm_routes = | |
2532 | all_hp_routes; | |
2533 | soc_codec_dev_cs43130.component_driver.num_dapm_routes = | |
2534 | ARRAY_SIZE(all_hp_routes); | |
2535 | break; | |
2536 | case CS43198_CHIP_ID: | |
2537 | case CS4399_CHIP_ID: | |
2538 | soc_codec_dev_cs43130.component_driver.dapm_widgets = | |
2539 | digital_hp_widgets; | |
2540 | soc_codec_dev_cs43130.component_driver.num_dapm_widgets = | |
2541 | ARRAY_SIZE(digital_hp_widgets); | |
2542 | soc_codec_dev_cs43130.component_driver.dapm_routes = | |
2543 | digital_hp_routes; | |
2544 | soc_codec_dev_cs43130.component_driver.num_dapm_routes = | |
2545 | ARRAY_SIZE(digital_hp_routes); | |
2546 | } | |
2547 | ||
2548 | ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_cs43130, | |
2549 | cs43130_dai, ARRAY_SIZE(cs43130_dai)); | |
2550 | if (ret < 0) { | |
2551 | dev_err(&client->dev, | |
2552 | "snd_soc_register_codec failed with ret = %d\n", ret); | |
2553 | goto err; | |
2554 | } | |
2555 | ||
2556 | regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG, | |
2557 | CS43130_ASP_3ST_MASK, 0); | |
2558 | regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG, | |
2559 | CS43130_XSP_3ST_MASK, 0); | |
2560 | ||
2561 | return 0; | |
2562 | err: | |
2563 | return ret; | |
2564 | } | |
2565 | ||
2566 | static int cs43130_i2c_remove(struct i2c_client *client) | |
2567 | { | |
2568 | struct cs43130_private *cs43130 = i2c_get_clientdata(client); | |
2569 | ||
2570 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) | |
2571 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | |
2572 | CS43130_XTAL_ERR_INT, | |
2573 | 1 << CS43130_XTAL_ERR_INT_SHIFT); | |
2574 | ||
2575 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | |
2576 | CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT, | |
2577 | CS43130_HP_PLUG_INT | CS43130_HP_UNPLUG_INT); | |
2578 | ||
2579 | if (cs43130->dc_meas) { | |
2580 | cancel_work_sync(&cs43130->work); | |
2581 | flush_workqueue(cs43130->wq); | |
2582 | ||
2583 | device_remove_file(&client->dev, &dev_attr_hpload_dc_l); | |
2584 | device_remove_file(&client->dev, &dev_attr_hpload_dc_r); | |
2585 | device_remove_file(&client->dev, &dev_attr_hpload_ac_l); | |
2586 | device_remove_file(&client->dev, &dev_attr_hpload_ac_r); | |
2587 | } | |
2588 | ||
2589 | if (cs43130->reset_gpio) | |
2590 | gpiod_set_value_cansleep(cs43130->reset_gpio, 0); | |
2591 | ||
2592 | pm_runtime_disable(&client->dev); | |
2593 | regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); | |
2594 | ||
2595 | snd_soc_unregister_codec(&client->dev); | |
2596 | ||
2597 | return 0; | |
2598 | } | |
2599 | ||
70513346 | 2600 | static int __maybe_unused cs43130_runtime_suspend(struct device *dev) |
8f1e5bf9 LX |
2601 | { |
2602 | struct cs43130_private *cs43130 = dev_get_drvdata(dev); | |
2603 | ||
2604 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) | |
2605 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | |
2606 | CS43130_XTAL_ERR_INT, | |
2607 | 1 << CS43130_XTAL_ERR_INT_SHIFT); | |
2608 | ||
2609 | regcache_cache_only(cs43130->regmap, true); | |
2610 | regcache_mark_dirty(cs43130->regmap); | |
2611 | ||
2612 | gpiod_set_value_cansleep(cs43130->reset_gpio, 0); | |
2613 | ||
2614 | regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); | |
2615 | ||
2616 | return 0; | |
2617 | } | |
2618 | ||
70513346 | 2619 | static int __maybe_unused cs43130_runtime_resume(struct device *dev) |
8f1e5bf9 LX |
2620 | { |
2621 | struct cs43130_private *cs43130 = dev_get_drvdata(dev); | |
2622 | int ret; | |
2623 | ||
2624 | ret = regulator_bulk_enable(CS43130_NUM_SUPPLIES, cs43130->supplies); | |
2625 | if (ret != 0) { | |
2626 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | |
2627 | return ret; | |
2628 | } | |
2629 | ||
2630 | regcache_cache_only(cs43130->regmap, false); | |
2631 | ||
2632 | gpiod_set_value_cansleep(cs43130->reset_gpio, 1); | |
2633 | ||
2634 | usleep_range(2000, 2050); | |
2635 | ||
2636 | ret = regcache_sync(cs43130->regmap); | |
2637 | if (ret != 0) { | |
2638 | dev_err(dev, "Failed to restore register cache\n"); | |
2639 | goto err; | |
2640 | } | |
2641 | ||
2642 | if (cs43130->xtal_ibias != CS43130_XTAL_UNUSED) | |
2643 | regmap_update_bits(cs43130->regmap, CS43130_INT_MASK_1, | |
2644 | CS43130_XTAL_ERR_INT, 0); | |
2645 | ||
2646 | return 0; | |
2647 | err: | |
2648 | regcache_cache_only(cs43130->regmap, true); | |
2649 | regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); | |
2650 | ||
2651 | return ret; | |
2652 | } | |
2653 | ||
2654 | static const struct dev_pm_ops cs43130_runtime_pm = { | |
2655 | SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume, | |
2656 | NULL) | |
2657 | }; | |
2658 | ||
2659 | static const struct of_device_id cs43130_of_match[] = { | |
2660 | {.compatible = "cirrus,cs43130",}, | |
2661 | {.compatible = "cirrus,cs4399",}, | |
2662 | {.compatible = "cirrus,cs43131",}, | |
2663 | {.compatible = "cirrus,cs43198",}, | |
2664 | {}, | |
2665 | }; | |
2666 | ||
2667 | MODULE_DEVICE_TABLE(of, cs43130_of_match); | |
2668 | ||
2669 | static const struct i2c_device_id cs43130_i2c_id[] = { | |
2670 | {"cs43130", 0}, | |
2671 | {"cs4399", 0}, | |
2672 | {"cs43131", 0}, | |
2673 | {"cs43198", 0}, | |
2674 | {} | |
2675 | }; | |
2676 | ||
2677 | MODULE_DEVICE_TABLE(i2c, cs43130_i2c_id); | |
2678 | ||
2679 | static struct i2c_driver cs43130_i2c_driver = { | |
2680 | .driver = { | |
2681 | .name = "cs43130", | |
2682 | .of_match_table = cs43130_of_match, | |
2683 | .pm = &cs43130_runtime_pm, | |
2684 | }, | |
2685 | .id_table = cs43130_i2c_id, | |
2686 | .probe = cs43130_i2c_probe, | |
2687 | .remove = cs43130_i2c_remove, | |
2688 | }; | |
2689 | ||
2690 | module_i2c_driver(cs43130_i2c_driver); | |
2691 | ||
2692 | MODULE_AUTHOR("Li Xu <li.xu@cirrus.com>"); | |
2693 | MODULE_DESCRIPTION("Cirrus Logic CS43130 ALSA SoC Codec Driver"); | |
2694 | MODULE_LICENSE("GPL"); |