Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // rk3328 ALSA SoC Audio driver
0004 //
0005 // Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
0006 
0007 #include <linux/clk.h>
0008 #include <linux/delay.h>
0009 #include <linux/device.h>
0010 #include <linux/gpio/consumer.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/pm_runtime.h>
0015 #include <linux/regmap.h>
0016 #include <linux/mfd/syscon.h>
0017 #include <sound/dmaengine_pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include "rk3328_codec.h"
0020 
0021 /*
0022  * volume setting
0023  * 0: -39dB
0024  * 26: 0dB
0025  * 31: 6dB
0026  * Step: 1.5dB
0027  */
0028 #define OUT_VOLUME  (0x18)
0029 #define RK3328_GRF_SOC_CON2 (0x0408)
0030 #define RK3328_GRF_SOC_CON10    (0x0428)
0031 #define INITIAL_FREQ    (11289600)
0032 
0033 struct rk3328_codec_priv {
0034     struct regmap *regmap;
0035     struct gpio_desc *mute;
0036     struct clk *mclk;
0037     struct clk *pclk;
0038     unsigned int sclk;
0039     int spk_depop_time; /* msec */
0040 };
0041 
0042 static const struct reg_default rk3328_codec_reg_defaults[] = {
0043     { CODEC_RESET, 0x03 },
0044     { DAC_INIT_CTRL1, 0x00 },
0045     { DAC_INIT_CTRL2, 0x50 },
0046     { DAC_INIT_CTRL3, 0x0e },
0047     { DAC_PRECHARGE_CTRL, 0x01 },
0048     { DAC_PWR_CTRL, 0x00 },
0049     { DAC_CLK_CTRL, 0x00 },
0050     { HPMIX_CTRL, 0x00 },
0051     { HPOUT_CTRL, 0x00 },
0052     { HPOUTL_GAIN_CTRL, 0x00 },
0053     { HPOUTR_GAIN_CTRL, 0x00 },
0054     { HPOUT_POP_CTRL, 0x11 },
0055 };
0056 
0057 static int rk3328_codec_reset(struct rk3328_codec_priv *rk3328)
0058 {
0059     regmap_write(rk3328->regmap, CODEC_RESET, 0x00);
0060     mdelay(10);
0061     regmap_write(rk3328->regmap, CODEC_RESET, 0x03);
0062 
0063     return 0;
0064 }
0065 
0066 static int rk3328_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0067 {
0068     struct rk3328_codec_priv *rk3328 =
0069         snd_soc_component_get_drvdata(dai->component);
0070     unsigned int val;
0071 
0072     switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
0073     case SND_SOC_DAIFMT_CBC_CFC:
0074         val = PIN_DIRECTION_IN | DAC_I2S_MODE_SLAVE;
0075         break;
0076     case SND_SOC_DAIFMT_CBP_CFP:
0077         val = PIN_DIRECTION_OUT | DAC_I2S_MODE_MASTER;
0078         break;
0079     default:
0080         return -EINVAL;
0081     }
0082 
0083     regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL1,
0084                PIN_DIRECTION_MASK | DAC_I2S_MODE_MASK, val);
0085 
0086     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0087     case SND_SOC_DAIFMT_DSP_A:
0088     case SND_SOC_DAIFMT_DSP_B:
0089         val = DAC_MODE_PCM;
0090         break;
0091     case SND_SOC_DAIFMT_I2S:
0092         val = DAC_MODE_I2S;
0093         break;
0094     case SND_SOC_DAIFMT_RIGHT_J:
0095         val = DAC_MODE_RJM;
0096         break;
0097     case SND_SOC_DAIFMT_LEFT_J:
0098         val = DAC_MODE_LJM;
0099         break;
0100     default:
0101         return -EINVAL;
0102     }
0103 
0104     regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2,
0105                DAC_MODE_MASK, val);
0106 
0107     return 0;
0108 }
0109 
0110 static int rk3328_mute_stream(struct snd_soc_dai *dai, int mute, int direction)
0111 {
0112     struct rk3328_codec_priv *rk3328 =
0113         snd_soc_component_get_drvdata(dai->component);
0114     unsigned int val;
0115 
0116     if (mute)
0117         val = HPOUTL_MUTE | HPOUTR_MUTE;
0118     else
0119         val = HPOUTL_UNMUTE | HPOUTR_UNMUTE;
0120 
0121     regmap_update_bits(rk3328->regmap, HPOUT_CTRL,
0122                HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK, val);
0123 
0124     return 0;
0125 }
0126 
0127 static int rk3328_codec_power_on(struct rk3328_codec_priv *rk3328, int wait_ms)
0128 {
0129     regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
0130                DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_PRECHARGE);
0131     mdelay(10);
0132     regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
0133                DAC_CHARGE_CURRENT_ALL_MASK,
0134                DAC_CHARGE_CURRENT_ALL_ON);
0135     mdelay(wait_ms);
0136 
0137     return 0;
0138 }
0139 
0140 static int rk3328_codec_power_off(struct rk3328_codec_priv *rk3328, int wait_ms)
0141 {
0142     regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
0143                DAC_CHARGE_XCHARGE_MASK, DAC_CHARGE_DISCHARGE);
0144     mdelay(10);
0145     regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
0146                DAC_CHARGE_CURRENT_ALL_MASK,
0147                DAC_CHARGE_CURRENT_ALL_ON);
0148     mdelay(wait_ms);
0149 
0150     return 0;
0151 }
0152 
0153 static const struct rk3328_reg_msk_val playback_open_list[] = {
0154     { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_ON },
0155     { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
0156       DACL_PATH_REFV_ON | DACR_PATH_REFV_ON },
0157     { DAC_PWR_CTRL, HPOUTL_ZERO_CROSSING_MASK | HPOUTR_ZERO_CROSSING_MASK,
0158       HPOUTL_ZERO_CROSSING_ON | HPOUTR_ZERO_CROSSING_ON },
0159     { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
0160       HPOUTR_POP_WORK | HPOUTL_POP_WORK },
0161     { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_EN | HPMIXR_EN },
0162     { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
0163       HPMIXL_INIT_EN | HPMIXR_INIT_EN },
0164     { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_EN | HPOUTR_EN },
0165     { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
0166       HPOUTL_INIT_EN | HPOUTR_INIT_EN },
0167     { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
0168       DACL_REFV_ON | DACR_REFV_ON },
0169     { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
0170       DACL_CLK_ON | DACR_CLK_ON },
0171     { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_ON | DACR_ON },
0172     { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
0173       DACL_INIT_ON | DACR_INIT_ON },
0174     { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
0175       DACL_SELECT | DACR_SELECT },
0176     { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
0177       HPMIXL_INIT2_EN | HPMIXR_INIT2_EN },
0178     { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
0179       HPOUTL_UNMUTE | HPOUTR_UNMUTE },
0180 };
0181 
0182 static int rk3328_codec_open_playback(struct rk3328_codec_priv *rk3328)
0183 {
0184     int i;
0185 
0186     regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
0187                DAC_CHARGE_CURRENT_ALL_MASK,
0188                DAC_CHARGE_CURRENT_I);
0189 
0190     for (i = 0; i < ARRAY_SIZE(playback_open_list); i++) {
0191         regmap_update_bits(rk3328->regmap,
0192                    playback_open_list[i].reg,
0193                    playback_open_list[i].msk,
0194                    playback_open_list[i].val);
0195         mdelay(1);
0196     }
0197 
0198     msleep(rk3328->spk_depop_time);
0199     gpiod_set_value(rk3328->mute, 0);
0200 
0201     regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
0202                HPOUTL_GAIN_MASK, OUT_VOLUME);
0203     regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,
0204                HPOUTR_GAIN_MASK, OUT_VOLUME);
0205 
0206     return 0;
0207 }
0208 
0209 static const struct rk3328_reg_msk_val playback_close_list[] = {
0210     { HPMIX_CTRL, HPMIXL_INIT2_MASK | HPMIXR_INIT2_MASK,
0211       HPMIXL_INIT2_DIS | HPMIXR_INIT2_DIS },
0212     { DAC_SELECT, DACL_SELECT_MASK | DACR_SELECT_MASK,
0213       DACL_UNSELECT | DACR_UNSELECT },
0214     { HPOUT_CTRL, HPOUTL_MUTE_MASK | HPOUTR_MUTE_MASK,
0215       HPOUTL_MUTE | HPOUTR_MUTE },
0216     { HPOUT_CTRL, HPOUTL_INIT_MASK | HPOUTR_INIT_MASK,
0217       HPOUTL_INIT_DIS | HPOUTR_INIT_DIS },
0218     { HPOUT_CTRL, HPOUTL_MASK | HPOUTR_MASK, HPOUTL_DIS | HPOUTR_DIS },
0219     { HPMIX_CTRL, HPMIXL_MASK | HPMIXR_MASK, HPMIXL_DIS | HPMIXR_DIS },
0220     { DAC_CLK_CTRL, DACL_MASK | DACR_MASK, DACL_OFF | DACR_OFF },
0221     { DAC_CLK_CTRL, DACL_CLK_MASK | DACR_CLK_MASK,
0222       DACL_CLK_OFF | DACR_CLK_OFF },
0223     { DAC_CLK_CTRL, DACL_REFV_MASK | DACR_REFV_MASK,
0224       DACL_REFV_OFF | DACR_REFV_OFF },
0225     { HPOUT_POP_CTRL, HPOUTR_POP_MASK | HPOUTL_POP_MASK,
0226       HPOUTR_POP_XCHARGE | HPOUTL_POP_XCHARGE },
0227     { DAC_PWR_CTRL, DACL_PATH_REFV_MASK | DACR_PATH_REFV_MASK,
0228       DACL_PATH_REFV_OFF | DACR_PATH_REFV_OFF },
0229     { DAC_PWR_CTRL, DAC_PWR_MASK, DAC_PWR_OFF },
0230     { HPMIX_CTRL, HPMIXL_INIT_MASK | HPMIXR_INIT_MASK,
0231       HPMIXL_INIT_DIS | HPMIXR_INIT_DIS },
0232     { DAC_CLK_CTRL, DACL_INIT_MASK | DACR_INIT_MASK,
0233       DACL_INIT_OFF | DACR_INIT_OFF },
0234 };
0235 
0236 static int rk3328_codec_close_playback(struct rk3328_codec_priv *rk3328)
0237 {
0238     size_t i;
0239 
0240     gpiod_set_value(rk3328->mute, 1);
0241 
0242     regmap_update_bits(rk3328->regmap, HPOUTL_GAIN_CTRL,
0243                HPOUTL_GAIN_MASK, 0);
0244     regmap_update_bits(rk3328->regmap, HPOUTR_GAIN_CTRL,
0245                HPOUTR_GAIN_MASK, 0);
0246 
0247     for (i = 0; i < ARRAY_SIZE(playback_close_list); i++) {
0248         regmap_update_bits(rk3328->regmap,
0249                    playback_close_list[i].reg,
0250                    playback_close_list[i].msk,
0251                    playback_close_list[i].val);
0252         mdelay(1);
0253     }
0254 
0255     /* Workaround for silence when changed Fs 48 -> 44.1kHz */
0256     rk3328_codec_reset(rk3328);
0257 
0258     regmap_update_bits(rk3328->regmap, DAC_PRECHARGE_CTRL,
0259                DAC_CHARGE_CURRENT_ALL_MASK,
0260                DAC_CHARGE_CURRENT_ALL_ON);
0261 
0262     return 0;
0263 }
0264 
0265 static int rk3328_hw_params(struct snd_pcm_substream *substream,
0266                 struct snd_pcm_hw_params *params,
0267                 struct snd_soc_dai *dai)
0268 {
0269     struct rk3328_codec_priv *rk3328 =
0270         snd_soc_component_get_drvdata(dai->component);
0271     unsigned int val = 0;
0272 
0273     switch (params_format(params)) {
0274     case SNDRV_PCM_FORMAT_S16_LE:
0275         val = DAC_VDL_16BITS;
0276         break;
0277     case SNDRV_PCM_FORMAT_S20_3LE:
0278         val = DAC_VDL_20BITS;
0279         break;
0280     case SNDRV_PCM_FORMAT_S24_LE:
0281         val = DAC_VDL_24BITS;
0282         break;
0283     case SNDRV_PCM_FORMAT_S32_LE:
0284         val = DAC_VDL_32BITS;
0285         break;
0286     default:
0287         return -EINVAL;
0288     }
0289     regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL2, DAC_VDL_MASK, val);
0290 
0291     val = DAC_WL_32BITS | DAC_RST_DIS;
0292     regmap_update_bits(rk3328->regmap, DAC_INIT_CTRL3,
0293                DAC_WL_MASK | DAC_RST_MASK, val);
0294 
0295     return 0;
0296 }
0297 
0298 static int rk3328_pcm_startup(struct snd_pcm_substream *substream,
0299                   struct snd_soc_dai *dai)
0300 {
0301     struct rk3328_codec_priv *rk3328 =
0302         snd_soc_component_get_drvdata(dai->component);
0303 
0304     return rk3328_codec_open_playback(rk3328);
0305 }
0306 
0307 static void rk3328_pcm_shutdown(struct snd_pcm_substream *substream,
0308                 struct snd_soc_dai *dai)
0309 {
0310     struct rk3328_codec_priv *rk3328 =
0311         snd_soc_component_get_drvdata(dai->component);
0312 
0313     rk3328_codec_close_playback(rk3328);
0314 }
0315 
0316 static const struct snd_soc_dai_ops rk3328_dai_ops = {
0317     .hw_params = rk3328_hw_params,
0318     .set_fmt = rk3328_set_dai_fmt,
0319     .mute_stream = rk3328_mute_stream,
0320     .startup = rk3328_pcm_startup,
0321     .shutdown = rk3328_pcm_shutdown,
0322     .no_capture_mute = 1,
0323 };
0324 
0325 static struct snd_soc_dai_driver rk3328_dai[] = {
0326     {
0327         .name = "rk3328-hifi",
0328         .id = RK3328_HIFI,
0329         .playback = {
0330             .stream_name = "HIFI Playback",
0331             .channels_min = 1,
0332             .channels_max = 2,
0333             .rates = SNDRV_PCM_RATE_8000_96000,
0334             .formats = (SNDRV_PCM_FMTBIT_S16_LE |
0335                     SNDRV_PCM_FMTBIT_S20_3LE |
0336                     SNDRV_PCM_FMTBIT_S24_LE |
0337                     SNDRV_PCM_FMTBIT_S32_LE),
0338         },
0339         .capture = {
0340             .stream_name = "HIFI Capture",
0341             .channels_min = 2,
0342             .channels_max = 8,
0343             .rates = SNDRV_PCM_RATE_8000_96000,
0344             .formats = (SNDRV_PCM_FMTBIT_S16_LE |
0345                     SNDRV_PCM_FMTBIT_S20_3LE |
0346                     SNDRV_PCM_FMTBIT_S24_LE |
0347                     SNDRV_PCM_FMTBIT_S32_LE),
0348         },
0349         .ops = &rk3328_dai_ops,
0350     },
0351 };
0352 
0353 static int rk3328_codec_probe(struct snd_soc_component *component)
0354 {
0355     struct rk3328_codec_priv *rk3328 =
0356         snd_soc_component_get_drvdata(component);
0357 
0358     rk3328_codec_reset(rk3328);
0359     rk3328_codec_power_on(rk3328, 0);
0360 
0361     return 0;
0362 }
0363 
0364 static void rk3328_codec_remove(struct snd_soc_component *component)
0365 {
0366     struct rk3328_codec_priv *rk3328 =
0367         snd_soc_component_get_drvdata(component);
0368 
0369     rk3328_codec_close_playback(rk3328);
0370     rk3328_codec_power_off(rk3328, 0);
0371 }
0372 
0373 static const struct snd_soc_component_driver soc_codec_rk3328 = {
0374     .probe = rk3328_codec_probe,
0375     .remove = rk3328_codec_remove,
0376 };
0377 
0378 static bool rk3328_codec_write_read_reg(struct device *dev, unsigned int reg)
0379 {
0380     switch (reg) {
0381     case CODEC_RESET:
0382     case DAC_INIT_CTRL1:
0383     case DAC_INIT_CTRL2:
0384     case DAC_INIT_CTRL3:
0385     case DAC_PRECHARGE_CTRL:
0386     case DAC_PWR_CTRL:
0387     case DAC_CLK_CTRL:
0388     case HPMIX_CTRL:
0389     case DAC_SELECT:
0390     case HPOUT_CTRL:
0391     case HPOUTL_GAIN_CTRL:
0392     case HPOUTR_GAIN_CTRL:
0393     case HPOUT_POP_CTRL:
0394         return true;
0395     default:
0396         return false;
0397     }
0398 }
0399 
0400 static bool rk3328_codec_volatile_reg(struct device *dev, unsigned int reg)
0401 {
0402     switch (reg) {
0403     case CODEC_RESET:
0404         return true;
0405     default:
0406         return false;
0407     }
0408 }
0409 
0410 static const struct regmap_config rk3328_codec_regmap_config = {
0411     .reg_bits = 32,
0412     .reg_stride = 4,
0413     .val_bits = 32,
0414     .max_register = HPOUT_POP_CTRL,
0415     .writeable_reg = rk3328_codec_write_read_reg,
0416     .readable_reg = rk3328_codec_write_read_reg,
0417     .volatile_reg = rk3328_codec_volatile_reg,
0418     .reg_defaults = rk3328_codec_reg_defaults,
0419     .num_reg_defaults = ARRAY_SIZE(rk3328_codec_reg_defaults),
0420     .cache_type = REGCACHE_FLAT,
0421 };
0422 
0423 static int rk3328_platform_probe(struct platform_device *pdev)
0424 {
0425     struct device_node *rk3328_np = pdev->dev.of_node;
0426     struct rk3328_codec_priv *rk3328;
0427     struct regmap *grf;
0428     void __iomem *base;
0429     int ret = 0;
0430 
0431     rk3328 = devm_kzalloc(&pdev->dev, sizeof(*rk3328), GFP_KERNEL);
0432     if (!rk3328)
0433         return -ENOMEM;
0434 
0435     grf = syscon_regmap_lookup_by_phandle(rk3328_np,
0436                           "rockchip,grf");
0437     if (IS_ERR(grf)) {
0438         dev_err(&pdev->dev, "missing 'rockchip,grf'\n");
0439         return PTR_ERR(grf);
0440     }
0441     /* enable i2s_acodec_en */
0442     regmap_write(grf, RK3328_GRF_SOC_CON2,
0443              (BIT(14) << 16 | BIT(14)));
0444 
0445     ret = of_property_read_u32(rk3328_np, "spk-depop-time-ms",
0446                    &rk3328->spk_depop_time);
0447     if (ret < 0) {
0448         dev_info(&pdev->dev, "spk_depop_time use default value.\n");
0449         rk3328->spk_depop_time = 200;
0450     }
0451 
0452     rk3328->mute = gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_HIGH);
0453     if (IS_ERR(rk3328->mute))
0454         return PTR_ERR(rk3328->mute);
0455     /*
0456      * Rock64 is the only supported platform to have widely relied on
0457      * this; if we do happen to come across an old DTB, just leave the
0458      * external mute forced off.
0459      */
0460     if (!rk3328->mute && of_machine_is_compatible("pine64,rock64")) {
0461         dev_warn(&pdev->dev, "assuming implicit control of GPIO_MUTE; update devicetree if possible\n");
0462         regmap_write(grf, RK3328_GRF_SOC_CON10, BIT(17) | BIT(1));
0463     }
0464 
0465     rk3328->mclk = devm_clk_get(&pdev->dev, "mclk");
0466     if (IS_ERR(rk3328->mclk))
0467         return PTR_ERR(rk3328->mclk);
0468 
0469     ret = clk_prepare_enable(rk3328->mclk);
0470     if (ret)
0471         return ret;
0472     clk_set_rate(rk3328->mclk, INITIAL_FREQ);
0473 
0474     rk3328->pclk = devm_clk_get(&pdev->dev, "pclk");
0475     if (IS_ERR(rk3328->pclk)) {
0476         dev_err(&pdev->dev, "can't get acodec pclk\n");
0477         ret = PTR_ERR(rk3328->pclk);
0478         goto err_unprepare_mclk;
0479     }
0480 
0481     ret = clk_prepare_enable(rk3328->pclk);
0482     if (ret < 0) {
0483         dev_err(&pdev->dev, "failed to enable acodec pclk\n");
0484         goto err_unprepare_mclk;
0485     }
0486 
0487     base = devm_platform_ioremap_resource(pdev, 0);
0488     if (IS_ERR(base)) {
0489         ret = PTR_ERR(base);
0490         goto err_unprepare_pclk;
0491     }
0492 
0493     rk3328->regmap = devm_regmap_init_mmio(&pdev->dev, base,
0494                            &rk3328_codec_regmap_config);
0495     if (IS_ERR(rk3328->regmap)) {
0496         ret = PTR_ERR(rk3328->regmap);
0497         goto err_unprepare_pclk;
0498     }
0499 
0500     platform_set_drvdata(pdev, rk3328);
0501 
0502     ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_rk3328,
0503                            rk3328_dai,
0504                            ARRAY_SIZE(rk3328_dai));
0505     if (ret)
0506         goto err_unprepare_pclk;
0507 
0508     return 0;
0509 
0510 err_unprepare_pclk:
0511     clk_disable_unprepare(rk3328->pclk);
0512 
0513 err_unprepare_mclk:
0514     clk_disable_unprepare(rk3328->mclk);
0515     return ret;
0516 }
0517 
0518 static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = {
0519         { .compatible = "rockchip,rk3328-codec", },
0520         {},
0521 };
0522 MODULE_DEVICE_TABLE(of, rk3328_codec_of_match);
0523 
0524 static struct platform_driver rk3328_codec_driver = {
0525     .driver = {
0526            .name = "rk3328-codec",
0527            .of_match_table = of_match_ptr(rk3328_codec_of_match),
0528     },
0529     .probe = rk3328_platform_probe,
0530 };
0531 module_platform_driver(rk3328_codec_driver);
0532 
0533 MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
0534 MODULE_DESCRIPTION("ASoC rk3328 codec driver");
0535 MODULE_LICENSE("GPL v2");