sun8i-codec.c 19 KB

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