sun8i-codec.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*
  2. * This driver supports the digital controls for the internal codec
  3. * found in Allwinner's A33 SoCs.
  4. *
  5. * (C) Copyright 2010-2016
  6. * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
  7. * huangxin <huangxin@Reuuimllatech.com>
  8. * Mylène Josserand <mylene.josserand@free-electrons.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. */
  20. #include <linux/module.h>
  21. #include <linux/delay.h>
  22. #include <linux/clk.h>
  23. #include <linux/io.h>
  24. #include <linux/pm_runtime.h>
  25. #include <linux/regmap.h>
  26. #include <sound/pcm_params.h>
  27. #include <sound/soc.h>
  28. #include <sound/soc-dapm.h>
  29. #define SUN8I_SYSCLK_CTL 0x00c
  30. #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11
  31. #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL 9
  32. #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC 8
  33. #define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3
  34. #define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0
  35. #define SUN8I_MOD_CLK_ENA 0x010
  36. #define SUN8I_MOD_CLK_ENA_AIF1 15
  37. #define SUN8I_MOD_CLK_ENA_ADC 3
  38. #define SUN8I_MOD_CLK_ENA_DAC 2
  39. #define SUN8I_MOD_RST_CTL 0x014
  40. #define SUN8I_MOD_RST_CTL_AIF1 15
  41. #define SUN8I_MOD_RST_CTL_ADC 3
  42. #define SUN8I_MOD_RST_CTL_DAC 2
  43. #define SUN8I_SYS_SR_CTRL 0x018
  44. #define SUN8I_SYS_SR_CTRL_AIF1_FS 12
  45. #define SUN8I_SYS_SR_CTRL_AIF2_FS 8
  46. #define SUN8I_AIF1CLK_CTRL 0x040
  47. #define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD 15
  48. #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV 14
  49. #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13
  50. #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9
  51. #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6
  52. #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6)
  53. #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4
  54. #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4)
  55. #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2
  56. #define SUN8I_AIF1_ADCDAT_CTRL 0x044
  57. #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA 15
  58. #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA 14
  59. #define SUN8I_AIF1_DACDAT_CTRL 0x048
  60. #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15
  61. #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14
  62. #define SUN8I_AIF1_MXR_SRC 0x04c
  63. #define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L 15
  64. #define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL 14
  65. #define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL 13
  66. #define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR 12
  67. #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11
  68. #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10
  69. #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9
  70. #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8
  71. #define SUN8I_ADC_DIG_CTRL 0x100
  72. #define SUN8I_ADC_DIG_CTRL_ENDA 15
  73. #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2
  74. #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1
  75. #define SUN8I_DAC_DIG_CTRL 0x120
  76. #define SUN8I_DAC_DIG_CTRL_ENDA 15
  77. #define SUN8I_DAC_MXR_SRC 0x130
  78. #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
  79. #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
  80. #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
  81. #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12
  82. #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
  83. #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
  84. #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
  85. #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8
  86. #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12)
  87. #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8)
  88. #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2)
  89. #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
  90. #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
  91. #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
  92. struct sun8i_codec {
  93. struct device *dev;
  94. struct regmap *regmap;
  95. struct clk *clk_module;
  96. struct clk *clk_bus;
  97. };
  98. static int sun8i_codec_runtime_resume(struct device *dev)
  99. {
  100. struct sun8i_codec *scodec = dev_get_drvdata(dev);
  101. int ret;
  102. ret = clk_prepare_enable(scodec->clk_module);
  103. if (ret) {
  104. dev_err(dev, "Failed to enable the module clock\n");
  105. return ret;
  106. }
  107. ret = clk_prepare_enable(scodec->clk_bus);
  108. if (ret) {
  109. dev_err(dev, "Failed to enable the bus clock\n");
  110. goto err_disable_modclk;
  111. }
  112. regcache_cache_only(scodec->regmap, false);
  113. ret = regcache_sync(scodec->regmap);
  114. if (ret) {
  115. dev_err(dev, "Failed to sync regmap cache\n");
  116. goto err_disable_clk;
  117. }
  118. return 0;
  119. err_disable_clk:
  120. clk_disable_unprepare(scodec->clk_bus);
  121. err_disable_modclk:
  122. clk_disable_unprepare(scodec->clk_module);
  123. return ret;
  124. }
  125. static int sun8i_codec_runtime_suspend(struct device *dev)
  126. {
  127. struct sun8i_codec *scodec = dev_get_drvdata(dev);
  128. regcache_cache_only(scodec->regmap, true);
  129. regcache_mark_dirty(scodec->regmap);
  130. clk_disable_unprepare(scodec->clk_module);
  131. clk_disable_unprepare(scodec->clk_bus);
  132. return 0;
  133. }
  134. static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
  135. {
  136. unsigned int rate = params_rate(params);
  137. switch (rate) {
  138. case 8000:
  139. case 7350:
  140. return 0x0;
  141. case 11025:
  142. return 0x1;
  143. case 12000:
  144. return 0x2;
  145. case 16000:
  146. return 0x3;
  147. case 22050:
  148. return 0x4;
  149. case 24000:
  150. return 0x5;
  151. case 32000:
  152. return 0x6;
  153. case 44100:
  154. return 0x7;
  155. case 48000:
  156. return 0x8;
  157. case 96000:
  158. return 0x9;
  159. case 192000:
  160. return 0xa;
  161. default:
  162. return -EINVAL;
  163. }
  164. }
  165. static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  166. {
  167. struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
  168. u32 value;
  169. /* clock masters */
  170. switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
  171. case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
  172. value = 0x1;
  173. break;
  174. case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
  175. value = 0x0;
  176. break;
  177. default:
  178. return -EINVAL;
  179. }
  180. regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
  181. BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
  182. value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
  183. /* clock inversion */
  184. switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
  185. case SND_SOC_DAIFMT_NB_NF: /* Normal */
  186. value = 0x0;
  187. break;
  188. case SND_SOC_DAIFMT_IB_IF: /* Inversion */
  189. value = 0x1;
  190. break;
  191. default:
  192. return -EINVAL;
  193. }
  194. regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
  195. BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
  196. value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
  197. /*
  198. * It appears that the DAI and the codec don't share the same
  199. * polarity for the LRCK signal when they mean 'normal' and
  200. * 'inverted' in the datasheet.
  201. *
  202. * Since the DAI here is our regular i2s driver that have been
  203. * tested with way more codecs than just this one, it means
  204. * that the codec probably gets it backward, and we have to
  205. * invert the value here.
  206. */
  207. regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
  208. BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
  209. !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
  210. /* DAI format */
  211. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  212. case SND_SOC_DAIFMT_I2S:
  213. value = 0x0;
  214. break;
  215. case SND_SOC_DAIFMT_LEFT_J:
  216. value = 0x1;
  217. break;
  218. case SND_SOC_DAIFMT_RIGHT_J:
  219. value = 0x2;
  220. break;
  221. case SND_SOC_DAIFMT_DSP_A:
  222. case SND_SOC_DAIFMT_DSP_B:
  223. value = 0x3;
  224. break;
  225. default:
  226. return -EINVAL;
  227. }
  228. regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
  229. SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK,
  230. value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
  231. return 0;
  232. }
  233. struct sun8i_codec_clk_div {
  234. u8 div;
  235. u8 val;
  236. };
  237. static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
  238. { .div = 1, .val = 0 },
  239. { .div = 2, .val = 1 },
  240. { .div = 4, .val = 2 },
  241. { .div = 6, .val = 3 },
  242. { .div = 8, .val = 4 },
  243. { .div = 12, .val = 5 },
  244. { .div = 16, .val = 6 },
  245. { .div = 24, .val = 7 },
  246. { .div = 32, .val = 8 },
  247. { .div = 48, .val = 9 },
  248. { .div = 64, .val = 10 },
  249. { .div = 96, .val = 11 },
  250. { .div = 128, .val = 12 },
  251. { .div = 192, .val = 13 },
  252. };
  253. static u8 sun8i_codec_get_bclk_div(struct sun8i_codec *scodec,
  254. unsigned int rate,
  255. unsigned int word_size)
  256. {
  257. unsigned long clk_rate = clk_get_rate(scodec->clk_module);
  258. unsigned int div = clk_rate / rate / word_size / 2;
  259. unsigned int best_val = 0, best_diff = ~0;
  260. int i;
  261. for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
  262. const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
  263. unsigned int diff = abs(bdiv->div - div);
  264. if (diff < best_diff) {
  265. best_diff = diff;
  266. best_val = bdiv->val;
  267. }
  268. }
  269. return best_val;
  270. }
  271. static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
  272. struct snd_pcm_hw_params *params,
  273. struct snd_soc_dai *dai)
  274. {
  275. struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
  276. int sample_rate;
  277. u8 bclk_div;
  278. /*
  279. * The CPU DAI handles only a sample of 16 bits. Configure the
  280. * codec to handle this type of sample resolution.
  281. */
  282. regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
  283. SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
  284. SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
  285. bclk_div = sun8i_codec_get_bclk_div(scodec, params_rate(params), 16);
  286. regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
  287. SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
  288. bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
  289. regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
  290. SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
  291. SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
  292. sample_rate = sun8i_codec_get_hw_rate(params);
  293. if (sample_rate < 0)
  294. return sample_rate;
  295. regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
  296. SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
  297. sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
  298. regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
  299. SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
  300. sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
  301. return 0;
  302. }
  303. static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
  304. SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
  305. SUN8I_DAC_MXR_SRC,
  306. SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
  307. SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
  308. SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
  309. SUN8I_DAC_MXR_SRC,
  310. SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
  311. SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
  312. SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
  313. SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
  314. SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
  315. SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
  316. SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
  317. SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
  318. };
  319. static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = {
  320. SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
  321. SUN8I_AIF1_MXR_SRC,
  322. SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L,
  323. SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
  324. SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC,
  325. SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL,
  326. SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
  327. SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
  328. SUN8I_AIF1_MXR_SRC,
  329. SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL,
  330. SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
  331. SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
  332. SUN8I_AIF1_MXR_SRC,
  333. SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR,
  334. SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
  335. };
  336. static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
  337. /* Digital parts of the DACs and ADC */
  338. SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA,
  339. 0, NULL, 0),
  340. SND_SOC_DAPM_SUPPLY("ADC", SUN8I_ADC_DIG_CTRL, SUN8I_ADC_DIG_CTRL_ENDA,
  341. 0, NULL, 0),
  342. /* Analog DAC AIF */
  343. SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0,
  344. SUN8I_AIF1_DACDAT_CTRL,
  345. SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
  346. SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0,
  347. SUN8I_AIF1_DACDAT_CTRL,
  348. SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
  349. /* Analog ADC AIF */
  350. SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left ADC", "Capture", 0,
  351. SUN8I_AIF1_ADCDAT_CTRL,
  352. SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA, 0),
  353. SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right ADC", "Capture", 0,
  354. SUN8I_AIF1_ADCDAT_CTRL,
  355. SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA, 0),
  356. /* DAC and ADC Mixers */
  357. SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
  358. sun8i_dac_mixer_controls),
  359. SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
  360. sun8i_dac_mixer_controls),
  361. SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
  362. sun8i_input_mixer_controls),
  363. SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
  364. sun8i_input_mixer_controls),
  365. /* Clocks */
  366. SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA,
  367. SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
  368. SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA,
  369. SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
  370. SND_SOC_DAPM_SUPPLY("MODCLK ADC", SUN8I_MOD_CLK_ENA,
  371. SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
  372. SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL,
  373. SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
  374. SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL,
  375. SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
  376. SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL,
  377. SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0),
  378. /* Inversion as 0=AIF1, 1=AIF2 */
  379. SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL,
  380. SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0),
  381. /* Module reset */
  382. SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL,
  383. SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
  384. SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL,
  385. SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
  386. SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL,
  387. SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
  388. SND_SOC_DAPM_MIC("Headset Mic", NULL),
  389. SND_SOC_DAPM_MIC("Mic", NULL),
  390. };
  391. static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
  392. /* Clock Routes */
  393. { "AIF1", NULL, "SYSCLK AIF1" },
  394. { "AIF1 PLL", NULL, "AIF1" },
  395. { "RST AIF1", NULL, "AIF1 PLL" },
  396. { "MODCLK AFI1", NULL, "RST AIF1" },
  397. { "DAC", NULL, "MODCLK AFI1" },
  398. { "ADC", NULL, "MODCLK AFI1" },
  399. { "RST DAC", NULL, "SYSCLK" },
  400. { "MODCLK DAC", NULL, "RST DAC" },
  401. { "DAC", NULL, "MODCLK DAC" },
  402. { "RST ADC", NULL, "SYSCLK" },
  403. { "MODCLK ADC", NULL, "RST ADC" },
  404. { "ADC", NULL, "MODCLK ADC" },
  405. /* DAC Routes */
  406. { "AIF1 Slot 0 Right", NULL, "DAC" },
  407. { "AIF1 Slot 0 Left", NULL, "DAC" },
  408. /* DAC Mixer Routes */
  409. { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
  410. "AIF1 Slot 0 Left"},
  411. { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
  412. "AIF1 Slot 0 Right"},
  413. /* ADC Routes */
  414. { "AIF1 Slot 0 Right ADC", NULL, "ADC" },
  415. { "AIF1 Slot 0 Left ADC", NULL, "ADC" },
  416. /* ADC Mixer Routes */
  417. { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
  418. "AIF1 Slot 0 Left ADC" },
  419. { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
  420. "AIF1 Slot 0 Right ADC" },
  421. };
  422. static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
  423. .hw_params = sun8i_codec_hw_params,
  424. .set_fmt = sun8i_set_fmt,
  425. };
  426. static struct snd_soc_dai_driver sun8i_codec_dai = {
  427. .name = "sun8i",
  428. /* playback capabilities */
  429. .playback = {
  430. .stream_name = "Playback",
  431. .channels_min = 1,
  432. .channels_max = 2,
  433. .rates = SNDRV_PCM_RATE_8000_192000,
  434. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  435. },
  436. /* capture capabilities */
  437. .capture = {
  438. .stream_name = "Capture",
  439. .channels_min = 1,
  440. .channels_max = 2,
  441. .rates = SNDRV_PCM_RATE_8000_192000,
  442. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  443. .sig_bits = 24,
  444. },
  445. /* pcm operations */
  446. .ops = &sun8i_codec_dai_ops,
  447. };
  448. static const struct snd_soc_component_driver sun8i_soc_component = {
  449. .dapm_widgets = sun8i_codec_dapm_widgets,
  450. .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
  451. .dapm_routes = sun8i_codec_dapm_routes,
  452. .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
  453. .idle_bias_on = 1,
  454. .use_pmdown_time = 1,
  455. .endianness = 1,
  456. .non_legacy_dai_naming = 1,
  457. };
  458. static const struct regmap_config sun8i_codec_regmap_config = {
  459. .reg_bits = 32,
  460. .reg_stride = 4,
  461. .val_bits = 32,
  462. .max_register = SUN8I_DAC_MXR_SRC,
  463. .cache_type = REGCACHE_FLAT,
  464. };
  465. static int sun8i_codec_probe(struct platform_device *pdev)
  466. {
  467. struct resource *res_base;
  468. struct sun8i_codec *scodec;
  469. void __iomem *base;
  470. int ret;
  471. scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
  472. if (!scodec)
  473. return -ENOMEM;
  474. scodec->dev = &pdev->dev;
  475. scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
  476. if (IS_ERR(scodec->clk_module)) {
  477. dev_err(&pdev->dev, "Failed to get the module clock\n");
  478. return PTR_ERR(scodec->clk_module);
  479. }
  480. scodec->clk_bus = devm_clk_get(&pdev->dev, "bus");
  481. if (IS_ERR(scodec->clk_bus)) {
  482. dev_err(&pdev->dev, "Failed to get the bus clock\n");
  483. return PTR_ERR(scodec->clk_bus);
  484. }
  485. res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  486. base = devm_ioremap_resource(&pdev->dev, res_base);
  487. if (IS_ERR(base)) {
  488. dev_err(&pdev->dev, "Failed to map the registers\n");
  489. return PTR_ERR(base);
  490. }
  491. scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
  492. &sun8i_codec_regmap_config);
  493. if (IS_ERR(scodec->regmap)) {
  494. dev_err(&pdev->dev, "Failed to create our regmap\n");
  495. return PTR_ERR(scodec->regmap);
  496. }
  497. platform_set_drvdata(pdev, scodec);
  498. pm_runtime_enable(&pdev->dev);
  499. if (!pm_runtime_enabled(&pdev->dev)) {
  500. ret = sun8i_codec_runtime_resume(&pdev->dev);
  501. if (ret)
  502. goto err_pm_disable;
  503. }
  504. ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
  505. &sun8i_codec_dai, 1);
  506. if (ret) {
  507. dev_err(&pdev->dev, "Failed to register codec\n");
  508. goto err_suspend;
  509. }
  510. return ret;
  511. err_suspend:
  512. if (!pm_runtime_status_suspended(&pdev->dev))
  513. sun8i_codec_runtime_suspend(&pdev->dev);
  514. err_pm_disable:
  515. pm_runtime_disable(&pdev->dev);
  516. return ret;
  517. }
  518. static int sun8i_codec_remove(struct platform_device *pdev)
  519. {
  520. pm_runtime_disable(&pdev->dev);
  521. if (!pm_runtime_status_suspended(&pdev->dev))
  522. sun8i_codec_runtime_suspend(&pdev->dev);
  523. return 0;
  524. }
  525. static const struct of_device_id sun8i_codec_of_match[] = {
  526. { .compatible = "allwinner,sun8i-a33-codec" },
  527. {}
  528. };
  529. MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
  530. static const struct dev_pm_ops sun8i_codec_pm_ops = {
  531. SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
  532. sun8i_codec_runtime_resume, NULL)
  533. };
  534. static struct platform_driver sun8i_codec_driver = {
  535. .driver = {
  536. .name = "sun8i-codec",
  537. .of_match_table = sun8i_codec_of_match,
  538. .pm = &sun8i_codec_pm_ops,
  539. },
  540. .probe = sun8i_codec_probe,
  541. .remove = sun8i_codec_remove,
  542. };
  543. module_platform_driver(sun8i_codec_driver);
  544. MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
  545. MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
  546. MODULE_LICENSE("GPL");
  547. MODULE_ALIAS("platform:sun8i-codec");