rk3328_codec.c 14 KB

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