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