cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rk3328_codec.c (14442B)


      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
     33struct 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
     42static 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
     57static 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
     66static 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
    110static 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
    127static 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
    140static 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
    153static 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
    182static 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
    209static 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
    236static 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
    265static 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
    298static 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
    307static 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
    316static 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
    325static 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
    353static 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
    364static 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
    373static const struct snd_soc_component_driver soc_codec_rk3328 = {
    374	.probe = rk3328_codec_probe,
    375	.remove = rk3328_codec_remove,
    376};
    377
    378static 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
    400static 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
    410static 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
    423static 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		goto err_unprepare_mclk;
    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
    510err_unprepare_pclk:
    511	clk_disable_unprepare(rk3328->pclk);
    512
    513err_unprepare_mclk:
    514	clk_disable_unprepare(rk3328->mclk);
    515	return ret;
    516}
    517
    518static const struct of_device_id rk3328_codec_of_match[] __maybe_unused = {
    519		{ .compatible = "rockchip,rk3328-codec", },
    520		{},
    521};
    522MODULE_DEVICE_TABLE(of, rk3328_codec_of_match);
    523
    524static 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};
    531module_platform_driver(rk3328_codec_driver);
    532
    533MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
    534MODULE_DESCRIPTION("ASoC rk3328 codec driver");
    535MODULE_LICENSE("GPL v2");