xref: /linux/sound/soc/codecs/jz4725b.c (revision df496157)
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 #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 
160 struct jz_icdc {
161 	struct regmap *regmap;
162 	void __iomem *base;
163 	struct clk *clk;
164 };
165 
166 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_adc_tlv,     0, 150, 0);
167 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_dac_tlv, -2250, 150, 0);
168 static 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 
173 static 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 );
178 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(jz4725b_mic_boost_tlv, 0, 2000, 0);
179 
180 static const char * const jz4725b_mic_mode_texts[] = {
181 	"Single Ended", "Differential",
182 };
183 
184 static 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 
188 static 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 
240 static const char * const jz4725b_codec_adc_src_texts[] = {
241 	"Mic 1", "Mic 2", "Line In", "Mixer",
242 };
243 static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, };
244 static 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);
250 static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
251 	SOC_DAPM_ENUM("ADC Source Capture Route", jz4725b_codec_adc_src_enum);
252 
253 static 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 
jz4725b_out_stage_enable(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)262 static 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(w->dapm);
267 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(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, 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, 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 
291 static 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 
345 static 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 
jz4725b_codec_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)373 static 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(component);
377 	struct regmap *map = icdc->regmap;
378 
379 	switch (level) {
380 	case SND_SOC_BIAS_ON:
381 		regmap_clear_bits(map, 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, JZ4725B_CODEC_REG_PMR2,
387 				  BIT(REG_PMR2_SB_OFFSET));
388 		msleep(224);
389 		break;
390 	case SND_SOC_BIAS_STANDBY:
391 		regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
392 				BIT(REG_PMR2_SB_SLEEP_OFFSET));
393 		break;
394 	case SND_SOC_BIAS_OFF:
395 		regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
396 				BIT(REG_PMR2_SB_OFFSET));
397 		break;
398 	}
399 
400 	return 0;
401 }
402 
jz4725b_codec_dev_probe(struct snd_soc_component * component)403 static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
404 {
405 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
406 	struct regmap *map = icdc->regmap;
407 
408 	clk_prepare_enable(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, JZ4725B_CODEC_REG_AICR,
414 		     0xf << REG_AICR_CONFIG1_OFFSET);
415 	regmap_write(map, JZ4725B_CODEC_REG_CCR1,
416 		     0x0 << REG_CCR1_CONFIG4_OFFSET);
417 
418 	return 0;
419 }
420 
jz4725b_codec_dev_remove(struct snd_soc_component * component)421 static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
422 {
423 	struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
424 
425 	clk_disable_unprepare(icdc->clk);
426 }
427 
428 static 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 
442 static const unsigned int jz4725b_codec_sample_rates[] = {
443 	96000, 48000, 44100, 32000,
444 	24000, 22050, 16000, 12000,
445 	11025, 9600, 8000,
446 };
447 
jz4725b_codec_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)448 static 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(dai->component);
452 	unsigned int rate, bit_width;
453 
454 	switch (params_format(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(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(icdc->regmap,
481 				   JZ4725B_CODEC_REG_CR2,
482 				   REG_CR2_DAC_ADWL_MASK,
483 				   bit_width << REG_CR2_DAC_ADWL_OFFSET);
484 
485 		regmap_update_bits(icdc->regmap,
486 				   JZ4725B_CODEC_REG_CCR2,
487 				   REG_CCR2_DFREQ_MASK,
488 				   rate << REG_CCR2_DFREQ_OFFSET);
489 	} else {
490 		regmap_update_bits(icdc->regmap,
491 				   JZ4725B_CODEC_REG_CR2,
492 				   REG_CR2_ADC_ADWL_MASK,
493 				   bit_width << REG_CR2_ADC_ADWL_OFFSET);
494 
495 		regmap_update_bits(icdc->regmap,
496 				   JZ4725B_CODEC_REG_CCR2,
497 				   REG_CCR2_AFREQ_MASK,
498 				   rate << REG_CCR2_AFREQ_OFFSET);
499 	}
500 
501 	return 0;
502 }
503 
504 static 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 
511 static 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 
jz4725b_codec_volatile(struct device * dev,unsigned int reg)530 static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg)
531 {
532 	return reg == JZ4725B_CODEC_REG_IFR;
533 }
534 
jz4725b_codec_can_access_reg(struct device * dev,unsigned int reg)535 static 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 
jz4725b_codec_io_wait(struct jz_icdc * icdc)540 static 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 
jz4725b_codec_reg_read(void * context,unsigned int reg,unsigned int * val)548 static 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(icdc->base + ICDC_RGADW_OFFSET);
561 	tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
562 	    | (reg << ICDC_RGADW_RGADDR_OFFSET);
563 	writel(tmp, icdc->base + ICDC_RGADW_OFFSET);
564 
565 	/* wait 6+ cycles */
566 	for (i = 0; i < 6; i++)
567 		*val = readl(icdc->base + ICDC_RGDATA_OFFSET) &
568 			ICDC_RGDATA_RGDOUT_MASK;
569 
570 	return 0;
571 }
572 
jz4725b_codec_reg_write(void * context,unsigned int reg,unsigned int val)573 static 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 			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 
593 static 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 
600 static 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 
jz4725b_codec_probe(struct platform_device * pdev)617 static 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, sizeof(*icdc), GFP_KERNEL);
624 	if (!icdc)
625 		return -ENOMEM;
626 
627 	icdc->base = devm_platform_ioremap_resource(pdev, 0);
628 	if (IS_ERR(icdc->base))
629 		return PTR_ERR(icdc->base);
630 
631 	icdc->regmap = devm_regmap_init(dev, NULL, icdc,
632 					&jz4725b_codec_regmap_config);
633 	if (IS_ERR(icdc->regmap))
634 		return PTR_ERR(icdc->regmap);
635 
636 	icdc->clk = devm_clk_get(&pdev->dev, "aic");
637 	if (IS_ERR(icdc->clk))
638 		return PTR_ERR(icdc->clk);
639 
640 	platform_set_drvdata(pdev, icdc);
641 
642 	ret = devm_snd_soc_register_component(dev, &jz4725b_codec,
643 					      &jz4725b_codec_dai, 1);
644 	if (ret)
645 		dev_err(dev, "Failed to register codec\n");
646 
647 	return ret;
648 }
649 
650 static const struct of_device_id jz4725b_codec_of_matches[] = {
651 	{ .compatible = "ingenic,jz4725b-codec", },
652 	{ }
653 };
654 MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches);
655 
656 static 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 };
663 module_platform_driver(jz4725b_codec_driver);
664 
665 MODULE_DESCRIPTION("JZ4725B SoC internal codec driver");
666 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
667 MODULE_LICENSE("GPL v2");
668