xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/rk3228_codec.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // rk3228_codec.c  --  rk3228 ALSA Soc Audio driver
4 //
5 // Copyright (c) 2018, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
6 
7 #include <linux/module.h>
8 #include <linux/device.h>
9 #include <linux/delay.h>
10 #include <linux/of.h>
11 #include <linux/of_gpio.h>
12 #include <linux/clk.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_runtime.h>
15 #include <linux/regmap.h>
16 #include <sound/pcm_params.h>
17 #include <sound/dmaengine_pcm.h>
18 #include "rk3228_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 INITIAL_FREQ	(11289600)
29 
30 struct rk3228_codec_priv {
31 	struct regmap *regmap;
32 	struct clk *mclk;
33 	struct clk *pclk;
34 	struct clk *sclk;
35 	struct gpio_desc *spk_en_gpio;
36 	int spk_depop_time; /* msec */
37 };
38 
39 static const struct reg_default rk3228_codec_reg_defaults[] = {
40 	{ CODEC_RESET, 0x03 },
41 	{ DAC_INIT_CTRL1, 0x00 },
42 	{ DAC_INIT_CTRL2, 0x50 },
43 	{ DAC_INIT_CTRL3, 0x0e },
44 	{ DAC_PRECHARGE_CTRL, 0x01 },
45 	{ DAC_PWR_CTRL, 0x00 },
46 	{ DAC_CLK_CTRL, 0x00 },
47 	{ HPMIX_CTRL, 0x00 },
48 	{ HPOUT_CTRL, 0x00 },
49 	{ HPOUTL_GAIN_CTRL, 0x00 },
50 	{ HPOUTR_GAIN_CTRL, 0x00 },
51 	{ HPOUT_POP_CTRL, 0x11 },
52 };
53 
rk3228_codec_reset(struct snd_soc_component * component)54 static int rk3228_codec_reset(struct snd_soc_component *component)
55 {
56 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
57 
58 	regmap_write(rk3228->regmap, CODEC_RESET, 0);
59 	mdelay(10);
60 	regmap_write(rk3228->regmap, CODEC_RESET, 0x03);
61 
62 	return 0;
63 }
64 
rk3228_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)65 static int rk3228_set_dai_fmt(struct snd_soc_dai *dai,
66 			      unsigned int fmt)
67 {
68 	struct snd_soc_component *component = dai->component;
69 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
70 	unsigned int val = 0;
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(rk3228->regmap, DAC_INIT_CTRL1,
84 			   PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val);
85 
86 	val = 0;
87 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
88 	case SND_SOC_DAIFMT_DSP_A:
89 	case SND_SOC_DAIFMT_DSP_B:
90 		val |= DAC_MODE_PCM;
91 		break;
92 	case SND_SOC_DAIFMT_I2S:
93 		val |= DAC_MODE_I2S;
94 		break;
95 	case SND_SOC_DAIFMT_RIGHT_J:
96 		val |= DAC_MODE_RJM;
97 		break;
98 	case SND_SOC_DAIFMT_LEFT_J:
99 		val |= DAC_MODE_LJM;
100 		break;
101 	default:
102 		return -EINVAL;
103 	}
104 
105 	regmap_update_bits(rk3228->regmap, DAC_INIT_CTRL2,
106 			   DAC_MODE_MASK, val);
107 	return 0;
108 }
109 
rk3228_analog_output(struct rk3228_codec_priv * rk3228,int mute)110 static void rk3228_analog_output(struct rk3228_codec_priv *rk3228, int mute)
111 {
112 	if (rk3228->spk_en_gpio)
113 		gpiod_set_value(rk3228->spk_en_gpio, mute);
114 }
115 
rk3228_digital_mute(struct snd_soc_dai * dai,int mute,int stream)116 static int rk3228_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
117 {
118 	struct snd_soc_component *component = dai->component;
119 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
120 	unsigned int val = 0;
121 
122 	if (mute)
123 		val = HPOUTL_MUTE | HPOUTR_MUTE;
124 	else
125 		val = HPOUTL_UNMUTE | HPOUTR_UNMUTE;
126 
127 	regmap_update_bits(rk3228->regmap, HPOUT_CTRL,
128 			   HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val);
129 	return 0;
130 }
131 
rk3228_codec_power_on(struct snd_soc_component * component,int wait_ms)132 static int rk3228_codec_power_on(struct snd_soc_component *component, int wait_ms)
133 {
134 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
135 
136 	regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
137 			   DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE);
138 	mdelay(10);
139 	regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
140 			   DAC_CHARGE_CURRENT_ALL_MASK,
141 			   DAC_CHARGE_CURRENT_ALL_ON);
142 
143 	mdelay(wait_ms);
144 
145 	return 0;
146 }
147 
rk3228_codec_power_off(struct snd_soc_component * component,int wait_ms)148 static int rk3228_codec_power_off(struct snd_soc_component *component, int wait_ms)
149 {
150 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
151 
152 	regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
153 			   DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE);
154 	mdelay(10);
155 	regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
156 			   DAC_CHARGE_CURRENT_ALL_MASK,
157 			   DAC_CHARGE_CURRENT_ALL_ON);
158 
159 	mdelay(wait_ms);
160 
161 	return 0;
162 }
163 
164 static struct rk3228_reg_msk_val playback_open_list[] = {
165 	{ DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON },
166 	{ DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
167 	  DACL_PATH_REFV_ON | DACR_PATH_REFV_ON },
168 	{ DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON,
169 	  HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON },
170 	{ HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
171 	  HPOUTR_POP_WORK | HPOUTL_POP_WORK },
172 	{ HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN },
173 	{ HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
174 	  HPMIXL_INIT_EN | HPMIXR_INIT_EN },
175 	{ HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN },
176 	{ HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
177 	  HPOUTL_INIT_EN | HPOUTR_INIT_EN },
178 	{ DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
179 	  DACL_REFV_ON | DACR_REFV_ON },
180 	{ DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
181 	  DACL_CLK_ON | DACR_CLK_ON },
182 	{ DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON },
183 	{ DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
184 	  DACL_INIT_ON | DACR_INIT_ON },
185 	{ DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
186 	  DACL_SELECT | DACR_SELECT },
187 	{ HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
188 	  HPMIXL_INIT2_EN | HPMIXR_INIT2_EN },
189 	{ HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
190 	  HPOUTL_UNMUTE | HPOUTR_UNMUTE },
191 };
192 
193 #define PLAYBACK_OPEN_LIST_LEN ARRAY_SIZE(playback_open_list)
194 
rk3228_codec_open_playback(struct snd_soc_component * component)195 static int rk3228_codec_open_playback(struct snd_soc_component *component)
196 {
197 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
198 	int i = 0;
199 
200 	regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
201 			   DAC_CHARGE_CURRENT_ALL_MASK,
202 			   DAC_CHARGE_CURRENT_I);
203 
204 	for (i = 0; i < PLAYBACK_OPEN_LIST_LEN; i++) {
205 		regmap_update_bits(rk3228->regmap,
206 				   playback_open_list[i].reg,
207 				   playback_open_list[i].msk,
208 				   playback_open_list[i].val);
209 		mdelay(1);
210 	}
211 
212 	msleep(rk3228->spk_depop_time);
213 	rk3228_analog_output(rk3228, 1);
214 
215 	regmap_update_bits(rk3228->regmap, HPOUTL_GAIN_CTRL,
216 			   HPOUTL_GAIN_MASK, OUT_VOLUME);
217 	regmap_update_bits(rk3228->regmap, HPOUTR_GAIN_CTRL,
218 			   HPOUTR_GAIN_MASK, OUT_VOLUME);
219 	return 0;
220 }
221 
222 static struct rk3228_reg_msk_val playback_close_list[] = {
223 	{ HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
224 	  HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS },
225 	{ DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
226 	  DACL_DESELECT | DACR_DESELECT },
227 	{ HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
228 	  HPOUTL_MUTE | HPOUTR_MUTE },
229 	{ HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
230 	  HPOUTL_INIT_DIS | HPOUTR_INIT_DIS },
231 	{ HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS },
232 	{ HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS },
233 	{ DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF },
234 	{ DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
235 	  DACL_CLK_OFF | DACR_CLK_OFF },
236 	{ DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
237 	  DACL_REFV_OFF | DACR_REFV_OFF },
238 	{ HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
239 	  HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE },
240 	{ DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
241 	  DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF },
242 	{ DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF },
243 	{ HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
244 	  HPMIXL_INIT_DIS | HPMIXR_INIT_DIS },
245 	{ DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
246 	  DACL_INIT_OFF | DACR_INIT_OFF },
247 };
248 
249 #define PLAYBACK_CLOSE_LIST_LEN ARRAY_SIZE(playback_close_list)
250 
rk3228_codec_close_playback(struct snd_soc_component * component)251 static int rk3228_codec_close_playback(struct snd_soc_component *component)
252 {
253 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
254 	int i = 0;
255 
256 	rk3228_analog_output(rk3228, 0);
257 
258 	regmap_update_bits(rk3228->regmap, HPOUTL_GAIN_CTRL,
259 			   HPOUTL_GAIN_MASK, 0);
260 	regmap_update_bits(rk3228->regmap, HPOUTR_GAIN_CTRL,
261 			   HPOUTR_GAIN_MASK, 0);
262 
263 	for (i = 0; i < PLAYBACK_CLOSE_LIST_LEN; i++) {
264 		regmap_update_bits(rk3228->regmap,
265 				   playback_close_list[i].reg,
266 				   playback_close_list[i].msk,
267 				   playback_close_list[i].val);
268 		mdelay(1);
269 	}
270 
271 	regmap_update_bits(rk3228->regmap, DAC_PRECHARGE_CTRL,
272 			   DAC_CHARGE_CURRENT_ALL_MASK,
273 			   DAC_CHARGE_CURRENT_I);
274 	return 0;
275 }
276 
rk3228_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)277 static int rk3228_hw_params(struct snd_pcm_substream *substream,
278 			    struct snd_pcm_hw_params *params,
279 			    struct snd_soc_dai *dai)
280 {
281 	struct snd_soc_component *component = dai->component;
282 	struct rk3228_codec_priv *rk3228 = snd_soc_component_get_drvdata(component);
283 	unsigned int val = 0;
284 
285 	switch (params_format(params)) {
286 	case SNDRV_PCM_FORMAT_S16_LE:
287 		val |= DAC_VDL_16BITS;
288 		break;
289 	case SNDRV_PCM_FORMAT_S20_3LE:
290 		val |= DAC_VDL_20BITS;
291 		break;
292 	case SNDRV_PCM_FORMAT_S24_LE:
293 		val |= DAC_VDL_24BITS;
294 		break;
295 	case SNDRV_PCM_FORMAT_S32_LE:
296 		val |= DAC_VDL_32BITS;
297 		break;
298 	default:
299 		return -EINVAL;
300 	}
301 
302 	regmap_update_bits(rk3228->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val);
303 	val = DAC_WL_32BITS | DAC_RST_DIS;
304 	regmap_update_bits(rk3228->regmap, DAC_INIT_CTRL3,
305 			   DAC_WL_MASK | DAC_RST_MASK, val);
306 
307 	return 0;
308 }
309 
rk3228_pcm_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)310 static int rk3228_pcm_startup(struct snd_pcm_substream *substream,
311 			      struct snd_soc_dai *dai)
312 {
313 	struct snd_soc_component *component = dai->component;
314 
315 	return rk3228_codec_open_playback(component);
316 }
317 
rk3228_pcm_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)318 static void rk3228_pcm_shutdown(struct snd_pcm_substream *substream,
319 				struct snd_soc_dai *dai)
320 {
321 	struct snd_soc_component *component = dai->component;
322 
323 	rk3228_codec_close_playback(component);
324 }
325 
326 static struct snd_soc_dai_ops rk3228_dai_ops = {
327 	.hw_params = rk3228_hw_params,
328 	.set_fmt = rk3228_set_dai_fmt,
329 	.mute_stream = rk3228_digital_mute,
330 	.startup = rk3228_pcm_startup,
331 	.shutdown = rk3228_pcm_shutdown,
332 	.no_capture_mute = 1,
333 };
334 
335 static struct snd_soc_dai_driver rk3228_dai[] = {
336 	{
337 		.name = "rk3228-hifi",
338 		.id = RK3228_HIFI,
339 		.playback = {
340 			.stream_name = "HIFI Playback",
341 			.channels_min = 1,
342 			.channels_max = 2,
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 		.capture = {
350 			.stream_name = "HIFI Capture",
351 			.channels_min = 2,
352 			.channels_max = 8,
353 			.rates = SNDRV_PCM_RATE_8000_96000,
354 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |
355 				    SNDRV_PCM_FMTBIT_S20_3LE |
356 				    SNDRV_PCM_FMTBIT_S24_LE |
357 				    SNDRV_PCM_FMTBIT_S32_LE),
358 		},
359 		.ops = &rk3228_dai_ops,
360 	},
361 };
362 
rk3228_codec_probe(struct snd_soc_component * component)363 static int rk3228_codec_probe(struct snd_soc_component *component)
364 {
365 	rk3228_codec_reset(component);
366 	rk3228_codec_power_on(component, 0);
367 
368 	return 0;
369 }
370 
rk3228_codec_remove(struct snd_soc_component * component)371 static void rk3228_codec_remove(struct snd_soc_component *component)
372 {
373 	rk3228_codec_close_playback(component);
374 	rk3228_codec_power_off(component, 0);
375 }
376 
377 static struct snd_soc_component_driver soc_codec_dev_rk3228 = {
378 	.probe = rk3228_codec_probe,
379 	.remove = rk3228_codec_remove,
380 };
381 
rk3228_codec_write_read_reg(struct device * dev,unsigned int reg)382 static bool rk3228_codec_write_read_reg(struct device *dev, unsigned int reg)
383 {
384 	switch (reg) {
385 	case CODEC_RESET:
386 	case DAC_INIT_CTRL1:
387 	case DAC_INIT_CTRL2:
388 	case DAC_INIT_CTRL3:
389 	case DAC_PRECHARGE_CTRL:
390 	case DAC_PWR_CTRL:
391 	case DAC_CLK_CTRL:
392 	case HPMIX_CTRL:
393 	case DAC_SELECT:
394 	case HPOUT_CTRL:
395 	case HPOUTL_GAIN_CTRL:
396 	case HPOUTR_GAIN_CTRL:
397 	case HPOUT_POP_CTRL:
398 		return true;
399 	default:
400 		return false;
401 	}
402 }
403 
rk3228_codec_volatile_reg(struct device * dev,unsigned int reg)404 static bool rk3228_codec_volatile_reg(struct device *dev, unsigned int reg)
405 {
406 	switch (reg) {
407 	case CODEC_RESET:
408 		return true;
409 	default:
410 		return false;
411 	}
412 }
413 
414 static const struct regmap_config rk3228_codec_regmap_config = {
415 	.reg_bits = 32,
416 	.reg_stride = 4,
417 	.val_bits = 32,
418 	.max_register = HPOUT_POP_CTRL,
419 	.writeable_reg = rk3228_codec_write_read_reg,
420 	.readable_reg = rk3228_codec_write_read_reg,
421 	.volatile_reg = rk3228_codec_volatile_reg,
422 	.reg_defaults = rk3228_codec_reg_defaults,
423 	.num_reg_defaults = ARRAY_SIZE(rk3228_codec_reg_defaults),
424 	.cache_type = REGCACHE_FLAT,
425 };
426 
427 #ifdef CONFIG_OF
428 static const struct of_device_id rk3228codec_of_match[] = {
429 	{ .compatible = "rockchip,rk3228-codec", },
430 	{},
431 };
432 MODULE_DEVICE_TABLE(of, rk3228codec_of_match);
433 #endif
434 
rk3228_platform_probe(struct platform_device * pdev)435 static int rk3228_platform_probe(struct platform_device *pdev)
436 {
437 	struct device_node *rk3228_np = pdev->dev.of_node;
438 	struct rk3228_codec_priv *rk3228;
439 	struct resource *res;
440 	void __iomem *base;
441 	int ret = 0;
442 
443 	rk3228 = devm_kzalloc(&pdev->dev, sizeof(*rk3228), GFP_KERNEL);
444 	if (!rk3228)
445 		return -ENOMEM;
446 
447 	rk3228->mclk = devm_clk_get(&pdev->dev, "mclk");
448 	if (PTR_ERR(rk3228->mclk) == -EPROBE_DEFER)
449 		return -EPROBE_DEFER;
450 
451 	rk3228->pclk = devm_clk_get(&pdev->dev, "pclk");
452 	if (IS_ERR(rk3228->pclk))
453 		return PTR_ERR(rk3228->pclk);
454 
455 	rk3228->sclk = devm_clk_get(&pdev->dev, "sclk");
456 	if (IS_ERR(rk3228->sclk))
457 		return PTR_ERR(rk3228->sclk);
458 
459 	rk3228->spk_en_gpio = devm_gpiod_get_optional(&pdev->dev,
460 						      "spk-en",
461 						      GPIOD_OUT_LOW);
462 	if (IS_ERR(rk3228->spk_en_gpio))
463 		return PTR_ERR(rk3228->spk_en_gpio);
464 
465 	ret = of_property_read_u32(rk3228_np, "spk-depop-time-ms",
466 				   &rk3228->spk_depop_time);
467 	if (ret < 0) {
468 		dev_info(&pdev->dev, "spk_depop_time use default value.\n");
469 		rk3228->spk_depop_time = 100;
470 	}
471 
472 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
473 	base = devm_ioremap_resource(&pdev->dev, res);
474 	if (IS_ERR(base))
475 		return PTR_ERR(base);
476 
477 	ret = clk_prepare_enable(rk3228->mclk);
478 	if (ret)
479 		return ret;
480 
481 	ret = clk_prepare_enable(rk3228->pclk);
482 	if (ret < 0)
483 		goto err_pclk;
484 
485 	ret = clk_prepare_enable(rk3228->sclk);
486 	if (ret)
487 		goto err_sclk;
488 
489 	clk_set_rate(rk3228->sclk, INITIAL_FREQ);
490 
491 	rk3228->regmap = devm_regmap_init_mmio(&pdev->dev, base,
492 					       &rk3228_codec_regmap_config);
493 	if (IS_ERR(rk3228->regmap)) {
494 		ret = PTR_ERR(rk3228->regmap);
495 		goto err_clk;
496 	}
497 
498 	platform_set_drvdata(pdev, rk3228);
499 
500 	ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rk3228,
501 					      rk3228_dai, ARRAY_SIZE(rk3228_dai));
502 	if (!ret)
503 		return 0;
504 
505 err_clk:
506 	clk_disable_unprepare(rk3228->sclk);
507 err_sclk:
508 	clk_disable_unprepare(rk3228->pclk);
509 err_pclk:
510 	clk_disable_unprepare(rk3228->mclk);
511 
512 	return ret;
513 }
514 
rk3228_platform_remove(struct platform_device * pdev)515 static int rk3228_platform_remove(struct platform_device *pdev)
516 {
517 	struct rk3228_codec_priv *rk3228 = platform_get_drvdata(pdev);
518 
519 	if (!IS_ERR(rk3228->mclk))
520 		clk_disable_unprepare(rk3228->mclk);
521 
522 	if (!IS_ERR(rk3228->pclk))
523 		clk_disable_unprepare(rk3228->pclk);
524 
525 	if (!IS_ERR(rk3228->sclk))
526 		clk_disable_unprepare(rk3228->sclk);
527 
528 	return 0;
529 }
530 
531 static struct platform_driver rk3228_codec_driver = {
532 	.driver = {
533 		   .name = "rk3228-codec",
534 		   .of_match_table = of_match_ptr(rk3228codec_of_match),
535 	},
536 	.probe = rk3228_platform_probe,
537 	.remove = rk3228_platform_remove,
538 };
539 module_platform_driver(rk3228_codec_driver);
540 
541 MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
542 MODULE_DESCRIPTION("ASoC rk3228 codec driver");
543 MODULE_LICENSE("GPL v2");
544