light-i2s.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2021 Alibaba Group Holding Limited.
  4. */
  5. #include <linux/delay.h>
  6. #include <linux/dma-mapping.h>
  7. #include <linux/pm_runtime.h>
  8. #include <linux/io.h>
  9. #include <linux/of.h>
  10. #include <linux/of_device.h>
  11. #include <linux/scatterlist.h>
  12. #include <linux/sh_dma.h>
  13. #include <linux/slab.h>
  14. #include <linux/module.h>
  15. #include <linux/workqueue.h>
  16. #include <sound/soc.h>
  17. #include <sound/pcm_params.h>
  18. #include <sound/sh_fsi.h>
  19. #include "light-i2s.h"
  20. #include "light-pcm.h"
  21. #include <linux/dmaengine.h>
  22. #include <linux/regmap.h>
  23. #include <sound/core.h>
  24. #include <sound/pcm.h>
  25. #include <sound/initval.h>
  26. #include <sound/dmaengine_pcm.h>
  27. #include <linux/mfd/syscon.h>
  28. #include <dt-bindings/pinctrl/light-fm-aon-pinctrl.h>
  29. #define IIS_SRC_CLK 294912000
  30. #define AUDIO_IIS_SRC0_CLK 49152000
  31. #define AUDIO_IIS_SRC1_CLK 135475200
  32. #define IIS_MCLK_SEL 256
  33. #define HDMI_DIV_VALUE 2
  34. #define DIV_DEFAULT 1
  35. #define MONO_SOURCE 1
  36. #define STEREO_CHANNEL 2
  37. #define AP_I2S "ap_i2s"
  38. #define AUDIO_I2S0 "i2s0"
  39. #define AUDIO_I2S1 "i2s1"
  40. #define AUDIO_I2S3 "i2s3"
  41. #define LIGHT_I2S_DMABUF_SIZE (64 * 1024)
  42. #define LIGHT_RATES SNDRV_PCM_RATE_8000_384000
  43. #define LIGHT_FMTS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8)
  44. #define LIGHT_AUDIO_PAD_CONFIG(idx) (i2s_priv->cfg_off + ((idx-25) >> 1) * 4)
  45. static u32 light_special_sample_rates[] = { 11025, 22050, 44100, 88200 };
  46. static int light_audio_cpr_set(struct light_i2s_priv *chip, unsigned int cpr_off,
  47. unsigned int mask, unsigned int val)
  48. {
  49. return regmap_update_bits(chip->audio_cpr_regmap,
  50. cpr_off, mask, val);
  51. }
  52. static void light_i2s_set_div_sclk(struct light_i2s_priv *chip, u32 sample_rate, unsigned int div_val)
  53. {
  54. u32 div;
  55. u32 div0;
  56. int i;
  57. u32 i2s_src_clk = 0;
  58. if (!strcmp(chip->name, AP_I2S))
  59. div = IIS_SRC_CLK / IIS_MCLK_SEL;
  60. else {
  61. for (i = 0; i < ARRAY_SIZE(light_special_sample_rates); i++) {
  62. if (light_special_sample_rates[i] == sample_rate) {
  63. i2s_src_clk = 1;
  64. break;
  65. }
  66. }
  67. if (!strcmp(chip->name, AUDIO_I2S0)) {
  68. if (!i2s_src_clk) {
  69. light_audio_cpr_set(chip, CPR_PERI_CLK_SEL_REG, CPR_I2S0_SRC_SEL_MSK, CPR_I2S0_SRC_SEL(0));
  70. div = AUDIO_IIS_SRC0_CLK / IIS_MCLK_SEL;
  71. } else {
  72. light_audio_cpr_set(chip, CPR_PERI_CLK_SEL_REG, CPR_I2S0_SRC_SEL_MSK, CPR_I2S0_SRC_SEL(2));
  73. div = AUDIO_IIS_SRC1_CLK / IIS_MCLK_SEL;
  74. }
  75. } else if (!strcmp(chip->name, AUDIO_I2S1)) {
  76. if (!i2s_src_clk) {
  77. light_audio_cpr_set(chip, CPR_PERI_CLK_SEL_REG, CPR_I2S1_SRC_SEL_MSK, CPR_I2S1_SRC_SEL(0));
  78. div = AUDIO_IIS_SRC0_CLK / IIS_MCLK_SEL;
  79. } else {
  80. light_audio_cpr_set(chip, CPR_PERI_CLK_SEL_REG, CPR_I2S1_SRC_SEL_MSK, CPR_I2S1_SRC_SEL(2));
  81. div = AUDIO_IIS_SRC1_CLK / IIS_MCLK_SEL;
  82. }
  83. } else if (!strcmp(chip->name, AUDIO_I2S3)) {
  84. div = AUDIO_IIS_SRC0_CLK / IIS_MCLK_SEL;
  85. }
  86. }
  87. div0 = (div + div % sample_rate) / sample_rate / div_val;
  88. writel(div0, chip->regs + I2S_DIV0_LEVEL);
  89. }
  90. static inline void light_snd_txctrl(struct light_i2s_priv *chip, bool on)
  91. {
  92. u32 dma_en = 0;
  93. u32 i2s_en = 0;
  94. u32 i2s_status = 0;
  95. u32 i2s_imr = 0;
  96. if (on) {
  97. dma_en |= DMACR_TDMAE_EN;
  98. i2s_en |= IISEN_I2SEN;
  99. writel(dma_en, chip->regs + I2S_DMACR);
  100. writel(i2s_en, chip->regs + I2S_IISEN);
  101. } else {
  102. dma_en &= ~DMACR_TDMAE_EN;
  103. i2s_en &= ~IISEN_I2SEN;
  104. i2s_status = readl(chip->regs + I2S_SR);
  105. while ((i2s_status & SR_TXBUSY_STATUS) || !(i2s_status & SR_TFNF_TX_FIFO_NOT_FULL)) {
  106. i2s_status = readl(chip->regs + I2S_SR);
  107. }
  108. i2s_imr = readl(chip->regs + I2S_IMR);
  109. i2s_imr &= ~(IMR_TXUIRM_INTR_MSK);
  110. i2s_imr &= ~(IMR_TXEIM_INTR_MSK);
  111. writel(i2s_imr, chip->regs + I2S_IMR);
  112. i2s_imr = readl(chip->regs + I2S_IMR);
  113. writel(dma_en, chip->regs + I2S_DMACR);
  114. i2s_status = readl(chip->regs + I2S_SR);
  115. while ((i2s_status & SR_TXBUSY_STATUS) || !(i2s_status & SR_TFE_TX_FIFO_EMPTY)) {
  116. i2s_status = readl(chip->regs + I2S_SR);
  117. }
  118. mdelay(10);
  119. writel(i2s_en, chip->regs + I2S_IISEN);
  120. }
  121. }
  122. static inline void light_snd_rxctrl(struct light_i2s_priv *chip, bool on)
  123. {
  124. u32 dma_en;
  125. u32 i2s_en;
  126. if (on) {
  127. dma_en |= DMACR_RDMAE_EN;
  128. i2s_en |= IISEN_I2SEN;
  129. } else {
  130. dma_en &= ~DMACR_RDMAE_EN;
  131. i2s_en &= ~IISEN_I2SEN;
  132. }
  133. writel(dma_en, chip->regs + I2S_DMACR);
  134. writel(i2s_en, chip->regs + I2S_IISEN);
  135. }
  136. static int light_i2s_dai_startup(struct snd_pcm_substream *substream,
  137. struct snd_soc_dai *dai)
  138. {
  139. return 0;
  140. }
  141. static void light_i2s_dai_shutdown(struct snd_pcm_substream *substream,
  142. struct snd_soc_dai *dai)
  143. {
  144. struct light_i2s_priv *i2s_private = snd_soc_dai_get_drvdata(dai);
  145. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  146. light_snd_rxctrl(i2s_private, 0);
  147. clk_disable_unprepare(i2s_private->clk);
  148. }
  149. /**
  150. * light_i2s_dai_trigger: start and stop the DMA transfer.
  151. *
  152. * This function is called by ALSA to start, stop, pause, and resume the DMA
  153. * transfer of data.
  154. */
  155. static int light_i2s_dai_trigger(struct snd_pcm_substream *substream, int cmd,
  156. struct snd_soc_dai *dai)
  157. {
  158. int ret = 0;
  159. struct light_i2s_priv *i2s_private = snd_soc_dai_get_drvdata(dai);
  160. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  161. switch (cmd) {
  162. case SNDRV_PCM_TRIGGER_START:
  163. case SNDRV_PCM_TRIGGER_RESUME:
  164. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  165. if (tx)
  166. light_snd_txctrl(i2s_private, 1);
  167. else
  168. light_snd_rxctrl(i2s_private, 1);
  169. break;
  170. case SNDRV_PCM_TRIGGER_STOP:
  171. case SNDRV_PCM_TRIGGER_SUSPEND:
  172. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  173. if (tx)
  174. light_snd_txctrl(i2s_private, 0);
  175. break;
  176. default:
  177. return -EINVAL;
  178. }
  179. return ret;
  180. }
  181. static int light_i2s_set_fmt_dai(struct snd_soc_dai *cpu_dai, unsigned int fmt)
  182. {
  183. struct light_i2s_priv *i2s_private = snd_soc_dai_get_drvdata(cpu_dai);
  184. u32 cnfout = 0;
  185. u32 cnfin = 0;
  186. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  187. case SND_SOC_DAIFMT_I2S:
  188. cnfout |= IISCNFOUT_TSAFS_I2S;
  189. break;
  190. case SND_SOC_DAIFMT_RIGHT_J:
  191. cnfout |= IISCNFOUT_TSAFS_RIGHT_JUSTIFIED;
  192. break;
  193. case SND_SOC_DAIFMT_LEFT_J:
  194. cnfout |= IISCNFOUT_TSAFS_LEFT_JUSTIFIED;
  195. break;
  196. default:
  197. pr_err("Unknown fmt dai\n");
  198. return -EINVAL;
  199. }
  200. regmap_update_bits(i2s_private->regmap, I2S_IISCNF_OUT,
  201. IISCNFOUT_TSAFS_MSK,
  202. cnfout);
  203. cnfin |= CNFIN_I2S_RXMODE_MASTER_MODE;
  204. regmap_update_bits(i2s_private->regmap, I2S_IISCNF_IN,
  205. CNFIN_I2S_RXMODE_Msk,
  206. cnfin);
  207. return 0;
  208. }
  209. static int light_i2s_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
  210. {
  211. struct light_i2s_priv *i2s_private = snd_soc_dai_get_drvdata(dai);
  212. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  213. u32 val;
  214. u32 len = 0;
  215. u32 sclk_sel = 0;
  216. u32 rate;
  217. u32 funcmode;
  218. u32 iiscnf_out;
  219. u32 iiscnf_in;
  220. u32 i2s_en;
  221. u32 channels = params_channels(params);
  222. rate = params_rate(params);
  223. iiscnf_out = readl(i2s_private->regs + I2S_IISCNF_OUT);
  224. iiscnf_in = readl(i2s_private->regs + I2S_IISCNF_IN);
  225. switch (params_format(params)) {
  226. case SNDRV_PCM_FORMAT_S8:
  227. val |= I2S_DATA_8BIT_WIDTH_32BIT;
  228. len = 32;
  229. break;
  230. case SNDRV_PCM_FORMAT_S16_LE:
  231. val |= I2S_DATA_WIDTH_16BIT;
  232. len = 32;
  233. break;
  234. case SNDRV_PCM_FORMAT_S24_LE:
  235. val |= I2S_DATA_WIDTH_24BIT;
  236. len = 32;
  237. break;
  238. case SNDRV_PCM_FORMAT_S32_LE:
  239. val |= I2S_DATA_WIDTH_32BIT;
  240. len = 32;
  241. break;
  242. default:
  243. pr_err("Unknown data format\n");
  244. return -EINVAL;
  245. }
  246. sclk_sel = len*STEREO_CHANNEL;
  247. switch (sclk_sel) {
  248. case 16:
  249. val |= FSSTA_SCLK_SEL_16;
  250. break;
  251. case 32:
  252. val |= FSSTA_SCLK_SEL_32;
  253. break;
  254. case 48:
  255. val |= FSSTA_SCLK_SEL_48;
  256. break;
  257. case 64:
  258. val |= FSSTA_SCLK_SEL_64;
  259. break;
  260. default:
  261. pr_err("Not support channel num %d\n", channels);
  262. return -EINVAL;
  263. }
  264. i2s_en &= ~IISEN_I2SEN;
  265. writel(i2s_en, i2s_private->regs + I2S_IISEN);
  266. regmap_update_bits(i2s_private->regmap, I2S_FSSTA,
  267. FSSTA_DATAWTH_Msk | FSSTA_SCLK_SEL_Msk,
  268. val);
  269. funcmode = readl(i2s_private->regs + I2S_FUNCMODE);
  270. if (tx) {
  271. funcmode |= FUNCMODE_TMODE_WEN;
  272. funcmode &= ~FUNCMODE_CH1_ENABLE;
  273. funcmode |= FUNCMODE_RMODE_WEN;
  274. funcmode &= ~FUNCMODE_RMODE;
  275. funcmode &= ~FUNCMODE_TMODE;
  276. funcmode |= FUNCMODE_TMODE;
  277. } else {
  278. funcmode |= FUNCMODE_RMODE_WEN;
  279. funcmode |= FUNCMODE_CH0_ENABLE;
  280. funcmode |= FUNCMODE_CH1_ENABLE;
  281. funcmode |= FUNCMODE_CH2_ENABLE;
  282. funcmode |= FUNCMODE_TMODE_WEN;
  283. funcmode &= ~FUNCMODE_TMODE;
  284. funcmode &= ~FUNCMODE_RMODE;
  285. funcmode |= FUNCMODE_RMODE;
  286. }
  287. writel(funcmode, i2s_private->regs + I2S_FUNCMODE);
  288. if (channels == MONO_SOURCE) {
  289. iiscnf_out |= IISCNFOUT_TX_VOICE_EN_MONO;
  290. iiscnf_in |= CNFIN_RX_CH_SEL_LEFT;
  291. iiscnf_in |= CNFIN_RVOICEEN_MONO;
  292. } else {
  293. iiscnf_out &= ~IISCNFOUT_TX_VOICE_EN_MONO;
  294. iiscnf_in &= ~CNFIN_RX_CH_SEL_LEFT;
  295. iiscnf_in &= ~CNFIN_RVOICEEN_MONO;
  296. }
  297. if (tx)
  298. writel(iiscnf_out, i2s_private->regs + I2S_IISCNF_OUT);
  299. else
  300. writel(iiscnf_in, i2s_private->regs + I2S_IISCNF_IN);
  301. light_i2s_set_div_sclk(i2s_private, rate, DIV_DEFAULT);
  302. return 0;
  303. }
  304. static int light_hdmi_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
  305. {
  306. struct light_i2s_priv *i2s_private = snd_soc_dai_get_drvdata(dai);
  307. bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
  308. u32 val;
  309. u32 len = 0;
  310. u32 rate;
  311. u32 funcmode;
  312. u32 iiscnf_out;
  313. u32 i2s_en;
  314. u32 channels = params_channels(params);
  315. rate = params_rate(params);
  316. switch (params_format(params)) {
  317. case SNDRV_PCM_FORMAT_S16_LE:
  318. val |= I2S_DATA_WIDTH_16BIT;
  319. len = 16;
  320. break;
  321. case SNDRV_PCM_FORMAT_S24_LE:
  322. val |= I2S_DATA_WIDTH_24BIT;
  323. len = 24;
  324. break;
  325. default:
  326. pr_err("Unknown data format\n");
  327. return -EINVAL;
  328. }
  329. val |= FSSTA_SCLK_SEL_64;
  330. i2s_en &= ~IISEN_I2SEN;
  331. writel(i2s_en, i2s_private->regs + I2S_IISEN);
  332. regmap_update_bits(i2s_private->regmap, I2S_FSSTA,
  333. FSSTA_DATAWTH_Msk | FSSTA_SCLK_SEL_Msk,
  334. val);
  335. funcmode = readl(i2s_private->regs + I2S_FUNCMODE);
  336. if (tx) {
  337. funcmode |= FUNCMODE_TMODE_WEN;
  338. funcmode &= ~FUNCMODE_TMODE;
  339. funcmode |= FUNCMODE_TMODE;
  340. } else {
  341. funcmode |= FUNCMODE_RMODE_WEN;
  342. funcmode &= ~FUNCMODE_RMODE;
  343. funcmode |= FUNCMODE_RMODE;
  344. }
  345. writel(funcmode, i2s_private->regs + I2S_FUNCMODE);
  346. iiscnf_out = readl(i2s_private->regs + I2S_IISCNF_OUT);
  347. if (channels == MONO_SOURCE)
  348. iiscnf_out |= IISCNFOUT_TX_VOICE_EN_MONO;
  349. else
  350. iiscnf_out &= ~IISCNFOUT_TX_VOICE_EN_MONO;
  351. writel(iiscnf_out, i2s_private->regs + I2S_IISCNF_OUT);
  352. light_i2s_set_div_sclk(i2s_private, rate, DIV_DEFAULT);
  353. return 0;
  354. }
  355. static int light_i2s_dai_probe(struct snd_soc_dai *dai)
  356. {
  357. struct light_i2s_priv *i2s = snd_soc_dai_get_drvdata(dai);
  358. if(i2s)
  359. snd_soc_dai_init_dma_data(dai, &i2s->dma_params_tx,
  360. &i2s->dma_params_rx);
  361. return 0;
  362. }
  363. static const struct snd_soc_dai_ops light_i2s_dai_ops = {
  364. .startup = light_i2s_dai_startup,
  365. .shutdown = light_i2s_dai_shutdown,
  366. .trigger = light_i2s_dai_trigger,
  367. .set_fmt = light_i2s_set_fmt_dai,
  368. .hw_params = light_i2s_dai_hw_params,
  369. };
  370. static const struct snd_soc_dai_ops light_hdmi_dai_ops = {
  371. .startup = light_i2s_dai_startup,
  372. .shutdown = light_i2s_dai_shutdown,
  373. .trigger = light_i2s_dai_trigger,
  374. .set_fmt = light_i2s_set_fmt_dai,
  375. .hw_params = light_hdmi_dai_hw_params,
  376. };
  377. static struct snd_soc_dai_driver light_i2s_soc_dai[] = {
  378. {
  379. .probe = light_i2s_dai_probe,
  380. .name = "light-i2s-dai",
  381. .playback = {
  382. .rates = LIGHT_RATES,
  383. .formats = LIGHT_FMTS,
  384. .channels_min = 1,
  385. .channels_max = 2,
  386. },
  387. .capture = {
  388. .rates = LIGHT_RATES,
  389. .formats = LIGHT_FMTS,
  390. .channels_min = 1,
  391. .channels_max = 2,
  392. },
  393. .ops = &light_i2s_dai_ops,
  394. },
  395. {
  396. .probe = light_i2s_dai_probe,
  397. .name = "light-hdmi-dai",
  398. .playback = {
  399. .rates = LIGHT_RATES,
  400. .formats = LIGHT_FMTS,
  401. .channels_min = 1,
  402. .channels_max = 2,
  403. },
  404. .ops = &light_hdmi_dai_ops,
  405. },
  406. };
  407. static const struct snd_soc_component_driver light_i2s_soc_component = {
  408. .name = "light_i2s",
  409. };
  410. static int light_pcm_probe(struct platform_device *pdev,struct light_i2s_priv *i2s)
  411. {
  412. int ret;
  413. ret = light_pcm_dma_init(pdev, LIGHT_I2S_DMABUF_SIZE);
  414. if (ret) {
  415. pr_err("light_pcm_dma_init error\n");
  416. return 0;
  417. }
  418. return 0;
  419. }
  420. static bool light_i2s_wr_reg(struct device *dev, unsigned int reg)
  421. {
  422. switch (reg) {
  423. case I2S_IISEN:
  424. case I2S_FUNCMODE:
  425. case I2S_IISCNF_IN:
  426. case I2S_FSSTA:
  427. case I2S_IISCNF_OUT:
  428. case I2S_DMACR:
  429. return true;
  430. default:
  431. return false;
  432. }
  433. }
  434. static bool light_i2s_rd_reg(struct device *dev, unsigned int reg)
  435. {
  436. switch (reg) {
  437. case I2S_IISEN:
  438. case I2S_FUNCMODE:
  439. case I2S_IISCNF_IN:
  440. case I2S_FSSTA:
  441. case I2S_IISCNF_OUT:
  442. case I2S_DMACR:
  443. return true;
  444. default:
  445. return false;
  446. }
  447. }
  448. static const struct regmap_config light_i2s_regmap_config = {
  449. .reg_bits = 32,
  450. .reg_stride = 4,
  451. .val_bits = 32,
  452. .max_register = I2S_DR4,
  453. .writeable_reg = light_i2s_wr_reg,
  454. .readable_reg = light_i2s_rd_reg,
  455. .cache_type = REGCACHE_FLAT,
  456. };
  457. static int light_audio_pinconf_set(struct device *dev, unsigned int pin_id, unsigned int val)
  458. {
  459. struct light_i2s_priv *i2s_priv = dev_get_drvdata(dev);
  460. unsigned int shift;
  461. unsigned int mask = 0;
  462. i2s_priv->cfg_off = 0xC;
  463. shift = (((pin_id-25) % 2) << 4);
  464. mask |= (0xFFFF << shift);
  465. val = (val << shift);
  466. return regmap_update_bits(i2s_priv->audio_pin_regmap,
  467. LIGHT_AUDIO_PAD_CONFIG(pin_id),mask, val);
  468. }
  469. static int light_audio_pinctrl(struct device *dev)
  470. {
  471. struct light_i2s_priv *i2s_priv = dev_get_drvdata(dev);
  472. if (!strcmp(i2s_priv->name, AUDIO_I2S0)) {
  473. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA6, 0x4);
  474. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA7, 0x4);
  475. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA9, 0x8);
  476. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA10, 0x8);
  477. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA11, 0x8);
  478. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA12, 0x8);
  479. } else if (!strcmp(i2s_priv->name, AUDIO_I2S1)) {
  480. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA6, 0x4);
  481. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA7, 0x4);
  482. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA13, 0x8);
  483. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA14, 0x8);
  484. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA15, 0x8);
  485. light_audio_pinconf_set(i2s_priv->dev, FM_AUDIO_PA17, 0x8);
  486. }
  487. return 0;
  488. }
  489. static int light_i2s_runtime_suspend(struct device *dev)
  490. {
  491. struct light_i2s_priv *i2s_priv = dev_get_drvdata(dev);
  492. regcache_cache_only(i2s_priv->regmap, true);
  493. clk_disable_unprepare(i2s_priv->clk);
  494. return 0;
  495. }
  496. static int light_i2s_runtime_resume(struct device *dev)
  497. {
  498. struct light_i2s_priv *i2s_priv = dev_get_drvdata(dev);
  499. int ret;
  500. ret = clk_prepare_enable(i2s_priv->clk);
  501. if (ret) {
  502. dev_err(i2s_priv->dev, "clock enable failed %d\n", ret);
  503. return ret;
  504. }
  505. regcache_cache_only(i2s_priv->regmap, false);
  506. return ret;
  507. }
  508. static const struct of_device_id light_i2s_of_match[] = {
  509. { .compatible = "light,light-i2s"},
  510. {},
  511. };
  512. MODULE_DEVICE_TABLE(of, light_i2s_of_match);
  513. static int light_audio_i2s_probe(struct platform_device *pdev)
  514. {
  515. struct device_node *np = pdev->dev.of_node;
  516. const char *sprop;
  517. const uint32_t *iprop;
  518. struct light_i2s_priv *i2s_priv;
  519. struct resource *res;
  520. struct device *dev = &pdev->dev;
  521. unsigned int irq;
  522. int ret;
  523. i2s_priv = devm_kzalloc(&pdev->dev, sizeof(*i2s_priv),
  524. GFP_KERNEL);
  525. if (!i2s_priv)
  526. return -ENOMEM;
  527. i2s_priv->dev = dev;
  528. sprop = of_get_property(np, "light,mode", NULL);
  529. if (sprop) {
  530. if (!strcmp(sprop, "i2s-master"))
  531. i2s_priv->dai_fmt = SND_SOC_DAIFMT_I2S;
  532. else
  533. printk("mode is not i2s-master");
  534. }
  535. sprop = of_get_property(np, "light,sel", NULL);
  536. if (sprop) {
  537. strcpy(i2s_priv->name, sprop);
  538. }
  539. iprop = of_get_property(np, "light,dma_maxburst", NULL);
  540. if (iprop)
  541. i2s_priv->dma_maxburst = be32_to_cpup(iprop);
  542. else
  543. i2s_priv->dma_maxburst = 8;
  544. dev_set_drvdata(&pdev->dev, i2s_priv);
  545. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  546. i2s_priv->regs = devm_ioremap_resource(dev, res);
  547. if (IS_ERR(i2s_priv->regs))
  548. return PTR_ERR(i2s_priv->regs);
  549. i2s_priv->regmap = devm_regmap_init_mmio(&pdev->dev, i2s_priv->regs,
  550. &light_i2s_regmap_config);
  551. if (IS_ERR(i2s_priv->regmap)) {
  552. dev_err(&pdev->dev,
  553. "Failed to initialise managed register map\n");
  554. return PTR_ERR(i2s_priv->regmap);
  555. }
  556. if (!strcmp(i2s_priv->name, AUDIO_I2S0) || !strcmp(i2s_priv->name, AUDIO_I2S1)) {
  557. i2s_priv->audio_pin_regmap = syscon_regmap_lookup_by_phandle(np, "audio-pin-regmap");
  558. if (IS_ERR(i2s_priv->audio_pin_regmap)) {
  559. dev_err(&pdev->dev, "cannot find regmap for audio system register\n");
  560. } else
  561. light_audio_pinctrl(&pdev->dev);
  562. i2s_priv->audio_cpr_regmap = syscon_regmap_lookup_by_phandle(np, "audio-cpr-regmap");
  563. if (IS_ERR(i2s_priv->audio_cpr_regmap)) {
  564. dev_err(&pdev->dev, "cannot find regmap for audio cpr register\n");
  565. } else
  566. light_audio_cpr_set(i2s_priv, CPR_PERI_DIV_SEL_REG, CPR_AUDIO_DIV1_SEL_MSK, CPR_AUDIO_DIV1_SEL(5));
  567. }
  568. pm_runtime_enable(&pdev->dev);
  569. if (!pm_runtime_enabled(&pdev->dev)) {
  570. ret = light_i2s_runtime_resume(&pdev->dev);
  571. if (ret)
  572. goto err_pm_disable;
  573. }
  574. irq = platform_get_irq(pdev, 0);
  575. if (!res || (int)irq <= 0) {
  576. dev_err(&pdev->dev, "Not enough light platform resources.\n");
  577. return -ENODEV;
  578. }
  579. i2s_priv->clk = devm_clk_get(&pdev->dev, "pclk");
  580. if (IS_ERR(i2s_priv->clk))
  581. return PTR_ERR(i2s_priv->clk);
  582. ret = clk_prepare_enable(i2s_priv->clk);
  583. if (ret < 0)
  584. return ret;
  585. i2s_priv->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
  586. i2s_priv->dma_params_rx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
  587. i2s_priv->dma_params_tx.maxburst = i2s_priv->dma_maxburst;
  588. i2s_priv->dma_params_rx.maxburst = i2s_priv->dma_maxburst;
  589. if (!strcmp(i2s_priv->name, AP_I2S)) {
  590. i2s_priv->dma_params_tx.addr = res->start + I2S_DR;
  591. i2s_priv->dma_params_rx.addr = res->start + I2S_DR1;
  592. } else if (!strcmp(i2s_priv->name, AUDIO_I2S0) || !strcmp(i2s_priv->name, AUDIO_I2S1)) {
  593. i2s_priv->dma_params_tx.addr = res->start + I2S_DR;
  594. i2s_priv->dma_params_rx.addr = res->start + I2S_DR;
  595. } else if (!strcmp(i2s_priv->name, AUDIO_I2S3)) {
  596. i2s_priv->dma_params_tx.addr = res->start + I2S_DR;
  597. i2s_priv->dma_params_rx.addr = res->start + I2S_DR2;
  598. }
  599. light_pcm_probe(pdev, i2s_priv);
  600. ret = devm_snd_soc_register_component(&pdev->dev, &light_i2s_soc_component,
  601. light_i2s_soc_dai, ARRAY_SIZE(light_i2s_soc_dai));
  602. if (ret < 0) {
  603. dev_err(&pdev->dev, "cannot snd component register\n");
  604. goto err_pm_disable;
  605. }
  606. return ret;
  607. err_pm_disable:
  608. pm_runtime_disable(&pdev->dev);
  609. return ret;
  610. }
  611. static int light_i2s_remove(struct platform_device *pdev)
  612. {
  613. struct light_i2s_priv *i2s_priv = dev_get_drvdata(&pdev->dev);
  614. pm_runtime_disable(&pdev->dev);
  615. if (!pm_runtime_status_suspended(&pdev->dev))
  616. light_i2s_runtime_suspend(&pdev->dev);
  617. clk_disable_unprepare(i2s_priv->clk);
  618. return 0;
  619. }
  620. static const struct dev_pm_ops light_i2s_pm_ops = {
  621. SET_RUNTIME_PM_OPS(light_i2s_runtime_suspend, light_i2s_runtime_resume,
  622. NULL)
  623. };
  624. static struct platform_driver light_i2s_driver = {
  625. .driver = {
  626. .name = "light-pcm-audio",
  627. .pm = &light_i2s_pm_ops,
  628. .of_match_table = light_i2s_of_match,
  629. },
  630. .probe = light_audio_i2s_probe,
  631. .remove = light_i2s_remove,
  632. };
  633. module_platform_driver(light_i2s_driver);
  634. MODULE_AUTHOR("shuofeng.ren <shuofeng.rsf@linux.alibaba.com>");
  635. MODULE_DESCRIPTION("Thead Light audio driver");
  636. MODULE_LICENSE("GPL v2");