1// SPDX-License-Identifier: GPL-2.0
2//
3// JZ4725B CODEC driver
4//
5// Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net>
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/platform_device.h>
10#include <linux/slab.h>
11#include <linux/io.h>
12#include <linux/iopoll.h>
13#include <linux/regmap.h>
14#include <linux/clk.h>
15
16#include <linux/delay.h>
17
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/pcm_params.h>
21#include <sound/initval.h>
22#include <sound/soc.h>
23#include <sound/tlv.h>
24
25#define ICDC_RGADW_OFFSET 0x00
26#define ICDC_RGDATA_OFFSET 0x04
27
28/* ICDC internal register access control register(RGADW) */
29#define ICDC_RGADW_RGWR BIT(16)
30
31#define ICDC_RGADW_RGADDR_OFFSET 8
32#define ICDC_RGADW_RGADDR_MASK GENMASK(14, ICDC_RGADW_RGADDR_OFFSET)
33
34#define ICDC_RGADW_RGDIN_OFFSET 0
35#define ICDC_RGADW_RGDIN_MASK GENMASK(7, ICDC_RGADW_RGDIN_OFFSET)
36
37/* ICDC internal register data output register (RGDATA)*/
38#define ICDC_RGDATA_IRQ BIT(8)
39
40#define ICDC_RGDATA_RGDOUT_OFFSET 0
41#define ICDC_RGDATA_RGDOUT_MASK GENMASK(7, ICDC_RGDATA_RGDOUT_OFFSET)
42
43/* JZ internal register space */
44enum {
45 JZ4725B_CODEC_REG_AICR,
46 JZ4725B_CODEC_REG_CR1,
47 JZ4725B_CODEC_REG_CR2,
48 JZ4725B_CODEC_REG_CCR1,
49 JZ4725B_CODEC_REG_CCR2,
50 JZ4725B_CODEC_REG_PMR1,
51 JZ4725B_CODEC_REG_PMR2,
52 JZ4725B_CODEC_REG_CRR,
53 JZ4725B_CODEC_REG_ICR,
54 JZ4725B_CODEC_REG_IFR,
55 JZ4725B_CODEC_REG_CGR1,
56 JZ4725B_CODEC_REG_CGR2,
57 JZ4725B_CODEC_REG_CGR3,
58 JZ4725B_CODEC_REG_CGR4,
59 JZ4725B_CODEC_REG_CGR5,
60 JZ4725B_CODEC_REG_CGR6,
61 JZ4725B_CODEC_REG_CGR7,
62 JZ4725B_CODEC_REG_CGR8,
63 JZ4725B_CODEC_REG_CGR9,
64 JZ4725B_CODEC_REG_CGR10,
65 JZ4725B_CODEC_REG_TR1,
66 JZ4725B_CODEC_REG_TR2,
67 JZ4725B_CODEC_REG_CR3,
68 JZ4725B_CODEC_REG_AGC1,
69 JZ4725B_CODEC_REG_AGC2,
70 JZ4725B_CODEC_REG_AGC3,
71 JZ4725B_CODEC_REG_AGC4,
72 JZ4725B_CODEC_REG_AGC5,
73};
74
75#define REG_AICR_CONFIG1_OFFSET 0
76#define REG_AICR_CONFIG1_MASK (0xf << REG_AICR_CONFIG1_OFFSET)
77
78#define REG_CR1_SB_MICBIAS_OFFSET 7
79#define REG_CR1_MONO_OFFSET 6
80#define REG_CR1_DAC_MUTE_OFFSET 5
81#define REG_CR1_HP_DIS_OFFSET 4
82#define REG_CR1_DACSEL_OFFSET 3
83#define REG_CR1_BYPASS_OFFSET 2
84
85#define REG_CR2_DAC_DEEMP_OFFSET 7
86#define REG_CR2_DAC_ADWL_OFFSET 5
87#define REG_CR2_DAC_ADWL_MASK (0x3 << REG_CR2_DAC_ADWL_OFFSET)
88#define REG_CR2_ADC_ADWL_OFFSET 3
89#define REG_CR2_ADC_ADWL_MASK (0x3 << REG_CR2_ADC_ADWL_OFFSET)
90#define REG_CR2_ADC_HPF_OFFSET 2
91
92#define REG_CR3_SB_MIC1_OFFSET 7
93#define REG_CR3_SB_MIC2_OFFSET 6
94#define REG_CR3_SIDETONE1_OFFSET 5
95#define REG_CR3_SIDETONE2_OFFSET 4
96#define REG_CR3_MICDIFF_OFFSET 3
97#define REG_CR3_MICSTEREO_OFFSET 2
98#define REG_CR3_INSEL_OFFSET 0
99#define REG_CR3_INSEL_MASK (0x3 << REG_CR3_INSEL_OFFSET)
100
101#define REG_CCR1_CONFIG4_OFFSET 0
102#define REG_CCR1_CONFIG4_MASK (0xf << REG_CCR1_CONFIG4_OFFSET)
103
104#define REG_CCR2_DFREQ_OFFSET 4
105#define REG_CCR2_DFREQ_MASK (0xf << REG_CCR2_DFREQ_OFFSET)
106#define REG_CCR2_AFREQ_OFFSET 0
107#define REG_CCR2_AFREQ_MASK (0xf << REG_CCR2_AFREQ_OFFSET)
108
109#define REG_PMR1_SB_DAC_OFFSET 7
110#define REG_PMR1_SB_OUT_OFFSET 6
111#define REG_PMR1_SB_MIX_OFFSET 5
112#define REG_PMR1_SB_ADC_OFFSET 4
113#define REG_PMR1_SB_LIN_OFFSET 3
114#define REG_PMR1_SB_IND_OFFSET 0
115
116#define REG_PMR2_LRGI_OFFSET 7
117#define REG_PMR2_RLGI_OFFSET 6
118#define REG_PMR2_LRGOD_OFFSET 5
119#define REG_PMR2_RLGOD_OFFSET 4
120#define REG_PMR2_GIM_OFFSET 3
121#define REG_PMR2_SB_MC_OFFSET 2
122#define REG_PMR2_SB_OFFSET 1
123#define REG_PMR2_SB_SLEEP_OFFSET 0
124
125#define REG_IFR_RAMP_UP_DONE_OFFSET 3
126#define REG_IFR_RAMP_DOWN_DONE_OFFSET 2
127
128#define REG_CGR1_GODL_OFFSET 4
129#define REG_CGR1_GODL_MASK (0xf << REG_CGR1_GODL_OFFSET)
130#define REG_CGR1_GODR_OFFSET 0
131#define REG_CGR1_GODR_MASK (0xf << REG_CGR1_GODR_OFFSET)
132
133#define REG_CGR2_GO1R_OFFSET 0
134#define REG_CGR2_GO1R_MASK (0x1f << REG_CGR2_GO1R_OFFSET)
135
136#define REG_CGR3_GO1L_OFFSET 0
137#define REG_CGR3_GO1L_MASK (0x1f << REG_CGR3_GO1L_OFFSET)
138
139#define REG_CGR4_GO2R_OFFSET 0
140#define REG_CGR4_GO2R_MASK (0x1f << REG_CGR4_GO2R_OFFSET)
141
142#define REG_CGR5_GO2L_OFFSET 0
143#define REG_CGR5_GO2L_MASK (0x1f << REG_CGR5_GO2L_OFFSET)
144
145#define REG_CGR6_GO3R_OFFSET 0
146#define REG_CGR6_GO3R_MASK (0x1f << REG_CGR6_GO3R_OFFSET)
147
148#define REG_CGR7_GO3L_OFFSET 0
149#define REG_CGR7_GO3L_MASK (0x1f << REG_CGR7_GO3L_OFFSET)
150
151#define REG_CGR8_GOR_OFFSET 0
152#define REG_CGR8_GOR_MASK (0x1f << REG_CGR8_GOR_OFFSET)
153
154#define REG_CGR9_GOL_OFFSET 0
155#define REG_CGR9_GOL_MASK (0x1f << REG_CGR9_GOL_OFFSET)
156
157#define REG_CGR10_GIL_OFFSET 0
158#define REG_CGR10_GIR_OFFSET 4
159
160struct jz_icdc {
161 struct regmap *regmap;
162 void __iomem *base;
163 struct clk *clk;
164};
165
166static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv, 0, 150, 0);
167static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0);
168static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_mix_tlv,
169 0, 11, TLV_DB_SCALE_ITEM(-2250, 0, 0),
170 12, 31, TLV_DB_SCALE_ITEM(-2250, 150, 0),
171);
172
173static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(jz4725b_out_tlv,
174 0, 11, TLV_DB_SCALE_ITEM(-3350, 200, 0),
175 12, 23, TLV_DB_SCALE_ITEM(-1050, 100, 0),
176 24, 31, TLV_DB_SCALE_ITEM( 100, 50, 0),
177);
178static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0);
179
180static const char * const jz4725b_mic_mode_texts[] = {
181 "Single Ended", "Differential",
182};
183
184static const struct soc_enum jz4725b_mic_mode_enum =
185 SOC_ENUM_SINGLE(JZ4725B_CODEC_REG_CR3, REG_CR3_MICDIFF_OFFSET,
186 2, jz4725b_mic_mode_texts);
187
188static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
189 SOC_DOUBLE_TLV("DAC Playback Volume",
190 JZ4725B_CODEC_REG_CGR1,
191 REG_CGR1_GODL_OFFSET,
192 REG_CGR1_GODR_OFFSET,
193 0xf, 1, jz4725b_dac_tlv),
194 SOC_DOUBLE_TLV("Master Capture Volume",
195 JZ4725B_CODEC_REG_CGR10,
196 REG_CGR10_GIL_OFFSET,
197 REG_CGR10_GIR_OFFSET,
198 0xf, 0, jz4725b_adc_tlv),
199 SOC_DOUBLE_R_TLV("Mixer Line In Bypass Playback Volume",
200 JZ4725B_CODEC_REG_CGR3,
201 JZ4725B_CODEC_REG_CGR2,
202 REG_CGR2_GO1R_OFFSET,
203 0x1f, 1, jz4725b_mix_tlv),
204 SOC_DOUBLE_R_TLV("Mixer Mic 1 Bypass Playback Volume",
205 JZ4725B_CODEC_REG_CGR5,
206 JZ4725B_CODEC_REG_CGR4,
207 REG_CGR4_GO2R_OFFSET,
208 0x1f, 1, jz4725b_mix_tlv),
209 SOC_DOUBLE_R_TLV("Mixer Mic 2 Bypass Playback Volume",
210 JZ4725B_CODEC_REG_CGR7,
211 JZ4725B_CODEC_REG_CGR6,
212 REG_CGR6_GO3R_OFFSET,
213 0x1f, 1, jz4725b_mix_tlv),
214
215 SOC_DOUBLE_R_TLV("Master Playback Volume",
216 JZ4725B_CODEC_REG_CGR9,
217 JZ4725B_CODEC_REG_CGR8,
218 REG_CGR8_GOR_OFFSET,
219 0x1f, 1, jz4725b_out_tlv),
220
221 SOC_SINGLE("DAC Playback Switch", JZ4725B_CODEC_REG_CR1,
222 REG_CR1_DAC_MUTE_OFFSET, 1, 1),
223
224 SOC_SINGLE("Deemphasize Filter Playback Switch",
225 JZ4725B_CODEC_REG_CR2,
226 REG_CR2_DAC_DEEMP_OFFSET, 1, 0),
227
228 SOC_SINGLE("High-Pass Filter Capture Switch",
229 JZ4725B_CODEC_REG_CR2,
230 REG_CR2_ADC_HPF_OFFSET, 1, 0),
231
232 SOC_ENUM("Mic Mode Capture Switch", jz4725b_mic_mode_enum),
233
234 SOC_SINGLE_TLV("Mic1 Boost Capture Volume",
235 JZ4725B_CODEC_REG_PMR2,
236 REG_PMR2_GIM_OFFSET,
237 1, 0, jz4725b_mic_boost_tlv),
238};
239
240static const char * const jz4725b_codec_adc_src_texts[] = {
241 "Mic 1", "Mic 2", "Line In", "Mixer",
242};
243static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, };
244static SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum,
245 JZ4725B_CODEC_REG_CR3,
246 REG_CR3_INSEL_OFFSET,
247 REG_CR3_INSEL_MASK,
248 jz4725b_codec_adc_src_texts,
249 jz4725b_codec_adc_src_values);
250static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
251 SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum);
252
253static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
254 SOC_DAPM_SINGLE("Line In Bypass Playback Switch", JZ4725B_CODEC_REG_CR1,
255 REG_CR1_BYPASS_OFFSET, 1, 0),
256 SOC_DAPM_SINGLE("Mic 1 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
257 REG_CR3_SIDETONE1_OFFSET, 1, 0),
258 SOC_DAPM_SINGLE("Mic 2 Bypass Playback Switch", JZ4725B_CODEC_REG_CR3,
259 REG_CR3_SIDETONE2_OFFSET, 1, 0),
260};
261
262static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
263 struct snd_kcontrol *kcontrol,
264 int event)
265{
266 struct snd_soc_component *codec = snd_soc_dapm_to_component(dapm: w->dapm);
267 struct jz_icdc *icdc = snd_soc_component_get_drvdata(c: codec);
268 struct regmap *map = icdc->regmap;
269 unsigned int val;
270
271 switch (event) {
272 case SND_SOC_DAPM_PRE_PMU:
273 return regmap_clear_bits(map, reg: JZ4725B_CODEC_REG_IFR,
274 BIT(REG_IFR_RAMP_UP_DONE_OFFSET));
275 case SND_SOC_DAPM_POST_PMU:
276 return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
277 val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET),
278 100000, 500000);
279 case SND_SOC_DAPM_PRE_PMD:
280 return regmap_clear_bits(map, reg: JZ4725B_CODEC_REG_IFR,
281 BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET));
282 case SND_SOC_DAPM_POST_PMD:
283 return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
284 val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET),
285 100000, 500000);
286 default:
287 return -EINVAL;
288 }
289}
290
291static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = {
292 /* DAC */
293 SND_SOC_DAPM_DAC("DAC", "Playback",
294 JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1),
295
296 /* ADC */
297 SND_SOC_DAPM_ADC("ADC", "Capture",
298 JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1),
299
300 SND_SOC_DAPM_MUX("ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
301 &jz4725b_codec_adc_src_ctrl),
302
303 /* Mixer */
304 SND_SOC_DAPM_MIXER("Mixer", JZ4725B_CODEC_REG_PMR1,
305 REG_PMR1_SB_MIX_OFFSET, 1,
306 jz4725b_codec_mixer_controls,
307 ARRAY_SIZE(jz4725b_codec_mixer_controls)),
308 SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1,
309 REG_CR1_DACSEL_OFFSET, 0, NULL, 0),
310
311 SND_SOC_DAPM_MIXER("Line In", JZ4725B_CODEC_REG_PMR1,
312 REG_PMR1_SB_LIN_OFFSET, 1, NULL, 0),
313 SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1,
314 REG_CR1_HP_DIS_OFFSET, 1, NULL, 0),
315
316 SND_SOC_DAPM_MIXER("Mic 1", JZ4725B_CODEC_REG_CR3,
317 REG_CR3_SB_MIC1_OFFSET, 1, NULL, 0),
318 SND_SOC_DAPM_MIXER("Mic 2", JZ4725B_CODEC_REG_CR3,
319 REG_CR3_SB_MIC2_OFFSET, 1, NULL, 0),
320
321 SND_SOC_DAPM_MIXER_E("Out Stage", JZ4725B_CODEC_REG_PMR1,
322 REG_PMR1_SB_OUT_OFFSET, 1, NULL, 0,
323 jz4725b_out_stage_enable,
324 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
325 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
326 SND_SOC_DAPM_MIXER("Mixer to ADC", JZ4725B_CODEC_REG_PMR1,
327 REG_PMR1_SB_IND_OFFSET, 1, NULL, 0),
328
329 SND_SOC_DAPM_SUPPLY("Mic Bias", JZ4725B_CODEC_REG_CR1,
330 REG_CR1_SB_MICBIAS_OFFSET, 1, NULL, 0),
331
332 /* Pins */
333 SND_SOC_DAPM_INPUT("MIC1P"),
334 SND_SOC_DAPM_INPUT("MIC1N"),
335 SND_SOC_DAPM_INPUT("MIC2P"),
336 SND_SOC_DAPM_INPUT("MIC2N"),
337
338 SND_SOC_DAPM_INPUT("LLINEIN"),
339 SND_SOC_DAPM_INPUT("RLINEIN"),
340
341 SND_SOC_DAPM_OUTPUT("LHPOUT"),
342 SND_SOC_DAPM_OUTPUT("RHPOUT"),
343};
344
345static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
346 {"Mic 1", NULL, "MIC1P"},
347 {"Mic 1", NULL, "MIC1N"},
348 {"Mic 2", NULL, "MIC2P"},
349 {"Mic 2", NULL, "MIC2N"},
350
351 {"Line In", NULL, "LLINEIN"},
352 {"Line In", NULL, "RLINEIN"},
353
354 {"Mixer", "Mic 1 Bypass Playback Switch", "Mic 1"},
355 {"Mixer", "Mic 2 Bypass Playback Switch", "Mic 2"},
356 {"Mixer", "Line In Bypass Playback Switch", "Line In"},
357 {"DAC to Mixer", NULL, "DAC"},
358 {"Mixer", NULL, "DAC to Mixer"},
359
360 {"Mixer to ADC", NULL, "Mixer"},
361 {"ADC Source Capture Route", "Mixer", "Mixer to ADC"},
362 {"ADC Source Capture Route", "Line In", "Line In"},
363 {"ADC Source Capture Route", "Mic 1", "Mic 1"},
364 {"ADC Source Capture Route", "Mic 2", "Mic 2"},
365 {"ADC", NULL, "ADC Source Capture Route"},
366
367 {"Out Stage", NULL, "Mixer"},
368 {"HP Out", NULL, "Out Stage"},
369 {"LHPOUT", NULL, "HP Out"},
370 {"RHPOUT", NULL, "HP Out"},
371};
372
373static int jz4725b_codec_set_bias_level(struct snd_soc_component *component,
374 enum snd_soc_bias_level level)
375{
376 struct jz_icdc *icdc = snd_soc_component_get_drvdata(c: component);
377 struct regmap *map = icdc->regmap;
378
379 switch (level) {
380 case SND_SOC_BIAS_ON:
381 regmap_clear_bits(map, reg: JZ4725B_CODEC_REG_PMR2,
382 BIT(REG_PMR2_SB_SLEEP_OFFSET));
383 break;
384 case SND_SOC_BIAS_PREPARE:
385 /* Enable sound hardware */
386 regmap_clear_bits(map, reg: JZ4725B_CODEC_REG_PMR2,
387 BIT(REG_PMR2_SB_OFFSET));
388 msleep(msecs: 224);
389 break;
390 case SND_SOC_BIAS_STANDBY:
391 regmap_set_bits(map, reg: JZ4725B_CODEC_REG_PMR2,
392 BIT(REG_PMR2_SB_SLEEP_OFFSET));
393 break;
394 case SND_SOC_BIAS_OFF:
395 regmap_set_bits(map, reg: JZ4725B_CODEC_REG_PMR2,
396 BIT(REG_PMR2_SB_OFFSET));
397 break;
398 }
399
400 return 0;
401}
402
403static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
404{
405 struct jz_icdc *icdc = snd_soc_component_get_drvdata(c: component);
406 struct regmap *map = icdc->regmap;
407
408 clk_prepare_enable(clk: icdc->clk);
409
410 /* Write CONFIGn (n=1 to 8) bits.
411 * The value 0x0f is specified in the datasheet as a requirement.
412 */
413 regmap_write(map, reg: JZ4725B_CODEC_REG_AICR,
414 val: 0xf << REG_AICR_CONFIG1_OFFSET);
415 regmap_write(map, reg: JZ4725B_CODEC_REG_CCR1,
416 val: 0x0 << REG_CCR1_CONFIG4_OFFSET);
417
418 return 0;
419}
420
421static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
422{
423 struct jz_icdc *icdc = snd_soc_component_get_drvdata(c: component);
424
425 clk_disable_unprepare(clk: icdc->clk);
426}
427
428static const struct snd_soc_component_driver jz4725b_codec = {
429 .probe = jz4725b_codec_dev_probe,
430 .remove = jz4725b_codec_dev_remove,
431 .set_bias_level = jz4725b_codec_set_bias_level,
432 .controls = jz4725b_codec_controls,
433 .num_controls = ARRAY_SIZE(jz4725b_codec_controls),
434 .dapm_widgets = jz4725b_codec_dapm_widgets,
435 .num_dapm_widgets = ARRAY_SIZE(jz4725b_codec_dapm_widgets),
436 .dapm_routes = jz4725b_codec_dapm_routes,
437 .num_dapm_routes = ARRAY_SIZE(jz4725b_codec_dapm_routes),
438 .suspend_bias_off = 1,
439 .use_pmdown_time = 1,
440};
441
442static const unsigned int jz4725b_codec_sample_rates[] = {
443 96000, 48000, 44100, 32000,
444 24000, 22050, 16000, 12000,
445 11025, 9600, 8000,
446};
447
448static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream,
449 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
450{
451 struct jz_icdc *icdc = snd_soc_component_get_drvdata(c: dai->component);
452 unsigned int rate, bit_width;
453
454 switch (params_format(p: params)) {
455 case SNDRV_PCM_FORMAT_S16_LE:
456 bit_width = 0;
457 break;
458 case SNDRV_PCM_FORMAT_S18_3LE:
459 bit_width = 1;
460 break;
461 case SNDRV_PCM_FORMAT_S20_3LE:
462 bit_width = 2;
463 break;
464 case SNDRV_PCM_FORMAT_S24_3LE:
465 bit_width = 3;
466 break;
467 default:
468 return -EINVAL;
469 }
470
471 for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) {
472 if (jz4725b_codec_sample_rates[rate] == params_rate(p: params))
473 break;
474 }
475
476 if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates))
477 return -EINVAL;
478
479 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
480 regmap_update_bits(map: icdc->regmap,
481 reg: JZ4725B_CODEC_REG_CR2,
482 REG_CR2_DAC_ADWL_MASK,
483 val: bit_width << REG_CR2_DAC_ADWL_OFFSET);
484
485 regmap_update_bits(map: icdc->regmap,
486 reg: JZ4725B_CODEC_REG_CCR2,
487 REG_CCR2_DFREQ_MASK,
488 val: rate << REG_CCR2_DFREQ_OFFSET);
489 } else {
490 regmap_update_bits(map: icdc->regmap,
491 reg: JZ4725B_CODEC_REG_CR2,
492 REG_CR2_ADC_ADWL_MASK,
493 val: bit_width << REG_CR2_ADC_ADWL_OFFSET);
494
495 regmap_update_bits(map: icdc->regmap,
496 reg: JZ4725B_CODEC_REG_CCR2,
497 REG_CCR2_AFREQ_MASK,
498 val: rate << REG_CCR2_AFREQ_OFFSET);
499 }
500
501 return 0;
502}
503
504static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = {
505 .hw_params = jz4725b_codec_hw_params,
506};
507
508#define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
509 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE)
510
511static struct snd_soc_dai_driver jz4725b_codec_dai = {
512 .name = "jz4725b-hifi",
513 .playback = {
514 .stream_name = "Playback",
515 .channels_min = 2,
516 .channels_max = 2,
517 .rates = SNDRV_PCM_RATE_8000_96000,
518 .formats = JZ_ICDC_FORMATS,
519 },
520 .capture = {
521 .stream_name = "Capture",
522 .channels_min = 2,
523 .channels_max = 2,
524 .rates = SNDRV_PCM_RATE_8000_96000,
525 .formats = JZ_ICDC_FORMATS,
526 },
527 .ops = &jz4725b_codec_dai_ops,
528};
529
530static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg)
531{
532 return reg == JZ4725B_CODEC_REG_IFR;
533}
534
535static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg)
536{
537 return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2);
538}
539
540static int jz4725b_codec_io_wait(struct jz_icdc *icdc)
541{
542 u32 reg;
543
544 return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg,
545 !(reg & ICDC_RGADW_RGWR), 1000, 10000);
546}
547
548static int jz4725b_codec_reg_read(void *context, unsigned int reg,
549 unsigned int *val)
550{
551 struct jz_icdc *icdc = context;
552 unsigned int i;
553 u32 tmp;
554 int ret;
555
556 ret = jz4725b_codec_io_wait(icdc);
557 if (ret)
558 return ret;
559
560 tmp = readl(addr: icdc->base + ICDC_RGADW_OFFSET);
561 tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
562 | (reg << ICDC_RGADW_RGADDR_OFFSET);
563 writel(val: tmp, addr: icdc->base + ICDC_RGADW_OFFSET);
564
565 /* wait 6+ cycles */
566 for (i = 0; i < 6; i++)
567 *val = readl(addr: icdc->base + ICDC_RGDATA_OFFSET) &
568 ICDC_RGDATA_RGDOUT_MASK;
569
570 return 0;
571}
572
573static int jz4725b_codec_reg_write(void *context, unsigned int reg,
574 unsigned int val)
575{
576 struct jz_icdc *icdc = context;
577 int ret;
578
579 ret = jz4725b_codec_io_wait(icdc);
580 if (ret)
581 return ret;
582
583 writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val,
584 addr: icdc->base + ICDC_RGADW_OFFSET);
585
586 ret = jz4725b_codec_io_wait(icdc);
587 if (ret)
588 return ret;
589
590 return 0;
591}
592
593static const u8 jz4725b_codec_reg_defaults[] = {
594 0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51,
595 0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
596 0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34,
597 0x07, 0x44, 0x1f, 0x00,
598};
599
600static const struct regmap_config jz4725b_codec_regmap_config = {
601 .reg_bits = 7,
602 .val_bits = 8,
603
604 .max_register = JZ4725B_CODEC_REG_AGC5,
605 .volatile_reg = jz4725b_codec_volatile,
606 .readable_reg = jz4725b_codec_can_access_reg,
607 .writeable_reg = jz4725b_codec_can_access_reg,
608
609 .reg_read = jz4725b_codec_reg_read,
610 .reg_write = jz4725b_codec_reg_write,
611
612 .reg_defaults_raw = jz4725b_codec_reg_defaults,
613 .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults),
614 .cache_type = REGCACHE_FLAT,
615};
616
617static int jz4725b_codec_probe(struct platform_device *pdev)
618{
619 struct device *dev = &pdev->dev;
620 struct jz_icdc *icdc;
621 int ret;
622
623 icdc = devm_kzalloc(dev, size: sizeof(*icdc), GFP_KERNEL);
624 if (!icdc)
625 return -ENOMEM;
626
627 icdc->base = devm_platform_ioremap_resource(pdev, index: 0);
628 if (IS_ERR(ptr: icdc->base))
629 return PTR_ERR(ptr: icdc->base);
630
631 icdc->regmap = devm_regmap_init(dev, NULL, icdc,
632 &jz4725b_codec_regmap_config);
633 if (IS_ERR(ptr: icdc->regmap))
634 return PTR_ERR(ptr: icdc->regmap);
635
636 icdc->clk = devm_clk_get(dev: &pdev->dev, id: "aic");
637 if (IS_ERR(ptr: icdc->clk))
638 return PTR_ERR(ptr: icdc->clk);
639
640 platform_set_drvdata(pdev, data: icdc);
641
642 ret = devm_snd_soc_register_component(dev, component_driver: &jz4725b_codec,
643 dai_drv: &jz4725b_codec_dai, num_dai: 1);
644 if (ret)
645 dev_err(dev, "Failed to register codec\n");
646
647 return ret;
648}
649
650static const struct of_device_id jz4725b_codec_of_matches[] = {
651 { .compatible = "ingenic,jz4725b-codec", },
652 { }
653};
654MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches);
655
656static struct platform_driver jz4725b_codec_driver = {
657 .probe = jz4725b_codec_probe,
658 .driver = {
659 .name = "jz4725b-codec",
660 .of_match_table = jz4725b_codec_of_matches,
661 },
662};
663module_platform_driver(jz4725b_codec_driver);
664
665MODULE_DESCRIPTION("JZ4725B SoC internal codec driver");
666MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
667MODULE_LICENSE("GPL v2");
668

source code of linux/sound/soc/codecs/jz4725b.c