~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/rk3328_codec.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php