xref: /openbmc/linux/sound/soc/codecs/jz4725b.c (revision 002dff36)
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 */
44 enum {
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 struct jz_icdc {
140 	struct regmap *regmap;
141 	void __iomem *base;
142 	struct clk *clk;
143 };
144 
145 static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0);
146 static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600);
147 
148 static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
149 	SOC_DOUBLE_TLV("Master Playback Volume",
150 		       JZ4725B_CODEC_REG_CGR1,
151 		       REG_CGR1_GODL_OFFSET,
152 		       REG_CGR1_GODR_OFFSET,
153 		       0xf, 1, jz4725b_dac_tlv),
154 	SOC_DOUBLE_R_TLV("Master Capture Volume",
155 			 JZ4725B_CODEC_REG_CGR3,
156 			 JZ4725B_CODEC_REG_CGR2,
157 			 REG_CGR2_GO1R_OFFSET,
158 			 0x1f, 1, jz4725b_line_tlv),
159 
160 	SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1,
161 		   REG_CR1_DAC_MUTE_OFFSET, 1, 1),
162 
163 	SOC_SINGLE("Deemphasize Filter Playback Switch",
164 		   JZ4725B_CODEC_REG_CR2,
165 		   REG_CR2_DAC_DEEMP_OFFSET, 1, 0),
166 
167 	SOC_SINGLE("High-Pass Filter Capture Switch",
168 		   JZ4725B_CODEC_REG_CR2,
169 		   REG_CR2_ADC_HPF_OFFSET, 1, 0),
170 };
171 
172 static const char * const jz4725b_codec_adc_src_texts[] = {
173 	"Mic 1", "Mic 2", "Line In", "Mixer",
174 };
175 static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, };
176 static SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum,
177 				  JZ4725B_CODEC_REG_CR3,
178 				  REG_CR3_INSEL_OFFSET,
179 				  REG_CR3_INSEL_MASK,
180 				  jz4725b_codec_adc_src_texts,
181 				  jz4725b_codec_adc_src_values);
182 static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
183 			SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum);
184 
185 static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
186 	SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1,
187 			REG_CR1_BYPASS_OFFSET, 1, 0),
188 };
189 
190 static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
191 				    struct snd_kcontrol *kcontrol,
192 				    int event)
193 {
194 	struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
195 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(codec);
196 	struct regmap *map = icdc->regmap;
197 	unsigned int val;
198 
199 	switch (event) {
200 	case SND_SOC_DAPM_PRE_PMU:
201 		return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR,
202 					  BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 0);
203 	case SND_SOC_DAPM_POST_PMU:
204 		return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
205 			       val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET),
206 			       100000, 500000);
207 	case SND_SOC_DAPM_PRE_PMD:
208 		return regmap_update_bits(map, JZ4725B_CODEC_REG_IFR,
209 				BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 0);
210 	case SND_SOC_DAPM_POST_PMD:
211 		return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
212 			       val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET),
213 			       100000, 500000);
214 	default:
215 		return -EINVAL;
216 	}
217 }
218 
219 static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = {
220 	/* DAC */
221 	SND_SOC_DAPM_DAC("DAC", "Playback",
222 			 JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1),
223 
224 	/* ADC */
225 	SND_SOC_DAPM_ADC("ADC", "Capture",
226 			 JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1),
227 
228 	SND_SOC_DAPM_MUX("ADC Source", SND_SOC_NOPM, 0, 0,
229 			 &jz4725b_codec_adc_src_ctrl),
230 
231 	/* Mixer */
232 	SND_SOC_DAPM_MIXER("Mixer", JZ4725B_CODEC_REG_PMR1,
233 			   REG_PMR1_SB_MIX_OFFSET, 1,
234 			   jz4725b_codec_mixer_controls,
235 			   ARRAY_SIZE(jz4725b_codec_mixer_controls)),
236 	SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1,
237 			   REG_CR1_DACSEL_OFFSET, 0, NULL, 0),
238 
239 	SND_SOC_DAPM_MIXER("Line In", SND_SOC_NOPM, 0, 0, NULL, 0),
240 	SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1,
241 			   REG_CR1_HP_DIS_OFFSET, 1, NULL, 0),
242 
243 	SND_SOC_DAPM_MIXER("Mic 1", JZ4725B_CODEC_REG_CR3,
244 			   REG_CR3_SB_MIC1_OFFSET, 1, NULL, 0),
245 	SND_SOC_DAPM_MIXER("Mic 2", JZ4725B_CODEC_REG_CR3,
246 			   REG_CR3_SB_MIC2_OFFSET, 1, NULL, 0),
247 
248 	SND_SOC_DAPM_MIXER_E("Out Stage", JZ4725B_CODEC_REG_PMR1,
249 			     REG_PMR1_SB_OUT_OFFSET, 1, NULL, 0,
250 			     jz4725b_out_stage_enable,
251 			     SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
252 			     SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
253 	SND_SOC_DAPM_MIXER("Mixer to ADC", JZ4725B_CODEC_REG_PMR1,
254 			   REG_PMR1_SB_IND_OFFSET, 1, NULL, 0),
255 
256 	SND_SOC_DAPM_SUPPLY("Mic Bias", JZ4725B_CODEC_REG_CR1,
257 			    REG_CR1_SB_MICBIAS_OFFSET, 1, NULL, 0),
258 
259 	/* Pins */
260 	SND_SOC_DAPM_INPUT("MIC1P"),
261 	SND_SOC_DAPM_INPUT("MIC1N"),
262 	SND_SOC_DAPM_INPUT("MIC2P"),
263 	SND_SOC_DAPM_INPUT("MIC2N"),
264 
265 	SND_SOC_DAPM_INPUT("LLINEIN"),
266 	SND_SOC_DAPM_INPUT("RLINEIN"),
267 
268 	SND_SOC_DAPM_OUTPUT("LHPOUT"),
269 	SND_SOC_DAPM_OUTPUT("RHPOUT"),
270 };
271 
272 static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
273 	{"Mic 1", NULL, "MIC1P"},
274 	{"Mic 1", NULL, "MIC1N"},
275 	{"Mic 2", NULL, "MIC2P"},
276 	{"Mic 2", NULL, "MIC2N"},
277 
278 	{"Line In", NULL, "LLINEIN"},
279 	{"Line In", NULL, "RLINEIN"},
280 
281 	{"Mixer", "Line In Bypass", "Line In"},
282 	{"DAC to Mixer", NULL, "DAC"},
283 	{"Mixer", NULL, "DAC to Mixer"},
284 
285 	{"Mixer to ADC", NULL, "Mixer"},
286 	{"ADC Source", "Mixer", "Mixer to ADC"},
287 	{"ADC Source", "Line In", "Line In"},
288 	{"ADC Source", "Mic 1", "Mic 1"},
289 	{"ADC Source", "Mic 2", "Mic 2"},
290 	{"ADC", NULL, "ADC Source"},
291 
292 	{"Out Stage", NULL, "Mixer"},
293 	{"HP Out", NULL, "Out Stage"},
294 	{"LHPOUT", NULL, "HP Out"},
295 	{"RHPOUT", NULL, "HP Out"},
296 };
297 
298 static int jz4725b_codec_set_bias_level(struct snd_soc_component *component,
299 					enum snd_soc_bias_level level)
300 {
301 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
302 	struct regmap *map = icdc->regmap;
303 
304 	switch (level) {
305 	case SND_SOC_BIAS_ON:
306 		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
307 				   BIT(REG_PMR2_SB_SLEEP_OFFSET), 0);
308 		break;
309 	case SND_SOC_BIAS_PREPARE:
310 		/* Enable sound hardware */
311 		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
312 				   BIT(REG_PMR2_SB_OFFSET), 0);
313 		msleep(224);
314 		break;
315 	case SND_SOC_BIAS_STANDBY:
316 		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
317 				   BIT(REG_PMR2_SB_SLEEP_OFFSET),
318 				   BIT(REG_PMR2_SB_SLEEP_OFFSET));
319 		break;
320 	case SND_SOC_BIAS_OFF:
321 		regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
322 				   BIT(REG_PMR2_SB_OFFSET),
323 				   BIT(REG_PMR2_SB_OFFSET));
324 		break;
325 	}
326 
327 	return 0;
328 }
329 
330 static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
331 {
332 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
333 	struct regmap *map = icdc->regmap;
334 
335 	clk_prepare_enable(icdc->clk);
336 
337 	/* Write CONFIGn (n=1 to 8) bits.
338 	 * The value 0x0f is specified in the datasheet as a requirement.
339 	 */
340 	regmap_write(map, JZ4725B_CODEC_REG_AICR,
341 		     0xf << REG_AICR_CONFIG1_OFFSET);
342 	regmap_write(map, JZ4725B_CODEC_REG_CCR1,
343 		     0x0 << REG_CCR1_CONFIG4_OFFSET);
344 
345 	return 0;
346 }
347 
348 static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
349 {
350 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
351 
352 	clk_disable_unprepare(icdc->clk);
353 }
354 
355 static const struct snd_soc_component_driver jz4725b_codec = {
356 	.probe			= jz4725b_codec_dev_probe,
357 	.remove			= jz4725b_codec_dev_remove,
358 	.set_bias_level		= jz4725b_codec_set_bias_level,
359 	.controls		= jz4725b_codec_controls,
360 	.num_controls		= ARRAY_SIZE(jz4725b_codec_controls),
361 	.dapm_widgets		= jz4725b_codec_dapm_widgets,
362 	.num_dapm_widgets	= ARRAY_SIZE(jz4725b_codec_dapm_widgets),
363 	.dapm_routes		= jz4725b_codec_dapm_routes,
364 	.num_dapm_routes	= ARRAY_SIZE(jz4725b_codec_dapm_routes),
365 	.suspend_bias_off	= 1,
366 	.use_pmdown_time	= 1,
367 };
368 
369 static const unsigned int jz4725b_codec_sample_rates[] = {
370 	96000, 48000, 44100, 32000,
371 	24000, 22050, 16000, 12000,
372 	11025, 9600, 8000,
373 };
374 
375 static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream,
376 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
377 {
378 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component);
379 	unsigned int rate, bit_width;
380 
381 	switch (params_format(params)) {
382 	case SNDRV_PCM_FORMAT_S16_LE:
383 		bit_width = 0;
384 		break;
385 	case SNDRV_PCM_FORMAT_S18_3LE:
386 		bit_width = 1;
387 		break;
388 	case SNDRV_PCM_FORMAT_S20_3LE:
389 		bit_width = 2;
390 		break;
391 	case SNDRV_PCM_FORMAT_S24_3LE:
392 		bit_width = 3;
393 		break;
394 	default:
395 		return -EINVAL;
396 	}
397 
398 	for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) {
399 		if (jz4725b_codec_sample_rates[rate] == params_rate(params))
400 			break;
401 	}
402 
403 	if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates))
404 		return -EINVAL;
405 
406 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
407 		regmap_update_bits(icdc->regmap,
408 				   JZ4725B_CODEC_REG_CR2,
409 				   REG_CR2_DAC_ADWL_MASK,
410 				   bit_width << REG_CR2_DAC_ADWL_OFFSET);
411 
412 		regmap_update_bits(icdc->regmap,
413 				   JZ4725B_CODEC_REG_CCR2,
414 				   REG_CCR2_DFREQ_MASK,
415 				   rate << REG_CCR2_DFREQ_OFFSET);
416 	} else {
417 		regmap_update_bits(icdc->regmap,
418 				   JZ4725B_CODEC_REG_CR2,
419 				   REG_CR2_ADC_ADWL_MASK,
420 				   bit_width << REG_CR2_ADC_ADWL_OFFSET);
421 
422 		regmap_update_bits(icdc->regmap,
423 				   JZ4725B_CODEC_REG_CCR2,
424 				   REG_CCR2_AFREQ_MASK,
425 				   rate << REG_CCR2_AFREQ_OFFSET);
426 	}
427 
428 	return 0;
429 }
430 
431 static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = {
432 	.hw_params = jz4725b_codec_hw_params,
433 };
434 
435 #define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S18_3LE | \
436 			 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE)
437 
438 static struct snd_soc_dai_driver jz4725b_codec_dai = {
439 	.name = "jz4725b-hifi",
440 	.playback = {
441 		.stream_name = "Playback",
442 		.channels_min = 2,
443 		.channels_max = 2,
444 		.rates = SNDRV_PCM_RATE_8000_96000,
445 		.formats = JZ_ICDC_FORMATS,
446 	},
447 	.capture = {
448 		.stream_name = "Capture",
449 		.channels_min = 2,
450 		.channels_max = 2,
451 		.rates = SNDRV_PCM_RATE_8000_96000,
452 		.formats = JZ_ICDC_FORMATS,
453 	},
454 	.ops = &jz4725b_codec_dai_ops,
455 };
456 
457 static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg)
458 {
459 	return reg == JZ4725B_CODEC_REG_IFR;
460 }
461 
462 static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg)
463 {
464 	return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2);
465 }
466 
467 static int jz4725b_codec_io_wait(struct jz_icdc *icdc)
468 {
469 	u32 reg;
470 
471 	return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg,
472 				  !(reg & ICDC_RGADW_RGWR), 1000, 10000);
473 }
474 
475 static int jz4725b_codec_reg_read(void *context, unsigned int reg,
476 				  unsigned int *val)
477 {
478 	struct jz_icdc *icdc = context;
479 	unsigned int i;
480 	u32 tmp;
481 	int ret;
482 
483 	ret = jz4725b_codec_io_wait(icdc);
484 	if (ret)
485 		return ret;
486 
487 	tmp = readl(icdc->base + ICDC_RGADW_OFFSET);
488 	tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
489 	    | (reg << ICDC_RGADW_RGADDR_OFFSET);
490 	writel(tmp, icdc->base + ICDC_RGADW_OFFSET);
491 
492 	/* wait 6+ cycles */
493 	for (i = 0; i < 6; i++)
494 		*val = readl(icdc->base + ICDC_RGDATA_OFFSET) &
495 			ICDC_RGDATA_RGDOUT_MASK;
496 
497 	return 0;
498 }
499 
500 static int jz4725b_codec_reg_write(void *context, unsigned int reg,
501 				   unsigned int val)
502 {
503 	struct jz_icdc *icdc = context;
504 	int ret;
505 
506 	ret = jz4725b_codec_io_wait(icdc);
507 	if (ret)
508 		return ret;
509 
510 	writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val,
511 			icdc->base + ICDC_RGADW_OFFSET);
512 
513 	ret = jz4725b_codec_io_wait(icdc);
514 	if (ret)
515 		return ret;
516 
517 	return 0;
518 }
519 
520 static const u8 jz4725b_codec_reg_defaults[] = {
521 	0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51,
522 	0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
523 	0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34,
524 	0x07, 0x44, 0x1f, 0x00,
525 };
526 
527 static const struct regmap_config jz4725b_codec_regmap_config = {
528 	.reg_bits = 7,
529 	.val_bits = 8,
530 
531 	.max_register = JZ4725B_CODEC_REG_AGC5,
532 	.volatile_reg = jz4725b_codec_volatile,
533 	.readable_reg = jz4725b_codec_can_access_reg,
534 	.writeable_reg = jz4725b_codec_can_access_reg,
535 
536 	.reg_read = jz4725b_codec_reg_read,
537 	.reg_write = jz4725b_codec_reg_write,
538 
539 	.reg_defaults_raw = jz4725b_codec_reg_defaults,
540 	.num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults),
541 	.cache_type = REGCACHE_FLAT,
542 };
543 
544 static int jz4725b_codec_probe(struct platform_device *pdev)
545 {
546 	struct device *dev = &pdev->dev;
547 	struct jz_icdc *icdc;
548 	int ret;
549 
550 	icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL);
551 	if (!icdc)
552 		return -ENOMEM;
553 
554 	icdc->base = devm_platform_ioremap_resource(pdev, 0);
555 	if (IS_ERR(icdc->base))
556 		return PTR_ERR(icdc->base);
557 
558 	icdc->regmap = devm_regmap_init(dev, NULL, icdc,
559 					&jz4725b_codec_regmap_config);
560 	if (IS_ERR(icdc->regmap))
561 		return PTR_ERR(icdc->regmap);
562 
563 	icdc->clk = devm_clk_get(&pdev->dev, "aic");
564 	if (IS_ERR(icdc->clk))
565 		return PTR_ERR(icdc->clk);
566 
567 	platform_set_drvdata(pdev, icdc);
568 
569 	ret = devm_snd_soc_register_component(dev, &jz4725b_codec,
570 					      &jz4725b_codec_dai, 1);
571 	if (ret)
572 		dev_err(dev, "Failed to register codec\n");
573 
574 	return ret;
575 }
576 
577 static const struct of_device_id jz4725b_codec_of_matches[] = {
578 	{ .compatible = "ingenic,jz4725b-codec", },
579 	{ }
580 };
581 MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches);
582 
583 static struct platform_driver jz4725b_codec_driver = {
584 	.probe = jz4725b_codec_probe,
585 	.driver = {
586 		.name = "jz4725b-codec",
587 		.of_match_table = jz4725b_codec_of_matches,
588 	},
589 };
590 module_platform_driver(jz4725b_codec_driver);
591 
592 MODULE_DESCRIPTION("JZ4725B SoC internal codec driver");
593 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
594 MODULE_LICENSE("GPL v2");
595