~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/cs530x.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 //
  3 // CS530x CODEC driver
  4 //
  5 // Copyright (C) 2024 Cirrus Logic, Inc. and
  6 //                    Cirrus Logic International Semiconductor Ltd.
  7 
  8 #include <sound/core.h>
  9 #include <linux/delay.h>
 10 #include <linux/i2c.h>
 11 #include <linux/init.h>
 12 #include <sound/initval.h>
 13 #include <linux/module.h>
 14 #include <sound/pcm.h>
 15 #include <sound/pcm_params.h>
 16 #include <linux/pm.h>
 17 #include <linux/property.h>
 18 #include <linux/slab.h>
 19 #include <sound/soc.h>
 20 #include <sound/tlv.h>
 21 
 22 #include "cs530x.h"
 23 
 24 #define CS530X_MAX_ADC_CH       8
 25 #define CS530X_MIN_ADC_CH       2
 26 
 27 static const char *cs530x_supply_names[CS530X_NUM_SUPPLIES] = {
 28         "vdd-a",
 29         "vdd-io",
 30 };
 31 
 32 static const struct reg_default cs530x_reg_defaults[] = {
 33         { CS530X_CLK_CFG_0, 0x30 },
 34         { CS530X_CLK_CFG_1, 0x0001 },
 35         { CS530X_CHIP_ENABLE, 0 },
 36         { CS530X_ASP_CFG, 0 },
 37         { CS530X_SIGNAL_PATH_CFG, 0 },
 38         { CS530X_IN_ENABLES, 0 },
 39         { CS530X_IN_RAMP_SUM, 0x0022 },
 40         { CS530X_IN_FILTER, 0 },
 41         { CS530X_IN_HIZ, 0 },
 42         { CS530X_IN_INV, 0 },
 43         { CS530X_IN_VOL_CTRL1_0, 0x8000 },
 44         { CS530X_IN_VOL_CTRL1_1, 0x8000 },
 45         { CS530X_IN_VOL_CTRL2_0, 0x8000 },
 46         { CS530X_IN_VOL_CTRL2_1, 0x8000 },
 47         { CS530X_IN_VOL_CTRL3_0, 0x8000 },
 48         { CS530X_IN_VOL_CTRL3_1, 0x8000 },
 49         { CS530X_IN_VOL_CTRL4_0, 0x8000 },
 50         { CS530X_IN_VOL_CTRL4_1, 0x8000 },
 51         { CS530X_PAD_FN, 0 },
 52         { CS530X_PAD_LVL, 0 },
 53 };
 54 
 55 static bool cs530x_read_and_write_regs(unsigned int reg)
 56 {
 57         switch (reg) {
 58         case CS530X_CLK_CFG_0:
 59         case CS530X_CLK_CFG_1:
 60         case CS530X_CHIP_ENABLE:
 61         case CS530X_ASP_CFG:
 62         case CS530X_SIGNAL_PATH_CFG:
 63         case CS530X_IN_ENABLES:
 64         case CS530X_IN_RAMP_SUM:
 65         case CS530X_IN_FILTER:
 66         case CS530X_IN_HIZ:
 67         case CS530X_IN_INV:
 68         case CS530X_IN_VOL_CTRL1_0:
 69         case CS530X_IN_VOL_CTRL1_1:
 70         case CS530X_IN_VOL_CTRL2_0:
 71         case CS530X_IN_VOL_CTRL2_1:
 72         case CS530X_IN_VOL_CTRL3_0:
 73         case CS530X_IN_VOL_CTRL3_1:
 74         case CS530X_IN_VOL_CTRL4_0:
 75         case CS530X_IN_VOL_CTRL4_1:
 76         case CS530X_PAD_FN:
 77         case CS530X_PAD_LVL:
 78                 return true;
 79         default:
 80                 return false;
 81         }
 82 }
 83 
 84 static bool cs530x_readable_register(struct device *dev, unsigned int reg)
 85 {
 86         switch (reg) {
 87         case CS530X_DEVID:
 88         case CS530X_REVID:
 89                 return true;
 90         default:
 91                 return cs530x_read_and_write_regs(reg);
 92         }
 93 }
 94 
 95 static bool cs530x_writeable_register(struct device *dev, unsigned int reg)
 96 {
 97         switch (reg) {
 98         case CS530X_SW_RESET:
 99         case CS530X_IN_VOL_CTRL5:
100                 return true;
101         default:
102                 return cs530x_read_and_write_regs(reg);
103         }
104 }
105 
106 static int cs530x_put_volsw_vu(struct snd_kcontrol *kcontrol,
107                                 struct snd_ctl_elem_value *ucontrol)
108 {
109         struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
110         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
111         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
112         struct regmap *regmap = cs530x->regmap;
113         int ret;
114 
115         snd_soc_dapm_mutex_lock(dapm);
116 
117         ret = snd_soc_put_volsw(kcontrol, ucontrol);
118         if (ret)
119                 goto volsw_err;
120 
121         /* Write IN_VU bit for the volume change to take effect */
122         regmap_write(regmap, CS530X_IN_VOL_CTRL5, CS530X_IN_VU);
123 
124 volsw_err:
125         snd_soc_dapm_mutex_unlock(dapm);
126 
127         return ret;
128 }
129 
130 static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1270, 50, 0);
131 
132 static const char * const cs530x_in_filter_text[] = {
133         "Min Phase Slow Roll-off",
134         "Min Phase Fast Roll-off",
135         "Linear Phase Slow Roll-off",
136         "Linear Phase Fast Roll-off",
137 };
138 
139 static SOC_ENUM_SINGLE_DECL(cs530x_in_filter_enum, CS530X_IN_FILTER,
140                             CS530X_IN_FILTER_SHIFT,
141                             cs530x_in_filter_text);
142 
143 static const char * const cs530x_in_4ch_sum_text[] = {
144         "None",
145         "Groups of 2",
146         "Groups of 4",
147 };
148 
149 static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch4_enum, CS530X_IN_RAMP_SUM,
150                             CS530X_IN_SUM_MODE_SHIFT,
151                             cs530x_in_4ch_sum_text);
152 
153 static const struct snd_kcontrol_new cs530x_in_sum_4ch_controls[] = {
154 SOC_ENUM("IN Sum Select", cs530x_in_sum_ch4_enum),
155 };
156 
157 static const char * const cs530x_in_8ch_sum_text[] = {
158         "None",
159         "Groups of 2",
160         "Groups of 4",
161         "Groups of 8",
162 };
163 
164 static SOC_ENUM_SINGLE_DECL(cs530x_in_sum_ch8_enum, CS530X_IN_RAMP_SUM,
165                             CS530X_IN_SUM_MODE_SHIFT,
166                             cs530x_in_8ch_sum_text);
167 
168 static const struct snd_kcontrol_new cs530x_in_sum_8ch_controls[] = {
169 SOC_ENUM("IN Sum Select", cs530x_in_sum_ch8_enum),
170 };
171 
172 
173 static const char * const cs530x_vol_ramp_text[] = {
174         "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
175         "15ms/6dB", "30ms/6dB",
176 };
177 
178 static SOC_ENUM_SINGLE_DECL(cs530x_ramp_inc_enum, CS530X_IN_RAMP_SUM,
179                             CS530X_RAMP_RATE_INC_SHIFT,
180                             cs530x_vol_ramp_text);
181 
182 static SOC_ENUM_SINGLE_DECL(cs530x_ramp_dec_enum, CS530X_IN_RAMP_SUM,
183                             CS530X_RAMP_RATE_DEC_SHIFT,
184                             cs530x_vol_ramp_text);
185 
186 static const struct snd_kcontrol_new cs530x_in_1_to_2_controls[] = {
187 SOC_SINGLE_EXT_TLV("IN1 Volume", CS530X_IN_VOL_CTRL1_0, 0, 255, 1,
188                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
189 SOC_SINGLE_EXT_TLV("IN2 Volume", CS530X_IN_VOL_CTRL1_1, 0, 255, 1,
190                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
191 
192 SOC_ENUM("IN DEC Filter Select", cs530x_in_filter_enum),
193 SOC_ENUM("Input Ramp Up", cs530x_ramp_inc_enum),
194 SOC_ENUM("Input Ramp Down", cs530x_ramp_dec_enum),
195 
196 SOC_SINGLE("ADC1 Invert Switch", CS530X_IN_INV, CS530X_IN1_INV_SHIFT, 1, 0),
197 SOC_SINGLE("ADC2 Invert Switch", CS530X_IN_INV, CS530X_IN2_INV_SHIFT, 1, 0),
198 };
199 
200 static const struct snd_kcontrol_new cs530x_in_3_to_4_controls[] = {
201 SOC_SINGLE_EXT_TLV("IN3 Volume", CS530X_IN_VOL_CTRL2_0, 0, 255, 1,
202                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
203 SOC_SINGLE_EXT_TLV("IN4 Volume", CS530X_IN_VOL_CTRL2_1, 0, 255, 1,
204                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
205 
206 SOC_SINGLE("ADC3 Invert Switch", CS530X_IN_INV, CS530X_IN3_INV_SHIFT, 1, 0),
207 SOC_SINGLE("ADC4 Invert Switch", CS530X_IN_INV, CS530X_IN4_INV_SHIFT, 1, 0),
208 };
209 
210 static const struct snd_kcontrol_new cs530x_in_5_to_8_controls[] = {
211 SOC_SINGLE_EXT_TLV("IN5 Volume", CS530X_IN_VOL_CTRL3_0, 0, 255, 1,
212                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
213 SOC_SINGLE_EXT_TLV("IN6 Volume", CS530X_IN_VOL_CTRL3_1, 0, 255, 1,
214                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
215 SOC_SINGLE_EXT_TLV("IN7 Volume", CS530X_IN_VOL_CTRL4_0, 0, 255, 1,
216                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
217 SOC_SINGLE_EXT_TLV("IN8 Volume", CS530X_IN_VOL_CTRL4_1, 0, 255, 1,
218                     snd_soc_get_volsw, cs530x_put_volsw_vu, in_vol_tlv),
219 
220 SOC_SINGLE("ADC5 Invert Switch", CS530X_IN_INV, CS530X_IN5_INV_SHIFT, 1, 0),
221 SOC_SINGLE("ADC6 Invert Switch", CS530X_IN_INV, CS530X_IN6_INV_SHIFT, 1, 0),
222 SOC_SINGLE("ADC7 Invert Switch", CS530X_IN_INV, CS530X_IN7_INV_SHIFT, 1, 0),
223 SOC_SINGLE("ADC8 Invert Switch", CS530X_IN_INV, CS530X_IN8_INV_SHIFT, 1, 0),
224 };
225 
226 static int cs530x_adc_event(struct snd_soc_dapm_widget *w,
227                              struct snd_kcontrol *kcontrol, int event)
228 {
229         struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
230         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
231         struct regmap *regmap = cs530x->regmap;
232 
233         switch (event) {
234         case SND_SOC_DAPM_PRE_PMU:
235                 cs530x->adc_pairs_count++;
236                 break;
237         case SND_SOC_DAPM_POST_PMU:
238                 regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
239                                  (w->shift * 2), CS530X_IN_MUTE);
240                 regmap_clear_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
241                                  ((w->shift+1) * 2), CS530X_IN_MUTE);
242 
243                 cs530x->adc_pairs_count--;
244                 if (!cs530x->adc_pairs_count) {
245                         usleep_range(1000, 1100);
246                         return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
247                                             CS530X_IN_VU);
248                 }
249                 break;
250         case SND_SOC_DAPM_PRE_PMD:
251                 regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
252                                (w->shift * 2), CS530X_IN_MUTE);
253                 regmap_set_bits(regmap, CS530X_IN_VOL_CTRL1_0 +
254                                ((w->shift+1) * 2), CS530X_IN_MUTE);
255                 return regmap_write(regmap, CS530X_IN_VOL_CTRL5,
256                                     CS530X_IN_VU);
257         default:
258                 return -EINVAL;
259         }
260 
261         return 0;
262 }
263 
264 static const struct snd_kcontrol_new adc12_ctrl =
265         SOC_DAPM_SINGLE_VIRT("Switch", 1);
266 
267 static const struct snd_kcontrol_new adc34_ctrl =
268         SOC_DAPM_SINGLE_VIRT("Switch", 1);
269 
270 static const struct snd_kcontrol_new adc56_ctrl =
271         SOC_DAPM_SINGLE_VIRT("Switch", 1);
272 
273 static const struct snd_kcontrol_new adc78_ctrl =
274         SOC_DAPM_SINGLE_VIRT("Switch", 1);
275 
276 static const struct snd_kcontrol_new in_hpf_ctrl =
277         SOC_DAPM_SINGLE_VIRT("Switch", 1);
278 
279 /* General DAPM widgets for all devices */
280 static const struct snd_soc_dapm_widget cs530x_gen_dapm_widgets[] = {
281 SND_SOC_DAPM_SUPPLY("Global Enable", CS530X_CHIP_ENABLE, 0, 0, NULL, 0),
282 };
283 
284 /* ADC's Channels 1 and 2 plus generic ADC DAPM events */
285 static const struct snd_soc_dapm_widget cs530x_adc_ch12_dapm_widgets[] = {
286 SND_SOC_DAPM_INPUT("IN1"),
287 SND_SOC_DAPM_INPUT("IN2"),
288 SND_SOC_DAPM_ADC_E("ADC1", NULL, CS530X_IN_ENABLES, 0, 0,
289                    cs530x_adc_event,
290                    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
291                    SND_SOC_DAPM_PRE_PMU),
292 SND_SOC_DAPM_ADC("ADC2", NULL, CS530X_IN_ENABLES, 1, 0),
293 SND_SOC_DAPM_SWITCH("ADC12 Enable", SND_SOC_NOPM, 0, 0, &adc12_ctrl),
294 SND_SOC_DAPM_SWITCH("IN HPF", CS530X_IN_FILTER, CS530X_IN_HPF_EN_SHIFT,
295                     0, &in_hpf_ctrl),
296 };
297 
298 /* ADC's Channels 3 and 4 */
299 static const struct snd_soc_dapm_widget cs530x_adc_ch34_dapm_widgets[] = {
300 SND_SOC_DAPM_INPUT("IN3"),
301 SND_SOC_DAPM_INPUT("IN4"),
302 SND_SOC_DAPM_ADC_E("ADC3", NULL, CS530X_IN_ENABLES, 2, 0,
303                    cs530x_adc_event,
304                    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
305                    SND_SOC_DAPM_PRE_PMU),
306 SND_SOC_DAPM_ADC("ADC4", NULL, CS530X_IN_ENABLES, 3, 0),
307 SND_SOC_DAPM_SWITCH("ADC34 Enable", SND_SOC_NOPM, 0, 0, &adc34_ctrl),
308 };
309 
310 /* ADC's Channels 5 to 8 */
311 static const struct snd_soc_dapm_widget cs530x_adc_ch58_dapm_widgets[] = {
312 SND_SOC_DAPM_INPUT("IN5"),
313 SND_SOC_DAPM_INPUT("IN6"),
314 SND_SOC_DAPM_INPUT("IN7"),
315 SND_SOC_DAPM_INPUT("IN8"),
316 SND_SOC_DAPM_ADC_E("ADC5", NULL, CS530X_IN_ENABLES, 4, 0,
317                    cs530x_adc_event,
318                    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
319                    SND_SOC_DAPM_PRE_PMU),
320 SND_SOC_DAPM_ADC("ADC6", NULL, CS530X_IN_ENABLES, 5, 0),
321 SND_SOC_DAPM_SWITCH("ADC56 Enable", SND_SOC_NOPM, 0, 0, &adc56_ctrl),
322 SND_SOC_DAPM_ADC_E("ADC7", NULL, CS530X_IN_ENABLES, 6, 0,
323                    cs530x_adc_event,
324                    SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU |
325                    SND_SOC_DAPM_PRE_PMU),
326 SND_SOC_DAPM_ADC("ADC8", NULL, CS530X_IN_ENABLES, 7, 0),
327 SND_SOC_DAPM_SWITCH("ADC78 Enable", SND_SOC_NOPM, 0, 0, &adc78_ctrl),
328 };
329 
330 static const struct snd_soc_dapm_route adc_ch1_2_routes[] = {
331         { "ADC1", NULL, "Global Enable" },
332         { "ADC2", NULL, "Global Enable" },
333 
334         { "ADC12 Enable", "Switch", "IN1" },
335         { "ADC12 Enable", "Switch", "IN2" },
336         { "ADC1", NULL, "ADC12 Enable" },
337         { "ADC2", NULL, "ADC12 Enable" },
338         { "IN HPF", "Switch", "ADC1" },
339         { "IN HPF", "Switch", "ADC2" },
340 
341         { "AIF Capture", NULL, "IN HPF" },
342         { "AIF Capture", NULL, "ADC1" },
343         { "AIF Capture", NULL, "ADC2" },
344 };
345 
346 static const struct snd_soc_dapm_route adc_ch3_4_routes[] = {
347         { "ADC3", NULL, "Global Enable" },
348         { "ADC4", NULL, "Global Enable" },
349 
350         { "ADC34 Enable", "Switch", "IN3" },
351         { "ADC34 Enable", "Switch", "IN4" },
352         { "ADC3", NULL, "ADC34 Enable" },
353         { "ADC4", NULL, "ADC34 Enable" },
354         { "IN HPF", "Switch", "ADC3" },
355         { "IN HPF", "Switch", "ADC4" },
356 
357         { "AIF Capture", NULL, "ADC3" },
358         { "AIF Capture", NULL, "ADC4" },
359 };
360 
361 static const struct snd_soc_dapm_route adc_ch5_8_routes[] = {
362         { "ADC5", NULL, "Global Enable" },
363         { "ADC6", NULL, "Global Enable" },
364         { "ADC7", NULL, "Global Enable" },
365         { "ADC8", NULL, "Global Enable" },
366 
367         { "ADC56 Enable", "Switch", "IN5" },
368         { "ADC56 Enable", "Switch", "IN6" },
369         { "ADC5", NULL, "ADC56 Enable" },
370         { "ADC6", NULL, "ADC56 Enable" },
371         { "IN HPF", "Switch", "ADC5" },
372         { "IN HPF", "Switch", "ADC6" },
373 
374         { "AIF Capture", NULL, "ADC5" },
375         { "AIF Capture", NULL, "ADC6" },
376 
377         { "ADC78 Enable", "Switch", "IN7" },
378         { "ADC78 Enable", "Switch", "IN8" },
379         { "ADC7", NULL, "ADC78 Enable" },
380         { "ADC8", NULL, "ADC78 Enable" },
381         { "IN HPF", "Switch", "ADC7" },
382         { "IN HPF", "Switch", "ADC8" },
383 
384         { "AIF Capture", NULL, "ADC7" },
385         { "AIF Capture", NULL, "ADC8" },
386 };
387 
388 static void cs530x_add_12_adc_widgets(struct snd_soc_component *component)
389 {
390         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
391 
392         snd_soc_add_component_controls(component,
393                                        cs530x_in_1_to_2_controls,
394                                        ARRAY_SIZE(cs530x_in_1_to_2_controls));
395 
396         snd_soc_dapm_new_controls(dapm, cs530x_adc_ch12_dapm_widgets,
397                                   ARRAY_SIZE(cs530x_adc_ch12_dapm_widgets));
398 
399         snd_soc_dapm_add_routes(dapm, adc_ch1_2_routes,
400                                 ARRAY_SIZE(adc_ch1_2_routes));
401 }
402 
403 static void cs530x_add_34_adc_widgets(struct snd_soc_component *component)
404 {
405         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
406 
407         snd_soc_add_component_controls(component,
408                                        cs530x_in_3_to_4_controls,
409                                        ARRAY_SIZE(cs530x_in_3_to_4_controls));
410 
411         snd_soc_dapm_new_controls(dapm, cs530x_adc_ch34_dapm_widgets,
412                                   ARRAY_SIZE(cs530x_adc_ch34_dapm_widgets));
413 
414         snd_soc_dapm_add_routes(dapm, adc_ch3_4_routes,
415                                 ARRAY_SIZE(adc_ch3_4_routes));
416 }
417 
418 static int cs530x_set_bclk(struct snd_soc_component *component, const int freq)
419 {
420         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
421         struct regmap *regmap = cs530x->regmap;
422         unsigned int bclk_val;
423 
424         switch (freq) {
425         case 2822400:
426         case 3072000:
427                 bclk_val = CS530X_BCLK_2P822_3P072;
428                 break;
429         case 5644800:
430         case 6144000:
431                 bclk_val = CS530X_BCLK_5P6448_6P144;
432                 break;
433         case 11289600:
434         case 12288000:
435                 bclk_val = CS530X_BCLK_11P2896_12P288;
436                 break;
437         case 22579200:
438         case 24576000:
439                 bclk_val = CS530X_BCLK_24P5792_24P576;
440                 break;
441         default:
442                 dev_err(component->dev, "Invalid BCLK frequency %d\n", freq);
443                 return -EINVAL;
444         }
445 
446         dev_dbg(component->dev, "BCLK frequency is %d\n", freq);
447 
448         return regmap_update_bits(regmap, CS530X_ASP_CFG,
449                                   CS530X_ASP_BCLK_FREQ_MASK, bclk_val);
450 }
451 
452 static int cs530x_set_pll_refclk(struct snd_soc_component *component,
453                                   const unsigned int freq)
454 {
455         struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
456         struct regmap *regmap = priv->regmap;
457         unsigned int refclk;
458 
459         switch (freq) {
460         case 2822400:
461         case 3072000:
462                 refclk = CS530X_REFCLK_2P822_3P072;
463                 break;
464         case 5644800:
465         case 6144000:
466                 refclk = CS530X_REFCLK_5P6448_6P144;
467                 break;
468         case 11289600:
469         case 12288000:
470                 refclk = CS530X_REFCLK_11P2896_12P288;
471                 break;
472         case 22579200:
473         case 24576000:
474                 refclk = CS530X_REFCLK_24P5792_24P576;
475                 break;
476         default:
477                 dev_err(component->dev, "Invalid PLL refclk %d\n", freq);
478                 return -EINVAL;
479         }
480 
481         return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
482                                   CS530X_PLL_REFCLK_FREQ_MASK, refclk);
483 }
484 
485 static int cs530x_hw_params(struct snd_pcm_substream *substream,
486                             struct snd_pcm_hw_params *params,
487                             struct snd_soc_dai *dai)
488 {
489         struct snd_soc_component *component = dai->component;
490         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
491         struct regmap *regmap = cs530x->regmap;
492         int ret = 0, fs = params_rate(params), bclk;
493         unsigned int fs_val;
494 
495 
496         switch (fs) {
497         case 32000:
498                 fs_val = CS530X_FS_32K;
499                 break;
500         case 44100:
501         case 48000:
502                 fs_val = CS530X_FS_48K_44P1K;
503                 break;
504         case 88200:
505         case 96000:
506                 fs_val = CS530X_FS_96K_88P2K;
507                 break;
508         case 176400:
509         case 192000:
510                 fs_val = CS530X_FS_192K_176P4K;
511                 break;
512         case 356800:
513         case 384000:
514                 fs_val = CS530X_FS_384K_356P8K;
515                 break;
516         case 705600:
517         case 768000:
518                 fs_val = CS530X_FS_768K_705P6K;
519                 break;
520         default:
521                 dev_err(component->dev, "Invalid sample rate %d\n", fs);
522                 return -EINVAL;
523         }
524 
525         cs530x->fs = fs;
526         regmap_update_bits(regmap, CS530X_CLK_CFG_1,
527                            CS530X_SAMPLE_RATE_MASK, fs_val);
528 
529 
530         if (regmap_test_bits(regmap, CS530X_SIGNAL_PATH_CFG,
531                              CS530X_TDM_EN_MASK)) {
532                 dev_dbg(component->dev, "Configuring for %d %d bit TDM slots\n",
533                         cs530x->tdm_slots, cs530x->tdm_width);
534                 bclk = snd_soc_tdm_params_to_bclk(params,
535                                                   cs530x->tdm_width,
536                                                   cs530x->tdm_slots,
537                                                   1);
538         } else {
539                 bclk = snd_soc_params_to_bclk(params);
540         }
541 
542         if (!regmap_test_bits(regmap, CS530X_CLK_CFG_0,
543                              CS530X_PLL_REFCLK_SRC_MASK)) {
544                 ret = cs530x_set_pll_refclk(component, bclk);
545                 if (ret)
546                         return ret;
547         }
548 
549         return cs530x_set_bclk(component, bclk);
550 }
551 
552 static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
553 {
554         struct snd_soc_component *component = dai->component;
555         struct cs530x_priv *priv = snd_soc_component_get_drvdata(component);
556         struct regmap *regmap = priv->regmap;
557         unsigned int asp_fmt, asp_cfg = 0;
558 
559         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
560         case SND_SOC_DAIFMT_CBS_CFS:
561                 break;
562         case SND_SOC_DAIFMT_CBM_CFM:
563                 asp_cfg = CS530X_ASP_PRIMARY;
564                 break;
565         default:
566                 return -EINVAL;
567         }
568 
569         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
570         case SND_SOC_DAIFMT_DSP_A:
571                 asp_fmt = CS530X_ASP_FMT_DSP_A;
572                 break;
573         case SND_SOC_DAIFMT_I2S:
574                 asp_fmt = CS530X_ASP_FMT_I2S;
575                 break;
576         case SND_SOC_DAIFMT_LEFT_J:
577                 asp_fmt = CS530X_ASP_FMT_LJ;
578                 break;
579         default:
580                 return -EINVAL;
581         }
582 
583         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
584         case SND_SOC_DAIFMT_NB_NF:
585                 break;
586         case SND_SOC_DAIFMT_IB_IF:
587                 asp_cfg |= CS530X_ASP_BCLK_INV;
588                 break;
589         default:
590                 return -EINVAL;
591         }
592 
593         regmap_update_bits(regmap, CS530X_ASP_CFG,
594                            CS530X_ASP_PRIMARY | CS530X_ASP_BCLK_INV,
595                            asp_cfg);
596 
597         return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
598                                   CS530X_ASP_FMT_MASK, asp_fmt);
599 }
600 
601 static bool cs530x_check_mclk_freq(struct snd_soc_component *component,
602                                    const unsigned int freq)
603 {
604         switch (freq) {
605         case 24576000:
606         case 22579200:
607         case 12288000:
608         case 11289600:
609                 return true;
610         default:
611                 dev_err(component->dev, "Invalid MCLK %d\n", freq);
612                 return false;
613         }
614 }
615 
616 static int cs530x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
617                                  unsigned int rx_mask, int slots, int slot_width)
618 {
619         struct snd_soc_component *component = dai->component;
620         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
621         struct regmap *regmap = cs530x->regmap;
622         unsigned int val;
623 
624         switch (tx_mask) {
625         case CS530X_0_1_TDM_SLOT_MASK:
626         case CS530X_0_3_TDM_SLOT_MASK:
627         case CS530X_0_7_TDM_SLOT_MASK:
628                 val = CS530X_0_7_TDM_SLOT_VAL;
629                 break;
630         case CS530X_2_3_TDM_SLOT_MASK:
631                 val = CS530X_2_3_TDM_SLOT_VAL;
632                 break;
633         case CS530X_4_5_TDM_SLOT_MASK:
634         case CS530X_4_7_TDM_SLOT_MASK:
635                 val = CS530X_4_7_TDM_SLOT_VAL;
636                 break;
637         case CS530X_6_7_TDM_SLOT_MASK:
638                 val = CS530X_6_7_TDM_SLOT_VAL;
639                 break;
640         case CS530X_8_9_TDM_SLOT_MASK:
641         case CS530X_8_11_TDM_SLOT_MASK:
642         case CS530X_8_15_TDM_SLOT_MASK:
643                 val = CS530X_8_15_TDM_SLOT_VAL;
644                 break;
645         case CS530X_10_11_TDM_SLOT_MASK:
646                 val = CS530X_10_11_TDM_SLOT_VAL;
647                 break;
648         case CS530X_12_13_TDM_SLOT_MASK:
649         case CS530X_12_15_TDM_SLOT_MASK:
650                 val = CS530X_12_15_TDM_SLOT_VAL;
651                 break;
652         case CS530X_14_15_TDM_SLOT_MASK:
653                 val = CS530X_14_15_TDM_SLOT_VAL;
654                 break;
655         default:
656                 dev_err(component->dev, "Invalid TX slot(s) 0x%x\n", tx_mask);
657                 return -EINVAL;
658         }
659 
660         cs530x->tdm_width = slot_width;
661         cs530x->tdm_slots = slots;
662 
663         return regmap_update_bits(regmap, CS530X_SIGNAL_PATH_CFG,
664                                   CS530X_ASP_TDM_SLOT_MASK,
665                                   val << CS530X_ASP_TDM_SLOT_SHIFT);
666 }
667 
668 static const struct snd_soc_dai_ops cs530x_dai_ops = {
669         .set_fmt = cs530x_set_fmt,
670         .hw_params = cs530x_hw_params,
671         .set_tdm_slot = cs530x_set_tdm_slot,
672 };
673 
674 static const struct snd_soc_dai_driver cs530x_dai = {
675         .name = "cs530x-dai",
676         .capture = {
677                 .stream_name = "AIF Capture",
678                 .channels_min = 2,
679                 .channels_max = 8,
680                 .rates = SNDRV_PCM_RATE_KNOT,
681                 .formats = SNDRV_PCM_FMTBIT_S32_LE,
682         },
683         .ops = &cs530x_dai_ops,
684         .symmetric_rate = 1,
685         .symmetric_sample_bits = 1,
686 };
687 
688 static int cs530x_set_pll(struct snd_soc_component *component, int pll_id,
689                            int source, unsigned int freq_in,
690                            unsigned int freq_out)
691 {
692         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
693         struct regmap *regmap = cs530x->regmap;
694         unsigned int sysclk_src;
695         int ret;
696 
697         regmap_read(regmap, CS530X_CLK_CFG_0, &sysclk_src);
698 
699         /* Check if the source is the PLL  */
700         if ((sysclk_src & CS530X_SYSCLK_SRC_MASK) == 0)
701                 return 0;
702 
703         switch (source) {
704         case CS530X_PLL_SRC_MCLK:
705                 if (!cs530x_check_mclk_freq(component, freq_in))
706                         return -EINVAL;
707 
708                 ret = cs530x_set_pll_refclk(component, freq_in);
709                 if (ret)
710                         return ret;
711 
712                 break;
713         case CS530X_PLL_SRC_BCLK:
714                 break;
715         default:
716                 dev_err(component->dev, "Invalid PLL source %d\n", source);
717                 return -EINVAL;
718         }
719 
720         return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
721                                   CS530X_PLL_REFCLK_SRC_MASK, source);
722 }
723 
724 static int cs530x_component_probe(struct snd_soc_component *component)
725 {
726         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
727         struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
728         int num_widgets;
729 
730         snd_soc_dapm_new_controls(dapm, cs530x_gen_dapm_widgets,
731                                   ARRAY_SIZE(cs530x_gen_dapm_widgets));
732 
733         switch (cs530x->devtype) {
734         case CS5302:
735                 cs530x_add_12_adc_widgets(component);
736                 break;
737         case CS5304:
738                 cs530x_add_12_adc_widgets(component);
739                 cs530x_add_34_adc_widgets(component);
740 
741                 num_widgets = ARRAY_SIZE(cs530x_in_sum_4ch_controls);
742                 snd_soc_add_component_controls(component,
743                                                cs530x_in_sum_4ch_controls,
744                                                num_widgets);
745                 break;
746 
747         case CS5308:
748                 cs530x_add_12_adc_widgets(component);
749                 cs530x_add_34_adc_widgets(component);
750 
751                 num_widgets = ARRAY_SIZE(cs530x_in_5_to_8_controls);
752                 snd_soc_add_component_controls(component,
753                                                cs530x_in_5_to_8_controls,
754                                                num_widgets);
755 
756                 num_widgets = ARRAY_SIZE(cs530x_in_sum_8ch_controls);
757                 snd_soc_add_component_controls(component,
758                                                cs530x_in_sum_8ch_controls,
759                                                num_widgets);
760 
761                 num_widgets = ARRAY_SIZE(cs530x_adc_ch58_dapm_widgets);
762                 snd_soc_dapm_new_controls(dapm, cs530x_adc_ch58_dapm_widgets,
763                                           num_widgets);
764 
765                 snd_soc_dapm_add_routes(dapm, adc_ch5_8_routes,
766                                         ARRAY_SIZE(adc_ch5_8_routes));
767                 break;
768         default:
769                 dev_err(component->dev, "Invalid device type %d\n",
770                         cs530x->devtype);
771                 return -EINVAL;
772         }
773 
774         return 0;
775 }
776 
777 static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
778                                 int source, unsigned int freq, int dir)
779 {
780         struct cs530x_priv *cs530x = snd_soc_component_get_drvdata(component);
781         struct regmap *regmap = cs530x->regmap;
782 
783         switch (source) {
784         case CS530X_SYSCLK_SRC_MCLK:
785                 if (freq != 24560000 && freq != 22572000) {
786                         dev_err(component->dev, "Invalid MCLK source rate %d\n",
787                                 freq);
788                         return -EINVAL;
789                 }
790 
791                 cs530x->mclk_rate = freq;
792                 break;
793         case CS530X_SYSCLK_SRC_PLL:
794                 break;
795         default:
796                 dev_err(component->dev, "Invalid clock id %d\n", clk_id);
797                 return -EINVAL;
798         }
799 
800         return regmap_update_bits(regmap, CS530X_CLK_CFG_0,
801                                   CS530X_SYSCLK_SRC_MASK,
802                                   source << CS530X_SYSCLK_SRC_SHIFT);
803 }
804 
805 static const struct snd_soc_component_driver soc_component_dev_cs530x = {
806         .probe                  = cs530x_component_probe,
807         .set_sysclk             = cs530x_set_sysclk,
808         .set_pll                = cs530x_set_pll,
809         .endianness             = 1,
810 };
811 
812 const struct regmap_config cs530x_regmap = {
813         .reg_bits = 16,
814         .val_bits = 16,
815 
816         .max_register = CS530X_MAX_REGISTER,
817         .readable_reg = cs530x_readable_register,
818         .writeable_reg = cs530x_writeable_register,
819 
820         .cache_type = REGCACHE_MAPLE,
821         .reg_defaults = cs530x_reg_defaults,
822         .num_reg_defaults = ARRAY_SIZE(cs530x_reg_defaults),
823 };
824 EXPORT_SYMBOL_NS_GPL(cs530x_regmap, SND_SOC_CS530X);
825 
826 static int cs530x_check_device_id(struct cs530x_priv *cs530x)
827 {
828         struct device *dev = cs530x->dev;
829         unsigned int dev_id, rev;
830         int ret;
831 
832         ret = regmap_read(cs530x->regmap, CS530X_DEVID, &dev_id);
833         if (ret)
834                 return dev_err_probe(dev, ret, "Can't read device ID\n");
835 
836         ret = regmap_read(cs530x->regmap, CS530X_REVID, &rev);
837         if (ret)
838                 return dev_err_probe(dev, ret, "Can't read REV ID\n");
839 
840         dev_dbg(dev, "Device ID 0x%x Rev ID 0x%x\n", dev_id, rev);
841 
842         switch (dev_id) {
843         case CS530X_2CH_ADC_DEV_ID:
844                 cs530x->num_adcs = 2;
845                 break;
846         case CS530X_4CH_ADC_DEV_ID:
847                 cs530x->num_adcs = 4;
848                 break;
849         case CS530X_8CH_ADC_DEV_ID:
850                 cs530x->num_adcs = 8;
851                 break;
852         default:
853                 return dev_err_probe(dev, -EINVAL, "Invalid device ID 0x%x\n",
854                                      dev_id);
855         }
856 
857         return 0;
858 }
859 
860 static int cs530x_parse_device_properties(struct cs530x_priv *cs530x)
861 {
862         struct regmap *regmap = cs530x->regmap;
863         struct device *dev = cs530x->dev;
864         unsigned int val = 0;
865 
866         switch (cs530x->num_adcs) {
867         case 8:
868                 if (device_property_read_bool(dev, "cirrus,in-hiz-pin78"))
869                         val = CS530X_IN78_HIZ;
870 
871                 if (device_property_read_bool(dev, "cirrus,in-hiz-pin56"))
872                         val |= CS530X_IN56_HIZ;
873 
874                 fallthrough;
875         case 4:
876                 if (device_property_read_bool(dev, "cirrus,in-hiz-pin34"))
877                         val |= CS530X_IN34_HIZ;
878 
879                 fallthrough;
880         case 2:
881                 if (device_property_read_bool(dev, "cirrus,in-hiz-pin12"))
882                         val |= CS530X_IN12_HIZ;
883 
884                 return regmap_set_bits(regmap, CS530X_IN_HIZ, val);
885         default:
886                 return dev_err_probe(dev, -EINVAL,
887                                      "Invalid number of adcs %d\n",
888                                      cs530x->num_adcs);
889         }
890 }
891 
892 int cs530x_probe(struct cs530x_priv *cs530x)
893 {
894         struct device *dev = cs530x->dev;
895         int ret, i;
896 
897         cs530x->dev_dai = devm_kmemdup(dev, &cs530x_dai,
898                                         sizeof(*(cs530x->dev_dai)),
899                                         GFP_KERNEL);
900         if (!cs530x->dev_dai)
901                 return -ENOMEM;
902 
903         for (i = 0; i < ARRAY_SIZE(cs530x->supplies); i++)
904                 cs530x->supplies[i].supply = cs530x_supply_names[i];
905 
906         ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs530x->supplies),
907                                       cs530x->supplies);
908         if (ret != 0)
909                 return dev_err_probe(dev, ret, "Failed to request supplies");
910 
911         ret = regulator_bulk_enable(ARRAY_SIZE(cs530x->supplies),
912                                     cs530x->supplies);
913         if (ret != 0)
914                 return dev_err_probe(dev, ret, "Failed to enable supplies");
915 
916         cs530x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
917                                                       GPIOD_OUT_HIGH);
918         if (IS_ERR(cs530x->reset_gpio)) {
919                 ret = dev_err_probe(dev, PTR_ERR(cs530x->reset_gpio),
920                               "Reset gpio not available\n");
921                 goto err_regulator;
922         }
923 
924         if (cs530x->reset_gpio) {
925                 usleep_range(2000, 2100);
926                 gpiod_set_value_cansleep(cs530x->reset_gpio, 0);
927         }
928 
929         usleep_range(5000, 5100);
930         ret = cs530x_check_device_id(cs530x);
931         if (ret)
932                 goto err_reset;
933 
934         if (!cs530x->reset_gpio) {
935                 ret = regmap_write(cs530x->regmap, CS530X_SW_RESET,
936                                    CS530X_SW_RST_VAL);
937                 if (ret) {
938                         dev_err_probe(dev, ret, "Soft Reset Failed\n");
939                         goto err_reset;
940                 }
941         }
942 
943         ret = cs530x_parse_device_properties(cs530x);
944         if (ret)
945                 goto err_reset;
946 
947         cs530x->dev_dai->capture.channels_max = cs530x->num_adcs;
948 
949         ret = devm_snd_soc_register_component(dev,
950                         &soc_component_dev_cs530x, cs530x->dev_dai, 1);
951         if (ret) {
952                 dev_err_probe(dev, ret, "Can't register cs530x component\n");
953                 goto err_reset;
954         }
955 
956         return 0;
957 
958 err_reset:
959         gpiod_set_value_cansleep(cs530x->reset_gpio, 1);
960 
961 err_regulator:
962         regulator_bulk_disable(ARRAY_SIZE(cs530x->supplies),
963                                cs530x->supplies);
964 
965         return ret;
966 }
967 EXPORT_SYMBOL_NS_GPL(cs530x_probe, SND_SOC_CS530X);
968 
969 MODULE_DESCRIPTION("CS530X CODEC Driver");
970 MODULE_AUTHOR("Paul Handrigan <paulha@opensource.cirrus.com>");
971 MODULE_LICENSE("GPL");
972 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php