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