xref: /openbmc/linux/sound/soc/codecs/rk3328_codec.c (revision 185c8f33)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // rk3328 ALSA SoC Audio driver
4 //
5 // Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
6 
7 #include <linux/clk.h>
8 #include <linux/delay.h>
9 #include <linux/device.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/platform_device.h>
14 #include <linux/regmap.h>
15 #include <linux/mfd/syscon.h>
16 #include <sound/dmaengine_pcm.h>
17 #include <sound/pcm_params.h>
18 #include "rk3328_codec.h"
19 
20 /*
21  * volume setting
22  * 0: -39dB
23  * 26: 0dB
24  * 31: 6dB
25  * Step: 1.5dB
26  */
27 #define OUT_VOLUME	(0x18)
28 #define RK3328_GRF_SOC_CON2	(0x0408)
29 #define RK3328_GRF_SOC_CON10	(0x0428)
30 #define INITIAL_FREQ	(11289600)
31 
32 struct rk3328_codec_priv {
33 	struct regmap *regmap;
34 	struct gpio_desc *mute;
35 	struct clk *mclk;
36 	struct clk *pclk;
37 	unsigned int sclk;
38 	int spk_depop_time; /* msec */
39 };
40 
41 static const struct reg_default rk3328_codec_reg_defaults[] = {
42 	{ CODEC_RESET, 0x03 },
43 	{ DAC_INIT_CTRL1, 0x00 },
44 	{ DAC_INIT_CTRL2, 0x50 },
45 	{ DAC_INIT_CTRL3, 0x0e },
46 	{ DAC_PRECHARGE_CTRL, 0x01 },
47 	{ DAC_PWR_CTRL, 0x00 },
48 	{ DAC_CLK_CTRL, 0x00 },
49 	{ HPMIX_CTRL, 0x00 },
50 	{ HPOUT_CTRL, 0x00 },
51 	{ HPOUTL_GAIN_CTRL, 0x00 },
52 	{ HPOUTR_GAIN_CTRL, 0x00 },
53 	{ HPOUT_POP_CTRL, 0x11 },
54 };
55 
56 static int rk3328_codec_reset(struct rk3328_codec_priv *rk3328)
57 {
58 	regmap_write(rk3328->regmap, CODEC_RESET, 0x00);
59 	mdelay(10);
60 	regmap_write(rk3328->regmap, CODEC_RESET, 0x03);
61 
62 	return 0;
63 }
64 
65 static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
66 {
67 	struct rk3328_codec_priv *rk3328 =
68 		snd_soc_component_get_drvdata(dai->component);
69 	unsigned int val;
70 
71 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
72 	case SND_SOC_DAIFMT_CBC_CFC:
73 		val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE;
74 		break;
75 	case SND_SOC_DAIFMT_CBP_CFP:
76 		val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER;
77 		break;
78 	default:
79 		return -EINVAL;
80 	}
81 
82 	regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL1,
83 			   PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val);
84 
85 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
86 	case SND_SOC_DAIFMT_DSP_A:
87 	case SND_SOC_DAIFMT_DSP_B:
88 		val = DAC_MODE_PCM;
89 		break;
90 	case SND_SOC_DAIFMT_I2S:
91 		val = DAC_MODE_I2S;
92 		break;
93 	case SND_SOC_DAIFMT_RIGHT_J:
94 		val = DAC_MODE_RJM;
95 		break;
96 	case SND_SOC_DAIFMT_LEFT_J:
97 		val = DAC_MODE_LJM;
98 		break;
99 	default:
100 		return -EINVAL;
101 	}
102 
103 	regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2,
104 			   DAC_MODE_MASK, val);
105 
106 	return 0;
107 }
108 
109 static int rk3328_mute_stream(struct snd_soc_dai *dai, int mute, int direction)
110 {
111 	struct rk3328_codec_priv *rk3328 =
112 		snd_soc_component_get_drvdata(dai->component);
113 	unsigned int val;
114 
115 	if (mute)
116 		val = HPOUTL_MUTE | HPOUTR_MUTE;
117 	else
118 		val = HPOUTL_UNMUTE | HPOUTR_UNMUTE;
119 
120 	regmap_update_bits(rk3328->regmap, HPOUT_CTRL,
121 			   HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val);
122 
123 	return 0;
124 }
125 
126 static int rk3328_codec_power_on(struct rk3328_codec_priv *rk3328, int wait_ms)
127 {
128 	regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
129 			   DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE);
130 	mdelay(10);
131 	regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
132 			   DAC_CHARGE_CURRENT_ALL_MASK,
133 			   DAC_CHARGE_CURRENT_ALL_ON);
134 	mdelay(wait_ms);
135 
136 	return 0;
137 }
138 
139 static int rk3328_codec_power_off(struct rk3328_codec_priv *rk3328, int wait_ms)
140 {
141 	regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
142 			   DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE);
143 	mdelay(10);
144 	regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
145 			   DAC_CHARGE_CURRENT_ALL_MASK,
146 			   DAC_CHARGE_CURRENT_ALL_ON);
147 	mdelay(wait_ms);
148 
149 	return 0;
150 }
151 
152 static const struct rk3328_reg_msk_val playback_open_list[] = {
153 	{ DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON },
154 	{ DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
155 	  DACL_PATH_REFV_ON | DACR_PATH_REFV_ON },
156 	{ DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_MASK | HPOUTR_ZERO_CROSSING_MASK,
157 	  HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON },
158 	{ HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
159 	  HPOUTR_POP_WORK | HPOUTL_POP_WORK },
160 	{ HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN },
161 	{ HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
162 	  HPMIXL_INIT_EN | HPMIXR_INIT_EN },
163 	{ HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN },
164 	{ HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
165 	  HPOUTL_INIT_EN | HPOUTR_INIT_EN },
166 	{ DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
167 	  DACL_REFV_ON | DACR_REFV_ON },
168 	{ DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
169 	  DACL_CLK_ON | DACR_CLK_ON },
170 	{ DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON },
171 	{ DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
172 	  DACL_INIT_ON | DACR_INIT_ON },
173 	{ DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
174 	  DACL_SELECT | DACR_SELECT },
175 	{ HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
176 	  HPMIXL_INIT2_EN | HPMIXR_INIT2_EN },
177 	{ HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
178 	  HPOUTL_UNMUTE | HPOUTR_UNMUTE },
179 };
180 
181 static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328)
182 {
183 	int i;
184 
185 	regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
186 			   DAC_CHARGE_CURRENT_ALL_MASK,
187 			   DAC_CHARGE_CURRENT_I);
188 
189 	for (i = 0; i < ARRAY_SIZE(playback_open_list); i++) {
190 		regmap_update_bits(rk3328->regmap,
191 				   playback_open_list[i].reg,
192 				   playback_open_list[i].msk,
193 				   playback_open_list[i].val);
194 		mdelay(1);
195 	}
196 
197 	msleep(rk3328->spk_depop_time);
198 	gpiod_set_value(rk3328->mute, 0);
199 
200 	regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
201 			   HPOUTL_GAIN_MASK, OUT_VOLUME);
202 	regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,
203 			   HPOUTR_GAIN_MASK, OUT_VOLUME);
204 
205 	return 0;
206 }
207 
208 static const struct rk3328_reg_msk_val playback_close_list[] = {
209 	{ HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
210 	  HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS },
211 	{ DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
212 	  DACL_UNSELECT | DACR_UNSELECT },
213 	{ HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
214 	  HPOUTL_MUTE | HPOUTR_MUTE },
215 	{ HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
216 	  HPOUTL_INIT_DIS | HPOUTR_INIT_DIS },
217 	{ HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS },
218 	{ HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS },
219 	{ DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF },
220 	{ DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
221 	  DACL_CLK_OFF | DACR_CLK_OFF },
222 	{ DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
223 	  DACL_REFV_OFF | DACR_REFV_OFF },
224 	{ HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
225 	  HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE },
226 	{ DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
227 	  DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF },
228 	{ DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF },
229 	{ HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
230 	  HPMIXL_INIT_DIS | HPMIXR_INIT_DIS },
231 	{ DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
232 	  DACL_INIT_OFF | DACR_INIT_OFF },
233 };
234 
235 static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328)
236 {
237 	size_t i;
238 
239 	gpiod_set_value(rk3328->mute, 1);
240 
241 	regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
242 			   HPOUTL_GAIN_MASK, 0);
243 	regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,
244 			   HPOUTR_GAIN_MASK, 0);
245 
246 	for (i = 0; i < ARRAY_SIZE(playback_close_list); i++) {
247 		regmap_update_bits(rk3328->regmap,
248 				   playback_close_list[i].reg,
249 				   playback_close_list[i].msk,
250 				   playback_close_list[i].val);
251 		mdelay(1);
252 	}
253 
254 	/* Workaround for silence when changed Fs 48 -> 44.1kHz */
255 	rk3328_codec_reset(rk3328);
256 
257 	regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
258 			   DAC_CHARGE_CURRENT_ALL_MASK,
259 			   DAC_CHARGE_CURRENT_ALL_ON);
260 
261 	return 0;
262 }
263 
264 static int rk3328_hw_params(struct snd_pcm_substream *substream,
265 			    struct snd_pcm_hw_params *params,
266 			    struct snd_soc_dai *dai)
267 {
268 	struct rk3328_codec_priv *rk3328 =
269 		snd_soc_component_get_drvdata(dai->component);
270 	unsigned int val = 0;
271 
272 	switch (params_format(params)) {
273 	case SNDRV_PCM_FORMAT_S16_LE:
274 		val = DAC_VDL_16BITS;
275 		break;
276 	case SNDRV_PCM_FORMAT_S20_3LE:
277 		val = DAC_VDL_20BITS;
278 		break;
279 	case SNDRV_PCM_FORMAT_S24_LE:
280 		val = DAC_VDL_24BITS;
281 		break;
282 	case SNDRV_PCM_FORMAT_S32_LE:
283 		val = DAC_VDL_32BITS;
284 		break;
285 	default:
286 		return -EINVAL;
287 	}
288 	regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val);
289 
290 	val = DAC_WL_32BITS | DAC_RST_DIS;
291 	regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL3,
292 			   DAC_WL_MASK | DAC_RST_MASK, val);
293 
294 	return 0;
295 }
296 
297 static int rk3328_pcm_startup(struct snd_pcm_substream *substream,
298 			      struct snd_soc_dai *dai)
299 {
300 	struct rk3328_codec_priv *rk3328 =
301 		snd_soc_component_get_drvdata(dai->component);
302 
303 	return rk3328_codec_open_playback(rk3328);
304 }
305 
306 static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream,
307 				struct snd_soc_dai *dai)
308 {
309 	struct rk3328_codec_priv *rk3328 =
310 		snd_soc_component_get_drvdata(dai->component);
311 
312 	rk3328_codec_close_playback(rk3328);
313 }
314 
315 static const struct snd_soc_dai_ops rk3328_dai_ops = {
316 	.hw_params = rk3328_hw_params,
317 	.set_fmt = rk3328_set_dai_fmt,
318 	.mute_stream = rk3328_mute_stream,
319 	.startup = rk3328_pcm_startup,
320 	.shutdown = rk3328_pcm_shutdown,
321 	.no_capture_mute = 1,
322 };
323 
324 static struct snd_soc_dai_driver rk3328_dai[] = {
325 	{
326 		.name = "rk3328-hifi",
327 		.id = RK3328_HIFI,
328 		.playback = {
329 			.stream_name = "HIFI Playback",
330 			.channels_min = 1,
331 			.channels_max = 2,
332 			.rates = SNDRV_PCM_RATE_8000_96000,
333 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
334 				    SNDRV_PCM_FMTBIT_S20_3LE |
335 				    SNDRV_PCM_FMTBIT_S24_LE |
336 				    SNDRV_PCM_FMTBIT_S32_LE),
337 		},
338 		.capture = {
339 			.stream_name = "HIFI Capture",
340 			.channels_min = 2,
341 			.channels_max = 8,
342 			.rates = SNDRV_PCM_RATE_8000_96000,
343 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
344 				    SNDRV_PCM_FMTBIT_S20_3LE |
345 				    SNDRV_PCM_FMTBIT_S24_LE |
346 				    SNDRV_PCM_FMTBIT_S32_LE),
347 		},
348 		.ops = &rk3328_dai_ops,
349 	},
350 };
351 
352 static int rk3328_codec_probe(struct snd_soc_component *component)
353 {
354 	struct rk3328_codec_priv *rk3328 =
355 		snd_soc_component_get_drvdata(component);
356 
357 	rk3328_codec_reset(rk3328);
358 	rk3328_codec_power_on(rk3328, 0);
359 
360 	return 0;
361 }
362 
363 static void rk3328_codec_remove(struct snd_soc_component *component)
364 {
365 	struct rk3328_codec_priv *rk3328 =
366 		snd_soc_component_get_drvdata(component);
367 
368 	rk3328_codec_close_playback(rk3328);
369 	rk3328_codec_power_off(rk3328, 0);
370 }
371 
372 static const struct snd_soc_component_driver soc_codec_rk3328 = {
373 	.probe = rk3328_codec_probe,
374 	.remove = rk3328_codec_remove,
375 };
376 
377 static bool rk3328_codec_write_read_reg(struct device *dev, unsigned int reg)
378 {
379 	switch (reg) {
380 	case CODEC_RESET:
381 	case DAC_INIT_CTRL1:
382 	case DAC_INIT_CTRL2:
383 	case DAC_INIT_CTRL3:
384 	case DAC_PRECHARGE_CTRL:
385 	case DAC_PWR_CTRL:
386 	case DAC_CLK_CTRL:
387 	case HPMIX_CTRL:
388 	case DAC_SELECT:
389 	case HPOUT_CTRL:
390 	case HPOUTL_GAIN_CTRL:
391 	case HPOUTR_GAIN_CTRL:
392 	case HPOUT_POP_CTRL:
393 		return true;
394 	default:
395 		return false;
396 	}
397 }
398 
399 static bool rk3328_codec_volatile_reg(struct device *dev, unsigned int reg)
400 {
401 	switch (reg) {
402 	case CODEC_RESET:
403 		return true;
404 	default:
405 		return false;
406 	}
407 }
408 
409 static const struct regmap_config rk3328_codec_regmap_config = {
410 	.reg_bits = 32,
411 	.reg_stride = 4,
412 	.val_bits = 32,
413 	.max_register = HPOUT_POP_CTRL,
414 	.writeable_reg = rk3328_codec_write_read_reg,
415 	.readable_reg = rk3328_codec_write_read_reg,
416 	.volatile_reg = rk3328_codec_volatile_reg,
417 	.reg_defaults = rk3328_codec_reg_defaults,
418 	.num_reg_defaults = ARRAY_SIZE(rk3328_codec_reg_defaults),
419 	.cache_type = REGCACHE_FLAT,
420 };
421 
422 static int rk3328_platform_probe(struct platform_device *pdev)
423 {
424 	struct device_node *rk3328_np = pdev->dev.of_node;
425 	struct rk3328_codec_priv *rk3328;
426 	struct regmap *grf;
427 	void __iomem *base;
428 	int ret = 0;
429 
430 	rk3328 = devm_kzalloc(&pdev->dev, sizeof(*rk3328), GFP_KERNEL);
431 	if (!rk3328)
432 		return -ENOMEM;
433 
434 	grf = syscon_regmap_lookup_by_phandle(rk3328_np,
435 					      "rockchip,grf");
436 	if (IS_ERR(grf)) {
437 		dev_err(&pdev->dev, "missing 'rockchip,grf'\n");
438 		return PTR_ERR(grf);
439 	}
440 	/* enable i2s_acodec_en */
441 	regmap_write(grf, RK3328_GRF_SOC_CON2,
442 		     (BIT(14) << 16 | BIT(14)));
443 
444 	ret = of_property_read_u32(rk3328_np, "spk-depop-time-ms",
445 				   &rk3328->spk_depop_time);
446 	if (ret < 0) {
447 		dev_info(&pdev->dev, "spk_depop_time use default value.\n");
448 		rk3328->spk_depop_time = 200;
449 	}
450 
451 	rk3328->mute = gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_HIGH);
452 	if (IS_ERR(rk3328->mute))
453 		return PTR_ERR(rk3328->mute);
454 	/*
455 	 * Rock64 is the only supported platform to have widely relied on
456 	 * this; if we do happen to come across an old DTB, just leave the
457 	 * external mute forced off.
458 	 */
459 	if (!rk3328->mute && of_machine_is_compatible("pine64,rock64")) {
460 		dev_warn(&pdev->dev, "assuming implicit control of GPIO_MUTE; update devicetree if possible\n");
461 		regmap_write(grf, RK3328_GRF_SOC_CON10, BIT(17) | BIT(1));
462 	}
463 
464 	rk3328->mclk = devm_clk_get(&pdev->dev, "mclk");
465 	if (IS_ERR(rk3328->mclk))
466 		return PTR_ERR(rk3328->mclk);
467 
468 	ret = clk_prepare_enable(rk3328->mclk);
469 	if (ret)
470 		return ret;
471 	clk_set_rate(rk3328->mclk, INITIAL_FREQ);
472 
473 	rk3328->pclk = devm_clk_get(&pdev->dev, "pclk");
474 	if (IS_ERR(rk3328->pclk)) {
475 		dev_err(&pdev->dev, "can't get acodec pclk\n");
476 		ret = PTR_ERR(rk3328->pclk);
477 		goto err_unprepare_mclk;
478 	}
479 
480 	ret = clk_prepare_enable(rk3328->pclk);
481 	if (ret < 0) {
482 		dev_err(&pdev->dev, "failed to enable acodec pclk\n");
483 		goto err_unprepare_mclk;
484 	}
485 
486 	base = devm_platform_ioremap_resource(pdev, 0);
487 	if (IS_ERR(base)) {
488 		ret = PTR_ERR(base);
489 		goto err_unprepare_pclk;
490 	}
491 
492 	rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base,
493 					       &rk3328_codec_regmap_config);
494 	if (IS_ERR(rk3328->regmap)) {
495 		ret = PTR_ERR(rk3328->regmap);
496 		goto err_unprepare_pclk;
497 	}
498 
499 	platform_set_drvdata(pdev, rk3328);
500 
501 	ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328,
502 					       rk3328_dai,
503 					       ARRAY_SIZE(rk3328_dai));
504 	if (ret)
505 		goto err_unprepare_pclk;
506 
507 	return 0;
508 
509 err_unprepare_pclk:
510 	clk_disable_unprepare(rk3328->pclk);
511 
512 err_unprepare_mclk:
513 	clk_disable_unprepare(rk3328->mclk);
514 	return ret;
515 }
516 
517 static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = {
518 		{ .compatible = "rockchip,rk3328-codec", },
519 		{},
520 };
521 MODULE_DEVICE_TABLE(of, rk3328_codec_of_match);
522 
523 static struct platform_driver rk3328_codec_driver = {
524 	.driver = {
525 		   .name = "rk3328-codec",
526 		   .of_match_table = of_match_ptr(rk3328_codec_of_match),
527 	},
528 	.probe = rk3328_platform_probe,
529 };
530 module_platform_driver(rk3328_codec_driver);
531 
532 MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
533 MODULE_DESCRIPTION("ASoC rk3328 codec driver");
534 MODULE_LICENSE("GPL v2");
535