1
2
3
4
5
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
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
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
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
139struct jz_icdc {
140 struct regmap *regmap;
141 void __iomem *base;
142 struct clk *clk;
143};
144
145static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0);
146static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600);
147
148static 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
172static const char * const jz4725b_codec_adc_src_texts[] = {
173 "Mic 1", "Mic 2", "Line In", "Mixer",
174};
175static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, };
176static 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);
182static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
183 SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum);
184
185static 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
190static 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_clear_bits(map, JZ4725B_CODEC_REG_IFR,
202 BIT(REG_IFR_RAMP_UP_DONE_OFFSET));
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_clear_bits(map, JZ4725B_CODEC_REG_IFR,
209 BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET));
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
219static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = {
220
221 SND_SOC_DAPM_DAC("DAC", "Playback",
222 JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1),
223
224
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
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
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
272static 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
298static 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_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
307 BIT(REG_PMR2_SB_SLEEP_OFFSET));
308 break;
309 case SND_SOC_BIAS_PREPARE:
310
311 regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
312 BIT(REG_PMR2_SB_OFFSET));
313 msleep(224);
314 break;
315 case SND_SOC_BIAS_STANDBY:
316 regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
317 BIT(REG_PMR2_SB_SLEEP_OFFSET));
318 break;
319 case SND_SOC_BIAS_OFF:
320 regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
321 BIT(REG_PMR2_SB_OFFSET));
322 break;
323 }
324
325 return 0;
326}
327
328static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
329{
330 struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
331 struct regmap *map = icdc->regmap;
332
333 clk_prepare_enable(icdc->clk);
334
335
336
337
338 regmap_write(map, JZ4725B_CODEC_REG_AICR,
339 0xf << REG_AICR_CONFIG1_OFFSET);
340 regmap_write(map, JZ4725B_CODEC_REG_CCR1,
341 0x0 << REG_CCR1_CONFIG4_OFFSET);
342
343 return 0;
344}
345
346static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
347{
348 struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
349
350 clk_disable_unprepare(icdc->clk);
351}
352
353static const struct snd_soc_component_driver jz4725b_codec = {
354 .probe = jz4725b_codec_dev_probe,
355 .remove = jz4725b_codec_dev_remove,
356 .set_bias_level = jz4725b_codec_set_bias_level,
357 .controls = jz4725b_codec_controls,
358 .num_controls = ARRAY_SIZE(jz4725b_codec_controls),
359 .dapm_widgets = jz4725b_codec_dapm_widgets,
360 .num_dapm_widgets = ARRAY_SIZE(jz4725b_codec_dapm_widgets),
361 .dapm_routes = jz4725b_codec_dapm_routes,
362 .num_dapm_routes = ARRAY_SIZE(jz4725b_codec_dapm_routes),
363 .suspend_bias_off = 1,
364 .use_pmdown_time = 1,
365};
366
367static const unsigned int jz4725b_codec_sample_rates[] = {
368 96000, 48000, 44100, 32000,
369 24000, 22050, 16000, 12000,
370 11025, 9600, 8000,
371};
372
373static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream,
374 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
375{
376 struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component);
377 unsigned int rate, bit_width;
378
379 switch (params_format(params)) {
380 case SNDRV_PCM_FORMAT_S16_LE:
381 bit_width = 0;
382 break;
383 case SNDRV_PCM_FORMAT_S18_3LE:
384 bit_width = 1;
385 break;
386 case SNDRV_PCM_FORMAT_S20_3LE:
387 bit_width = 2;
388 break;
389 case SNDRV_PCM_FORMAT_S24_3LE:
390 bit_width = 3;
391 break;
392 default:
393 return -EINVAL;
394 }
395
396 for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) {
397 if (jz4725b_codec_sample_rates[rate] == params_rate(params))
398 break;
399 }
400
401 if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates))
402 return -EINVAL;
403
404 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
405 regmap_update_bits(icdc->regmap,
406 JZ4725B_CODEC_REG_CR2,
407 REG_CR2_DAC_ADWL_MASK,
408 bit_width << REG_CR2_DAC_ADWL_OFFSET);
409
410 regmap_update_bits(icdc->regmap,
411 JZ4725B_CODEC_REG_CCR2,
412 REG_CCR2_DFREQ_MASK,
413 rate << REG_CCR2_DFREQ_OFFSET);
414 } else {
415 regmap_update_bits(icdc->regmap,
416 JZ4725B_CODEC_REG_CR2,
417 REG_CR2_ADC_ADWL_MASK,
418 bit_width << REG_CR2_ADC_ADWL_OFFSET);
419
420 regmap_update_bits(icdc->regmap,
421 JZ4725B_CODEC_REG_CCR2,
422 REG_CCR2_AFREQ_MASK,
423 rate << REG_CCR2_AFREQ_OFFSET);
424 }
425
426 return 0;
427}
428
429static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = {
430 .hw_params = jz4725b_codec_hw_params,
431};
432
433#define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
434 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE)
435
436static struct snd_soc_dai_driver jz4725b_codec_dai = {
437 .name = "jz4725b-hifi",
438 .playback = {
439 .stream_name = "Playback",
440 .channels_min = 2,
441 .channels_max = 2,
442 .rates = SNDRV_PCM_RATE_8000_96000,
443 .formats = JZ_ICDC_FORMATS,
444 },
445 .capture = {
446 .stream_name = "Capture",
447 .channels_min = 2,
448 .channels_max = 2,
449 .rates = SNDRV_PCM_RATE_8000_96000,
450 .formats = JZ_ICDC_FORMATS,
451 },
452 .ops = &jz4725b_codec_dai_ops,
453};
454
455static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg)
456{
457 return reg == JZ4725B_CODEC_REG_IFR;
458}
459
460static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg)
461{
462 return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2);
463}
464
465static int jz4725b_codec_io_wait(struct jz_icdc *icdc)
466{
467 u32 reg;
468
469 return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg,
470 !(reg & ICDC_RGADW_RGWR), 1000, 10000);
471}
472
473static int jz4725b_codec_reg_read(void *context, unsigned int reg,
474 unsigned int *val)
475{
476 struct jz_icdc *icdc = context;
477 unsigned int i;
478 u32 tmp;
479 int ret;
480
481 ret = jz4725b_codec_io_wait(icdc);
482 if (ret)
483 return ret;
484
485 tmp = readl(icdc->base + ICDC_RGADW_OFFSET);
486 tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
487 | (reg << ICDC_RGADW_RGADDR_OFFSET);
488 writel(tmp, icdc->base + ICDC_RGADW_OFFSET);
489
490
491 for (i = 0; i < 6; i++)
492 *val = readl(icdc->base + ICDC_RGDATA_OFFSET) &
493 ICDC_RGDATA_RGDOUT_MASK;
494
495 return 0;
496}
497
498static int jz4725b_codec_reg_write(void *context, unsigned int reg,
499 unsigned int val)
500{
501 struct jz_icdc *icdc = context;
502 int ret;
503
504 ret = jz4725b_codec_io_wait(icdc);
505 if (ret)
506 return ret;
507
508 writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val,
509 icdc->base + ICDC_RGADW_OFFSET);
510
511 ret = jz4725b_codec_io_wait(icdc);
512 if (ret)
513 return ret;
514
515 return 0;
516}
517
518static const u8 jz4725b_codec_reg_defaults[] = {
519 0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51,
520 0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
521 0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34,
522 0x07, 0x44, 0x1f, 0x00,
523};
524
525static const struct regmap_config jz4725b_codec_regmap_config = {
526 .reg_bits = 7,
527 .val_bits = 8,
528
529 .max_register = JZ4725B_CODEC_REG_AGC5,
530 .volatile_reg = jz4725b_codec_volatile,
531 .readable_reg = jz4725b_codec_can_access_reg,
532 .writeable_reg = jz4725b_codec_can_access_reg,
533
534 .reg_read = jz4725b_codec_reg_read,
535 .reg_write = jz4725b_codec_reg_write,
536
537 .reg_defaults_raw = jz4725b_codec_reg_defaults,
538 .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults),
539 .cache_type = REGCACHE_FLAT,
540};
541
542static int jz4725b_codec_probe(struct platform_device *pdev)
543{
544 struct device *dev = &pdev->dev;
545 struct jz_icdc *icdc;
546 int ret;
547
548 icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL);
549 if (!icdc)
550 return -ENOMEM;
551
552 icdc->base = devm_platform_ioremap_resource(pdev, 0);
553 if (IS_ERR(icdc->base))
554 return PTR_ERR(icdc->base);
555
556 icdc->regmap = devm_regmap_init(dev, NULL, icdc,
557 &jz4725b_codec_regmap_config);
558 if (IS_ERR(icdc->regmap))
559 return PTR_ERR(icdc->regmap);
560
561 icdc->clk = devm_clk_get(&pdev->dev, "aic");
562 if (IS_ERR(icdc->clk))
563 return PTR_ERR(icdc->clk);
564
565 platform_set_drvdata(pdev, icdc);
566
567 ret = devm_snd_soc_register_component(dev, &jz4725b_codec,
568 &jz4725b_codec_dai, 1);
569 if (ret)
570 dev_err(dev, "Failed to register codec\n");
571
572 return ret;
573}
574
575static const struct of_device_id jz4725b_codec_of_matches[] = {
576 { .compatible = "ingenic,jz4725b-codec", },
577 { }
578};
579MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches);
580
581static struct platform_driver jz4725b_codec_driver = {
582 .probe = jz4725b_codec_probe,
583 .driver = {
584 .name = "jz4725b-codec",
585 .of_match_table = jz4725b_codec_of_matches,
586 },
587};
588module_platform_driver(jz4725b_codec_driver);
589
590MODULE_DESCRIPTION("JZ4725B SoC internal codec driver");
591MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
592MODULE_LICENSE("GPL v2");
593