Advertisement
codekipper

Untitled

May 30th, 2016
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.55 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2015 Andrea Venturi
  3. * Andrea Venturi <be17068@iperbole.bo.it>
  4. *
  5. * Copyright (C) 2015 Maxime Ripard
  6. * Maxime Ripard <maxime.ripard@free-electrons.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. */
  13.  
  14. #include <linux/clk.h>
  15. #include <linux/dmaengine.h>
  16. #include <linux/module.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/regmap.h>
  19.  
  20. #include <sound/dmaengine_pcm.h>
  21. #include <sound/pcm_params.h>
  22. #include <sound/soc.h>
  23. #include <sound/soc-dai.h>
  24.  
  25. #define SUN4I_DAI_CTRL_REG 0x00
  26. #define SUN4I_DAI_CTRL_SDO_EN_MASK GENMASK(11, 8)
  27. #define SUN4I_DAI_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
  28. #define SUN4I_DAI_CTRL_MODE_MASK BIT(5)
  29. #define SUN4I_DAI_CTRL_MODE_SLAVE (1 << 5)
  30. #define SUN4I_DAI_CTRL_MODE_MASTER (0 << 5)
  31. #define SUN4I_DAI_CTRL_TX_EN BIT(2)
  32. #define SUN4I_DAI_CTRL_RX_EN BIT(1)
  33. #define SUN4I_DAI_CTRL_GL_EN BIT(0)
  34.  
  35. #define SUN4I_DAI_FMT0_REG 0x04
  36. #define SUN4I_DAI_FMT0_LRCLK_POLARITY_MASK BIT(7)
  37. #define SUN4I_DAI_FMT0_LRCLK_POLARITY_INVERTED (1 << 7)
  38. #define SUN4I_DAI_FMT0_LRCLK_POLARITY_NORMAL (0 << 7)
  39. #define SUN4I_DAI_FMT0_BCLK_POLARITY_MASK BIT(6)
  40. #define SUN4I_DAI_FMT0_BCLK_POLARITY_INVERTED (1 << 6)
  41. #define SUN4I_DAI_FMT0_BCLK_POLARITY_NORMAL (0 << 6)
  42. #define SUN4I_DAI_FMT0_SR_MASK GENMASK(5, 4)
  43. #define SUN4I_DAI_FMT0_SR(sr) ((sr) << 4)
  44. #define SUN4I_DAI_FMT0_WSS_MASK GENMASK(3, 2)
  45. #define SUN4I_DAI_FMT0_WSS(wss) ((wss) << 2)
  46. #define SUN4I_DAI_FMT0_FMT_MASK GENMASK(1, 0)
  47. #define SUN4I_DAI_FMT0_FMT_RIGHT_J (2 << 0)
  48. #define SUN4I_DAI_FMT0_FMT_LEFT_J (1 << 0)
  49. #define SUN4I_DAI_FMT0_FMT_I2S (0 << 0)
  50.  
  51. #define SUN4I_DAI_FMT1_REG 0x08
  52. #define SUN4I_DAI_FIFO_TX_REG 0x0c
  53. #define SUN4I_DAI_FIFO_RX_REG 0x10
  54.  
  55. #define SUN4I_DAI_FIFO_CTRL_REG 0x14
  56. #define SUN4I_DAI_FIFO_CTRL_FLUSH_TX BIT(25)
  57. #define SUN4I_DAI_FIFO_CTRL_FLUSH_RX BIT(24)
  58. #define SUN4I_DAI_FIFO_CTRL_TXTL_MASK GENMASK(18,12)
  59. #define SUN4I_DAI_FIFO_CTRL_TXTL(level) ((level) << 12)
  60. #define SUN4I_DAI_FIFO_CTRL_TX_MODE_MASK BIT(2)
  61. #define SUN4I_DAI_FIFO_CTRL_TX_MODE(mode) ((mode) << 2)
  62. #define SUN4I_DAI_FIFO_CTRL_RX_MODE_MASK GENMASK(1, 0)
  63. #define SUN4I_DAI_FIFO_CTRL_RX_MODE(mode) (mode)
  64.  
  65. #define SUN4I_DAI_FIFO_STA_REG 0x18
  66.  
  67. #define SUN4I_DAI_DMA_INT_CTRL_REG 0x1c
  68. #define SUN4I_DAI_DMA_INT_CTRL_TX_DRQ_EN BIT(7)
  69. #define SUN4I_DAI_DMA_INT_CTRL_RX_DRQ_EN BIT(3)
  70.  
  71. #define SUN4I_DAI_INT_STA_REG 0x20
  72.  
  73. #define SUN4I_DAI_CLK_DIV_REG 0x24
  74. #define SUN4I_DAI_CLK_DIV_MCLK_EN BIT(7)
  75. #define SUN4I_DAI_CLK_DIV_BCLK_MASK GENMASK(6, 4)
  76. #define SUN4I_DAI_CLK_DIV_BCLK(bclk) ((bclk) << 4)
  77. #define SUN4I_DAI_CLK_DIV_MCLK_MASK GENMASK(3, 0)
  78. #define SUN4I_DAI_CLK_DIV_MCLK(mclk) ((mclk) << 0)
  79.  
  80. #define SUN4I_DAI_RX_CNT_REG 0x28
  81. #define SUN4I_DAI_TX_CNT_REG 0x2c
  82.  
  83. #define SUN4I_DAI_TX_CHAN_SEL_REG 0x30
  84. #define SUN4I_DAI_TX_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
  85.  
  86. #define SUN4I_DAI_TX_CHAN_MAP_REG 0x34
  87. #define SUN4I_DAI_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2))
  88.  
  89. #define SUN4I_DAI_RX_CHAN_SEL_REG 0x38
  90. #define SUN4I_DAI_RX_CHAN_MAP_REG 0x3c
  91.  
  92. struct sun4i_dai {
  93. struct platform_device *pdev;
  94. struct clk *bus_clk;
  95. struct clk *mod_clk;
  96. struct regmap *regmap;
  97.  
  98. struct snd_dmaengine_dai_dma_data playback_dma_data;
  99. struct snd_dmaengine_dai_dma_data capture_dma_data;
  100. };
  101.  
  102. struct sun4i_dai_clk_div {
  103. u8 div;
  104. u8 val;
  105. };
  106.  
  107. static const struct sun4i_dai_clk_div sun4i_dai_bclk_div[] = {
  108. { .div = 2, .val = 0 },
  109. { .div = 4, .val = 1 },
  110. { .div = 6, .val = 2 },
  111. { .div = 8, .val = 3 },
  112. { .div = 12, .val = 4 },
  113. { .div = 16, .val = 5 },
  114. { /* Sentinel */ },
  115. };
  116.  
  117. static const struct sun4i_dai_clk_div sun4i_dai_mclk_div[] = {
  118. { .div = 1, .val = 0 },
  119. { .div = 2, .val = 1 },
  120. { .div = 4, .val = 2 },
  121. { .div = 6, .val = 3 },
  122. { .div = 8, .val = 4 },
  123. { .div = 12, .val = 5 },
  124. { .div = 16, .val = 6 },
  125. { .div = 24, .val = 7 },
  126. { /* Sentinel */ },
  127. };
  128.  
  129. static int sun4i_dai_params_to_sr(struct snd_pcm_hw_params *params)
  130. {
  131. int ret = -EINVAL;
  132. switch (params_width(params)) {
  133. case 16:
  134. ret = 0;
  135. break;
  136. case 20:
  137. ret = 1;
  138. break;
  139. case 24:
  140. ret = 2;
  141. break;
  142. default:
  143. ret = -EINVAL;
  144.  
  145. }
  146.  
  147. return ret;
  148. }
  149.  
  150. static u8 sun4i_dai_params_to_wss(struct snd_pcm_hw_params *params)
  151. {
  152. int ret = -EINVAL;
  153. switch (params_width(params)) {
  154. case 16:
  155. ret = 0;
  156. break;
  157. case 20:
  158. ret = 1;
  159. break;
  160. case 24:
  161. ret = 2;
  162. break;
  163. default:
  164. ret = 3;
  165. break;
  166. }
  167.  
  168. return ret;
  169. }
  170.  
  171. static int sun4i_dai_get_bclk_div(struct sun4i_dai *sdai,
  172. unsigned int oversample_rate,
  173. unsigned int word_size)
  174. {
  175. int div = oversample_rate / word_size / 2;
  176. int i;
  177.  
  178. for (i = 0; sun4i_dai_bclk_div[i].div; i++) {
  179. const struct sun4i_dai_clk_div *bdiv = sun4i_dai_bclk_div + i;
  180.  
  181. if (bdiv->div == div)
  182. return bdiv->val;
  183. }
  184.  
  185. return -EINVAL;
  186. }
  187.  
  188. static int sun4i_dai_get_mclk_div(struct sun4i_dai *sdai,
  189. unsigned int oversample_rate,
  190. unsigned int module_rate,
  191. unsigned int sampling_rate)
  192. {
  193. int div = module_rate / sampling_rate / oversample_rate;
  194. int i;
  195.  
  196. for (i = 0; sun4i_dai_mclk_div[i].div; i++) {
  197. const struct sun4i_dai_clk_div *mdiv = sun4i_dai_mclk_div + i;
  198.  
  199. if (mdiv->div == div)
  200. return mdiv->val;
  201. }
  202.  
  203. return -EINVAL;
  204. }
  205.  
  206. static int sun4i_dai_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };
  207.  
  208. static int sun4i_dai_set_clk_rate(struct sun4i_dai *sdai,
  209. unsigned int rate,
  210. unsigned int word_size)
  211. {
  212. unsigned int clk_rate;
  213. int bclk_div, mclk_div;
  214. int i;
  215.  
  216. printk("%s +%d\n", __func__, __LINE__);
  217.  
  218. switch (rate) {
  219. case 176400:
  220. case 88200:
  221. case 44100:
  222. case 22050:
  223. case 11025:
  224. clk_rate = 22579200;
  225. break;
  226.  
  227. case 192000:
  228. case 128000:
  229. case 96000:
  230. case 64000:
  231. case 48000:
  232. case 32000:
  233. case 24000:
  234. case 16000:
  235. case 12000:
  236. case 8000:
  237. clk_rate = 24576000;
  238. break;
  239.  
  240. default:
  241. return -EINVAL;
  242. }
  243.  
  244. printk("%s +%d\n", __func__, __LINE__);
  245.  
  246. clk_set_rate(sdai->mod_clk, clk_rate);
  247.  
  248. /* Always favor the highest oversampling rate */
  249. for (i = (ARRAY_SIZE(sun4i_dai_oversample_rates) - 1); i >= 0; i--) {
  250. unsigned int oversample_rate = sun4i_dai_oversample_rates[i];
  251.  
  252. bclk_div = sun4i_dai_get_bclk_div(sdai, oversample_rate,
  253. word_size);
  254. mclk_div = sun4i_dai_get_mclk_div(sdai, oversample_rate,
  255. clk_rate,
  256. rate);
  257.  
  258. printk("%s rate %dHz oversample rate %d fs mclk %d bclk %d\n", __func__, rate,
  259. oversample_rate, mclk_div, bclk_div);
  260.  
  261. if ((bclk_div >= 0) && (mclk_div >= 0))
  262. break;
  263. }
  264.  
  265. if ((bclk_div < 0) || (mclk_div < 0))
  266. return -EINVAL;
  267.  
  268. printk("%s +%d\n", __func__, __LINE__);
  269.  
  270. regmap_write(sdai->regmap, SUN4I_DAI_CLK_DIV_REG,
  271. SUN4I_DAI_CLK_DIV_BCLK(bclk_div) |
  272. SUN4I_DAI_CLK_DIV_MCLK(mclk_div) |
  273. SUN4I_DAI_CLK_DIV_MCLK_EN);
  274.  
  275. printk("%s +%d\n", __func__, __LINE__);
  276.  
  277. return 0;
  278. }
  279.  
  280. static int sun4i_dai_hw_params(struct snd_pcm_substream *substream,
  281. struct snd_pcm_hw_params *params,
  282. struct snd_soc_dai *dai)
  283. {
  284. struct sun4i_dai *sdai = snd_soc_dai_get_drvdata(dai);
  285. int sr, wss;
  286. u32 width;
  287.  
  288. printk("%s +%d\n", __func__, __LINE__);
  289.  
  290. if (params_channels(params) != 2)
  291. return -EINVAL;
  292.  
  293. printk("%s +%d\n", __func__, __LINE__);
  294.  
  295. /* Enable the first output line */
  296. regmap_update_bits(sdai->regmap, SUN4I_DAI_CTRL_REG,
  297. SUN4I_DAI_CTRL_SDO_EN_MASK,
  298. SUN4I_DAI_CTRL_SDO_EN(0));
  299.  
  300. printk("%s +%d\n", __func__, __LINE__);
  301.  
  302. /* Enable the first two channels */
  303. regmap_write(sdai->regmap, SUN4I_DAI_TX_CHAN_SEL_REG,
  304. SUN4I_DAI_TX_CHAN_SEL(2));
  305.  
  306. printk("%s +%d\n", __func__, __LINE__);
  307.  
  308. /* Map them to the two first samples coming in */
  309. regmap_write(sdai->regmap, SUN4I_DAI_TX_CHAN_MAP_REG,
  310. SUN4I_DAI_TX_CHAN_MAP(0, 0) | SUN4I_DAI_TX_CHAN_MAP(1, 1));
  311.  
  312. printk("%s +%d\n", __func__, __LINE__);
  313.  
  314. switch (params_physical_width(params)) {
  315. case 16:
  316. width = DMA_SLAVE_BUSWIDTH_2_BYTES;
  317. break;
  318. case 24:
  319. case 32:
  320. width = DMA_SLAVE_BUSWIDTH_4_BYTES;
  321. break;
  322. default:
  323. return -EINVAL;
  324. }
  325. sdai->playback_dma_data.addr_width = width;
  326.  
  327. printk("%s +%d\n", __func__, __LINE__);
  328.  
  329. sr = sun4i_dai_params_to_sr(params);
  330. if (sr < 0)
  331. return -EINVAL;
  332.  
  333. printk("%s +%d\n", __func__, __LINE__);
  334.  
  335. wss = sun4i_dai_params_to_wss(params);
  336. if (wss < 0)
  337. return -EINVAL;
  338.  
  339. printk("%s wss returned is %d based on a width of %d\n", __func__, wss, snd_soc_params_to_frame_size(params));
  340.  
  341. regmap_update_bits(sdai->regmap, SUN4I_DAI_FMT0_REG,
  342. SUN4I_DAI_FMT0_WSS_MASK | SUN4I_DAI_FMT0_SR_MASK,
  343. SUN4I_DAI_FMT0_WSS(wss) | SUN4I_DAI_FMT0_SR(sr));
  344.  
  345. printk("%s +%d\n", __func__, __LINE__);
  346.  
  347. return sun4i_dai_set_clk_rate(sdai, params_rate(params),
  348. params_width(params));
  349. }
  350.  
  351. static int sun4i_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  352. {
  353. struct sun4i_dai *sdai = snd_soc_dai_get_drvdata(dai);
  354. u32 val;
  355.  
  356. /* DAI Mode */
  357. switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
  358. case SND_SOC_DAIFMT_I2S:
  359. val = SUN4I_DAI_FMT0_FMT_I2S;
  360. break;
  361. case SND_SOC_DAIFMT_LEFT_J:
  362. val = SUN4I_DAI_FMT0_FMT_LEFT_J;
  363. break;
  364. case SND_SOC_DAIFMT_RIGHT_J:
  365. val = SUN4I_DAI_FMT0_FMT_RIGHT_J;
  366. break;
  367. default:
  368. return -EINVAL;
  369. }
  370.  
  371. regmap_update_bits(sdai->regmap, SUN4I_DAI_FMT0_REG,
  372. SUN4I_DAI_FMT0_FMT_MASK,
  373. val);
  374.  
  375. /* DAI clock polarity */
  376. switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
  377. case SND_SOC_DAIFMT_IB_IF:
  378. /* Invert both clocks */
  379. val = SUN4I_DAI_FMT0_BCLK_POLARITY_INVERTED |
  380. SUN4I_DAI_FMT0_LRCLK_POLARITY_INVERTED;
  381. break;
  382. case SND_SOC_DAIFMT_IB_NF:
  383. /* Invert bit clock */
  384. val = SUN4I_DAI_FMT0_BCLK_POLARITY_INVERTED |
  385. SUN4I_DAI_FMT0_LRCLK_POLARITY_NORMAL;
  386. break;
  387. case SND_SOC_DAIFMT_NB_IF:
  388. /* Invert frame clock */
  389. val = SUN4I_DAI_FMT0_LRCLK_POLARITY_INVERTED |
  390. SUN4I_DAI_FMT0_BCLK_POLARITY_NORMAL;
  391. break;
  392. case SND_SOC_DAIFMT_NB_NF:
  393. /* Nothing to do for both normal cases */
  394. val = SUN4I_DAI_FMT0_BCLK_POLARITY_NORMAL |
  395. SUN4I_DAI_FMT0_LRCLK_POLARITY_NORMAL;
  396. break;
  397. default:
  398. return -EINVAL;
  399. }
  400.  
  401. regmap_update_bits(sdai->regmap, SUN4I_DAI_FMT0_REG,
  402. SUN4I_DAI_FMT0_BCLK_POLARITY_MASK |
  403. SUN4I_DAI_FMT0_LRCLK_POLARITY_MASK,
  404. val);
  405.  
  406. /* DAI clock master masks */
  407. switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
  408. case SND_SOC_DAIFMT_CBS_CFS:
  409. /* BCLK and LRCLK master */
  410. val = SUN4I_DAI_CTRL_MODE_MASTER;
  411. break;
  412. case SND_SOC_DAIFMT_CBM_CFM:
  413. /* BCLK and LRCLK slave */
  414. val = SUN4I_DAI_CTRL_MODE_SLAVE;
  415. break;
  416. default:
  417. return -EINVAL;
  418. }
  419.  
  420. regmap_update_bits(sdai->regmap, SUN4I_DAI_CTRL_REG,
  421. SUN4I_DAI_CTRL_MODE_MASK,
  422. val);
  423.  
  424. /* Set significant bits in our FIFOs */
  425. regmap_update_bits(sdai->regmap, SUN4I_DAI_FIFO_CTRL_REG,
  426. SUN4I_DAI_FIFO_CTRL_TX_MODE_MASK |
  427. SUN4I_DAI_FIFO_CTRL_RX_MODE_MASK,
  428. SUN4I_DAI_FIFO_CTRL_TX_MODE(1) |
  429. SUN4I_DAI_FIFO_CTRL_RX_MODE(1));
  430. return 0;
  431. }
  432.  
  433. static void sun4i_dai_start_capture(struct sun4i_dai *sdai)
  434. {
  435. /* Flush RX FIFO */
  436. regmap_update_bits(sdai->regmap, SUN4I_DAI_FIFO_CTRL_REG,
  437. SUN4I_DAI_FIFO_CTRL_FLUSH_RX,
  438. SUN4I_DAI_FIFO_CTRL_FLUSH_RX);
  439.  
  440. /* Clear RX counter */
  441. regmap_write(sdai->regmap, SUN4I_DAI_RX_CNT_REG, 0);
  442.  
  443. /* Enable RX Block */
  444. regmap_update_bits(sdai->regmap, SUN4I_DAI_CTRL_REG,
  445. SUN4I_DAI_CTRL_RX_EN,
  446. SUN4I_DAI_CTRL_RX_EN);
  447.  
  448. /* Enable RX DRQ */
  449. regmap_update_bits(sdai->regmap, SUN4I_DAI_DMA_INT_CTRL_REG,
  450. SUN4I_DAI_DMA_INT_CTRL_RX_DRQ_EN,
  451. SUN4I_DAI_DMA_INT_CTRL_RX_DRQ_EN);
  452. }
  453.  
  454. static void sun4i_dai_start_playback(struct sun4i_dai *sdai)
  455. {
  456. /* Flush TX FIFO */
  457. regmap_update_bits(sdai->regmap, SUN4I_DAI_FIFO_CTRL_REG,
  458. SUN4I_DAI_FIFO_CTRL_FLUSH_TX,
  459. SUN4I_DAI_FIFO_CTRL_FLUSH_TX);
  460.  
  461. /* Clear TX counter */
  462. regmap_write(sdai->regmap, SUN4I_DAI_TX_CNT_REG, 0);
  463.  
  464. /* Enable TX Block */
  465. regmap_update_bits(sdai->regmap, SUN4I_DAI_CTRL_REG,
  466. SUN4I_DAI_CTRL_TX_EN,
  467. SUN4I_DAI_CTRL_TX_EN);
  468.  
  469. /* Set FIFO Level */
  470. regmap_update_bits(sdai->regmap, SUN4I_DAI_FIFO_CTRL_REG,
  471. SUN4I_DAI_FIFO_CTRL_TXTL_MASK,
  472. SUN4I_DAI_FIFO_CTRL_TXTL(0x60));
  473.  
  474. /* Enable TX DRQ */
  475. regmap_update_bits(sdai->regmap, SUN4I_DAI_DMA_INT_CTRL_REG,
  476. SUN4I_DAI_DMA_INT_CTRL_TX_DRQ_EN,
  477. SUN4I_DAI_DMA_INT_CTRL_TX_DRQ_EN);
  478. }
  479.  
  480. static void sun4i_dai_stop_capture(struct sun4i_dai *sdai)
  481. {
  482. /* Disable RX Block */
  483. regmap_update_bits(sdai->regmap, SUN4I_DAI_CTRL_REG,
  484. SUN4I_DAI_CTRL_RX_EN,
  485. 0);
  486.  
  487. /* Disable RX DRQ */
  488. regmap_update_bits(sdai->regmap, SUN4I_DAI_DMA_INT_CTRL_REG,
  489. SUN4I_DAI_DMA_INT_CTRL_RX_DRQ_EN,
  490. 0);
  491. }
  492.  
  493. static void sun4i_dai_stop_playback(struct sun4i_dai *sdai)
  494. {
  495. /* Disable TX Block */
  496. regmap_update_bits(sdai->regmap, SUN4I_DAI_CTRL_REG,
  497. SUN4I_DAI_CTRL_TX_EN,
  498. 0);
  499.  
  500. /* Disable TX DRQ */
  501. regmap_update_bits(sdai->regmap, SUN4I_DAI_DMA_INT_CTRL_REG,
  502. SUN4I_DAI_DMA_INT_CTRL_TX_DRQ_EN,
  503. 0);
  504. }
  505.  
  506. static int sun4i_dai_trigger(struct snd_pcm_substream *substream, int cmd,
  507. struct snd_soc_dai *dai)
  508. {
  509. struct sun4i_dai *sdai = snd_soc_dai_get_drvdata(dai);
  510.  
  511. switch (cmd) {
  512. case SNDRV_PCM_TRIGGER_START:
  513. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  514. case SNDRV_PCM_TRIGGER_RESUME:
  515. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  516. sun4i_dai_start_playback(sdai);
  517. else
  518. sun4i_dai_start_capture(sdai);
  519. break;
  520.  
  521. case SNDRV_PCM_TRIGGER_STOP:
  522. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  523. case SNDRV_PCM_TRIGGER_SUSPEND:
  524. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  525. sun4i_dai_stop_playback(sdai);
  526. else
  527. sun4i_dai_stop_capture(sdai);
  528. break;
  529.  
  530. default:
  531. return -EINVAL;
  532. }
  533. {
  534. /* COOPS DEBUGGING FOR NOW */
  535. struct platform_device *pdev = sdai->pdev;
  536. u32 reg_val = 0;
  537.  
  538. dev_err(&pdev->dev,
  539. "Command State %d Audio Clock is %lu\n", cmd, clk_get_rate(sdai->mod_clk));
  540. regmap_read(sdai->regmap, SUN4I_DAI_CTRL_REG, &reg_val);
  541. dev_err(&pdev->dev,
  542. "SUN4I_DAI_CTRL_REG 0x%x\n", reg_val);
  543. regmap_read(sdai->regmap, SUN4I_DAI_FMT0_REG, &reg_val);
  544. dev_err(&pdev->dev,
  545. "SUN4I_DAI_FMT0_REG 0x%x\n", reg_val);
  546. regmap_read(sdai->regmap, SUN4I_DAI_FMT1_REG, &reg_val);
  547. dev_err(&pdev->dev,
  548. "SUN4I_DAI_FMT1_REG 0x%x\n", reg_val);
  549. regmap_read(sdai->regmap, SUN4I_DAI_FIFO_CTRL_REG, &reg_val);
  550. dev_err(&pdev->dev,
  551. "SUN4I_DAI_FIFO_CTRL_REG 0x%x\n", reg_val);
  552. regmap_read(sdai->regmap, SUN4I_DAI_FIFO_STA_REG, &reg_val);
  553. dev_err(&pdev->dev,
  554. "SUN4I_DAI_FIFO_STA_REG 0x%x\n", reg_val);
  555. }
  556.  
  557. return 0;
  558. }
  559.  
  560. static int sun4i_dai_startup(struct snd_pcm_substream *substream,
  561. struct snd_soc_dai *dai)
  562. {
  563. struct sun4i_dai *sdai = snd_soc_dai_get_drvdata(dai);
  564.  
  565. return clk_prepare_enable(sdai->mod_clk);
  566. }
  567.  
  568. static void sun4i_dai_shutdown(struct snd_pcm_substream *substream,
  569. struct snd_soc_dai *dai)
  570. {
  571. struct sun4i_dai *sdai = snd_soc_dai_get_drvdata(dai);
  572.  
  573. return clk_disable_unprepare(sdai->mod_clk);
  574. }
  575.  
  576. static const struct snd_soc_dai_ops sun4i_dai_dai_ops = {
  577. .hw_params = sun4i_dai_hw_params,
  578. .set_fmt = sun4i_dai_set_fmt,
  579. .shutdown = sun4i_dai_shutdown,
  580. .startup = sun4i_dai_startup,
  581. .trigger = sun4i_dai_trigger,
  582. };
  583.  
  584. static int sun4i_dai_dai_probe(struct snd_soc_dai *dai)
  585. {
  586. struct sun4i_dai *sdai = snd_soc_dai_get_drvdata(dai);
  587.  
  588. /* Enable the whole hardware block */
  589. regmap_write(sdai->regmap, SUN4I_DAI_CTRL_REG,
  590. SUN4I_DAI_CTRL_GL_EN);
  591.  
  592. snd_soc_dai_init_dma_data(dai, &sdai->playback_dma_data,
  593. &sdai->capture_dma_data);
  594.  
  595. snd_soc_dai_set_drvdata(dai, sdai);
  596.  
  597. return 0;
  598. }
  599.  
  600. #define SUN4I_RATES SNDRV_PCM_RATE_8000_192000
  601.  
  602. #define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
  603. SNDRV_PCM_FMTBIT_S24_LE)
  604.  
  605. static struct snd_soc_dai_driver sun4i_dai_dai = {
  606. .probe = sun4i_dai_dai_probe,
  607. .playback = {
  608. .stream_name = "Playback",
  609. .channels_min = 2,
  610. .channels_max = 2,
  611. .rates = SUN4I_RATES,
  612. .formats = SUN4I_FORMATS,
  613. },
  614. .capture = {
  615. .stream_name = "Capture",
  616. .channels_min = 2,
  617. .channels_max = 2,
  618. .rates = SNDRV_PCM_RATE_8000_192000,
  619. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  620. },
  621. .ops = &sun4i_dai_dai_ops,
  622. .symmetric_rates = 1,
  623. };
  624.  
  625. static const struct snd_soc_component_driver sun4i_dai_component = {
  626. .name = "sun4i-dai",
  627. };
  628.  
  629. static const struct regmap_config sun4i_dai_regmap_config = {
  630. .reg_bits = 32,
  631. .reg_stride = 4,
  632. .val_bits = 32,
  633. .max_register = SUN4I_DAI_RX_CHAN_MAP_REG,
  634. };
  635.  
  636. static int sun4i_dai_probe(struct platform_device *pdev)
  637. {
  638. struct sun4i_dai *sdai;
  639. struct resource *res;
  640. void __iomem *regs;
  641. int irq, ret;
  642.  
  643. dev_dbg(&pdev->dev, "Entered %s\n", __func__);
  644.  
  645. sdai = devm_kzalloc(&pdev->dev, sizeof(*sdai), GFP_KERNEL);
  646. if (!sdai)
  647. return -ENOMEM;
  648.  
  649. sdai->pdev = pdev;
  650. platform_set_drvdata(pdev, sdai);
  651.  
  652. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  653. regs = devm_ioremap_resource(&pdev->dev, res);
  654. if (IS_ERR(regs)) {
  655. dev_err(&pdev->dev, "Can't request IO region\n");
  656. return PTR_ERR(regs);
  657. }
  658.  
  659. irq = platform_get_irq(pdev, 0);
  660. if (irq < 0) {
  661. dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
  662. return irq;
  663. }
  664.  
  665. sdai->bus_clk = devm_clk_get(&pdev->dev, "apb");
  666. if (IS_ERR(sdai->bus_clk)) {
  667. dev_err(&pdev->dev, "Can't get our bus clock\n");
  668. return PTR_ERR(sdai->bus_clk);
  669. }
  670. clk_prepare_enable(sdai->bus_clk);
  671.  
  672. sdai->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
  673. &sun4i_dai_regmap_config);
  674. if (IS_ERR(sdai->regmap)) {
  675. dev_err(&pdev->dev, "Regmap initialisation failed\n");
  676. ret = PTR_ERR(sdai->regmap);
  677. goto err_disable_clk;
  678. };
  679.  
  680. sdai->mod_clk = devm_clk_get(&pdev->dev, "dai");
  681. if (IS_ERR(sdai->mod_clk)) {
  682. dev_err(&pdev->dev, "Can't get our mod clock\n");
  683. ret = PTR_ERR(sdai->mod_clk);
  684. goto err_disable_clk;
  685. }
  686.  
  687. sdai->playback_dma_data.addr = res->start + SUN4I_DAI_FIFO_TX_REG;
  688. sdai->playback_dma_data.maxburst = 4;
  689. sdai->capture_dma_data.addr = res->start + SUN4I_DAI_FIFO_RX_REG;
  690. sdai->capture_dma_data.maxburst = 4;
  691.  
  692. ret = devm_snd_soc_register_component(&pdev->dev,
  693. &sun4i_dai_component,
  694. &sun4i_dai_dai, 1);
  695. if (ret) {
  696. dev_err(&pdev->dev, "Could not register DAI\n");
  697. goto err_disable_clk;
  698. }
  699.  
  700. ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
  701. if (ret) {
  702. dev_err(&pdev->dev, "Could not register PCM\n");
  703. goto err_disable_clk;
  704. }
  705.  
  706. return 0;
  707.  
  708. err_disable_clk:
  709. clk_disable_unprepare(sdai->bus_clk);
  710. return ret;
  711. }
  712.  
  713. static int sun4i_dai_remove(struct platform_device *pdev)
  714. {
  715. struct sun4i_dai *sdai = platform_get_drvdata(pdev);
  716.  
  717. snd_dmaengine_pcm_unregister(&pdev->dev);
  718. clk_disable_unprepare(sdai->bus_clk);
  719.  
  720. return 0;
  721. }
  722.  
  723. static const struct of_device_id sun4i_dai_match[] = {
  724. { .compatible = "allwinner,sun4i-a10-dai", },
  725. {}
  726. };
  727. MODULE_DEVICE_TABLE(of, sun4i_dai_match);
  728.  
  729. static struct platform_driver sun4i_dai_driver = {
  730. .probe = sun4i_dai_probe,
  731. .remove = sun4i_dai_remove,
  732. .driver = {
  733. .name = "sun4i-dai",
  734. .of_match_table = sun4i_dai_match,
  735. },
  736. };
  737. module_platform_driver(sun4i_dai_driver);
  738.  
  739. MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
  740. MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
  741. MODULE_DESCRIPTION("Allwinner A10 DAI driver");
  742. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement