2 * rk29_i2s.c -- ALSA SoC ROCKCHIP IIS Audio Layer Platform driver
4 * Driver for rockchip iis audio
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
14 #include <linux/init.h>
15 #include <linux/module.h>
16 #include <linux/interrupt.h>
17 #include <linux/device.h>
18 #include <linux/delay.h>
19 #include <linux/clk.h>
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 #include <sound/pcm_params.h>
25 #include <sound/initval.h>
26 #include <sound/soc.h>
29 #include <mach/hardware.h>
30 #include <mach/board.h>
31 #include <mach/rk29_iomap.h>
32 #include <mach/rk29-dma-pl330.h>
33 #include <mach/iomux.h>
40 #define I2S_DBG(x...) printk(KERN_INFO x)
42 #define I2S_DBG(x...) do { } while (0)
45 #define pheadi2s ((pI2S_REG)(i2s->regs))
49 struct rk29_i2s_info {
60 struct rockchip_pcm_dma_params *dma_playback;
61 struct rockchip_pcm_dma_params *dma_capture;
68 static struct rk29_dma_client rk29_dma_client_out = {
69 .name = "I2S PCM Stereo Out"
72 static struct rk29_dma_client rk29_dma_client_in = {
73 .name = "I2S PCM Stereo In"
76 static inline struct rk29_i2s_info *to_info(struct snd_soc_dai *cpu_dai)
78 return cpu_dai->private_data;
81 static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_out[MAX_I2S];
82 static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_in[MAX_I2S];
83 static struct rk29_i2s_info rk29_i2s[MAX_I2S];
85 struct snd_soc_dai rk29_i2s_dai[MAX_I2S];
86 EXPORT_SYMBOL_GPL(rk29_i2s_dai);
89 static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_out[MAX_I2S] = {
91 .client = &rk29_dma_client_out,
92 .channel = DMACH_I2S_2CH_TX, ///0, //DMACH_I2S_OUT,
93 .dma_addr = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF,
97 .client = &rk29_dma_client_out,
98 .channel = DMACH_I2S_8CH_TX, ///0, //DMACH_I2S_OUT,
99 .dma_addr = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF,
104 static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_in[MAX_I2S] = {
106 .client = &rk29_dma_client_in,
107 .channel = DMACH_I2S_2CH_RX, ///1, //DMACH_I2S_IN,
108 .dma_addr = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF,
112 .client = &rk29_dma_client_in,
113 .channel = DMACH_I2S_8CH_RX, ///1, //DMACH_I2S_IN,
114 .dma_addr = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF,
124 *Turn on or off the transmission path.
126 static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on)
128 u32 opr,xfer,fifosts;
130 I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
131 opr = readl(&(pheadi2s->I2S_DMACR));
132 xfer = readl(&(pheadi2s->I2S_XFER));
133 opr &= ~I2S_TRAN_DMA_ENABLE;
134 xfer &= ~I2S_TX_TRAN_START;
137 writel(opr, &(pheadi2s->I2S_DMACR));
138 writel(xfer, &(pheadi2s->I2S_XFER));
141 opr |= I2S_TRAN_DMA_ENABLE;
142 xfer |= I2S_TX_TRAN_START;
143 writel(opr, &(pheadi2s->I2S_DMACR));
144 writel(xfer, &(pheadi2s->I2S_XFER));
148 writel(opr, &(pheadi2s->I2S_DMACR));
149 writel(xfer, &(pheadi2s->I2S_XFER));
153 static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on)
155 u32 opr,xfer,fifosts;
157 I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
159 opr = readl(&(pheadi2s->I2S_DMACR));
160 xfer = readl(&(pheadi2s->I2S_XFER));
162 opr &= ~I2S_RECE_DMA_ENABLE;
163 xfer &= ~I2S_RX_TRAN_START;
167 writel(opr, &(pheadi2s->I2S_DMACR));
168 writel(xfer, &(pheadi2s->I2S_XFER));
171 opr |= I2S_RECE_DMA_ENABLE;
172 xfer |= I2S_RX_TRAN_START;
173 writel(opr, &(pheadi2s->I2S_DMACR));
174 writel(xfer, &(pheadi2s->I2S_XFER));
178 writel(opr, &(pheadi2s->I2S_DMACR));
179 writel(xfer, &(pheadi2s->I2S_XFER));
184 * Set Rockchip I2S DAI format
186 static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
189 struct rk29_i2s_info *i2s = to_info(cpu_dai);
192 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
194 tx_ctl = readl(&(pheadi2s->I2S_TXCR));
196 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
197 case SND_SOC_DAIFMT_CBM_CFM:
198 tx_ctl &= ~I2S_MODE_MASK;
199 tx_ctl |= I2S_MASTER_MODE;
201 case SND_SOC_DAIFMT_CBS_CFS:
202 tx_ctl &= ~I2S_MODE_MASK;
203 tx_ctl |= I2S_SLAVE_MODE;
206 I2S_DBG("unknwon master/slave format\n");
210 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
211 case SND_SOC_DAIFMT_RIGHT_J:
212 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
213 tx_ctl |= I2S_BUS_MODE_RSJM;
215 case SND_SOC_DAIFMT_LEFT_J:
216 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
217 tx_ctl |= I2S_BUS_MODE_LSJM;
219 case SND_SOC_DAIFMT_I2S:
220 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
221 tx_ctl |= I2S_BUS_MODE_NOR;
224 I2S_DBG("Unknown data format\n");
227 I2S_DBG("Enter::%s----%d, I2S_TXCR=0x%X\n",__FUNCTION__,__LINE__,tx_ctl);
228 writel(tx_ctl, &(pheadi2s->I2S_TXCR));
229 rx_ctl = tx_ctl & 0x00007FFF;
230 writel(rx_ctl, &(pheadi2s->I2S_RXCR));
234 static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
235 struct snd_pcm_hw_params *params, struct snd_soc_dai *socdai)
237 struct snd_soc_pcm_runtime *rtd = substream->private_data;
238 struct snd_soc_dai_link *dai = rtd->dai;
239 struct rk29_i2s_info *i2s = to_info(dai->cpu_dai);
242 I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
243 /*by Vincent Hsiung for EQ Vol Change*/
244 #define HW_PARAMS_FLAG_EQVOL_ON 0x21
245 #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
246 if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
251 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
252 dai->cpu_dai->dma_data = i2s->dma_playback;
254 dai->cpu_dai->dma_data = i2s->dma_capture;
256 /* Working copies of register */
257 iismod = readl(&(pheadi2s->I2S_TXCR));
258 //iismod &= (~((1<<5)-1));
259 switch (params_format(params)) {
260 case SNDRV_PCM_FORMAT_S8:
261 iismod |= SAMPLE_DATA_8bit;
263 case SNDRV_PCM_FORMAT_S16_LE:
264 iismod |= I2S_DATA_WIDTH(15);
266 case SNDRV_PCM_FORMAT_S20_3LE:
267 iismod |= I2S_DATA_WIDTH(19);
269 case SNDRV_PCM_FORMAT_S24_LE:
270 iismod |= I2S_DATA_WIDTH(23);
272 case SNDRV_PCM_FORMAT_S32_LE:
273 iismod |= I2S_DATA_WIDTH(31);
276 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
277 iismod |= I2S_MASTER_MODE;
280 #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
281 iismod |= I2S_SLAVE_MODE;
284 writel((16<<24) |(16<<18)|(16<<12)|(16<<6)|16, &(pheadi2s->I2S_FIFOLR));
286 I2S_DBG("Enter %s, %d I2S_TXCR=0x%08X\n", __func__, __LINE__, iismod);
287 writel(iismod, &(pheadi2s->I2S_TXCR));
288 iismod = iismod & 0x00007FFF;
289 writel(iismod, &(pheadi2s->I2S_RXCR));
294 static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
297 struct snd_soc_pcm_runtime *rtd = substream->private_data;
298 struct rk29_i2s_info *i2s = to_info(rtd->dai->cpu_dai);
300 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
303 case SNDRV_PCM_TRIGGER_START:
304 case SNDRV_PCM_TRIGGER_RESUME:
305 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
306 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
307 rockchip_snd_rxctrl(i2s, 1);
309 rockchip_snd_txctrl(i2s, 1);
311 case SNDRV_PCM_TRIGGER_STOP:
312 case SNDRV_PCM_TRIGGER_SUSPEND:
313 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
314 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
315 rockchip_snd_rxctrl(i2s, 0);
317 rockchip_snd_txctrl(i2s, 0);
327 * Set Rockchip Clock source
329 static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
330 int clk_id, unsigned int freq, int dir)
332 struct rk29_i2s_info *i2s;
334 i2s = to_info(cpu_dai);
336 I2S_DBG("Enter:%s, %d, i2s=0x%p, freq=%d\n", __FUNCTION__, __LINE__, i2s, freq);
337 /*add scu clk source and enable clk*/
338 clk_set_rate(i2s->iis_clk, freq);
343 * Set Rockchip Clock dividers
345 static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
348 struct rk29_i2s_info *i2s;
351 i2s = to_info(cpu_dai);
353 /*stereo mode MCLK/SCK=4*/
355 reg = readl(&(pheadi2s->I2S_TXCKR));
357 I2S_DBG("Enter:%s, %d, div_id=0x%08X, div=0x%08X\n", __FUNCTION__, __LINE__, div_id, div);
359 /*when i2s in master mode ,must set codec pll div*/
361 case ROCKCHIP_DIV_BCLK:
362 reg &= ~I2S_TX_SCLK_DIV_MASK;
363 reg |= I2S_TX_SCLK_DIV(div);
365 case ROCKCHIP_DIV_MCLK:
366 reg &= ~I2S_MCLK_DIV_MASK;
367 reg |= I2S_MCLK_DIV(div);
369 case ROCKCHIP_DIV_PRESCALER:
375 writel(reg, &(pheadi2s->I2S_TXCKR));
376 writel(reg, &(pheadi2s->I2S_RXCKR));
380 static int rockchip_set_sysclk(struct snd_soc_dai *cpu_dai,
381 int clk_id, unsigned int freq, int dir)
388 * To avoid duplicating clock code, allow machine driver to
389 * get the clockrate from here.
391 u32 rockchip_i2s_get_clockrate(void)
393 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
394 return 0; ///clk_get_rate(s3c24xx_i2s.iis_clk);
396 EXPORT_SYMBOL_GPL(rockchip_i2s_get_clockrate);
399 int rockchip_i2s_suspend(struct snd_soc_dai *cpu_dai)
401 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
406 int rockchip_i2s_resume(struct snd_soc_dai *cpu_dai)
408 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
413 #define rockchip_i2s_suspend NULL
414 #define rockchip_i2s_resume NULL
417 #define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
418 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
419 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
421 static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
422 .trigger = rockchip_i2s_trigger,
423 .hw_params = rockchip_i2s_hw_params,
424 .set_fmt = rockchip_i2s_set_fmt,
425 .set_clkdiv = rockchip_i2s_set_clkdiv,
426 .set_sysclk = rockchip_i2s_set_sysclk,
429 static int rockchip_i2s_dai_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
431 I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
435 rk29_mux_api_set(GPIO2D0_I2S0CLK_MIIRXCLKIN_NAME, GPIO2H_I2S0_CLK);
436 rk29_mux_api_set(GPIO2D1_I2S0SCLK_MIICRS_NAME, GPIO2H_I2S0_SCLK);
437 rk29_mux_api_set(GPIO2D2_I2S0LRCKRX_MIITXERR_NAME, GPIO2H_I2S0_LRCK_RX);
438 rk29_mux_api_set(GPIO2D3_I2S0SDI_MIICOL_NAME, GPIO2H_I2S0_SDI);
439 rk29_mux_api_set(GPIO2D4_I2S0SDO0_MIIRXD2_NAME, GPIO2H_I2S0_SDO0);
440 rk29_mux_api_set(GPIO2D5_I2S0SDO1_MIIRXD3_NAME, GPIO2H_I2S0_SDO1);
441 rk29_mux_api_set(GPIO2D6_I2S0SDO2_MIITXD2_NAME, GPIO2H_I2S0_SDO2);
442 rk29_mux_api_set(GPIO2D7_I2S0SDO3_MIITXD3_NAME, GPIO2H_I2S0_SDO3);
444 rk29_mux_api_set(GPIO4D6_I2S0LRCKTX0_NAME, GPIO4H_I2S0_LRCK_TX0);
445 rk29_mux_api_set(GPIO4D7_I2S0LRCKTX1_NAME, GPIO4H_I2S0_LRCK_TX1);
448 rk29_mux_api_set(GPIO3A0_I2S1CLK_NAME, GPIO3L_I2S1_CLK);
449 rk29_mux_api_set(GPIO3A1_I2S1SCLK_NAME, GPIO3L_I2S1_SCLK);
450 rk29_mux_api_set(GPIO3A2_I2S1LRCKRX_NAME, GPIO3L_I2S1_LRCK_RX);
451 rk29_mux_api_set(GPIO3A3_I2S1SDI_NAME, GPIO3L_I2S1_SDI);
452 rk29_mux_api_set(GPIO3A4_I2S1SDO_NAME, GPIO3L_I2S1_SDO);
453 rk29_mux_api_set(GPIO3A5_I2S1LRCKTX_NAME, GPIO3L_I2S1_LRCK_TX);
456 I2S_DBG("Enter:%s, %d, Error For DevId!!!", __FUNCTION__, __LINE__);
462 static int rk29_i2s_probe(struct platform_device *pdev,
463 struct snd_soc_dai *dai,
464 struct rk29_i2s_info *i2s,
467 struct device *dev = &pdev->dev;
468 struct resource *res;
470 I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
474 /* record our i2s structure for later use in the callbacks */
475 dai->private_data = i2s;
478 res = platform_get_resource(pdev,
482 dev_err(dev, "Unable to get register resource\n");
486 if (!request_mem_region(res->start, resource_size(res),
488 dev_err(dev, "Unable to request register region\n");
495 i2s->regs = ioremap(base, (res->end - res->start) + 1); ////res));
496 if (i2s->regs == NULL) {
497 dev_err(dev, "cannot ioremap registers\n");
501 i2s->iis_pclk = clk_get(dev, "i2s");
502 if (IS_ERR(i2s->iis_pclk)) {
503 dev_err(dev, "failed to get iis_clock\n");
508 clk_enable(i2s->iis_pclk);
510 /* Mark ourselves as in TXRX mode so we can run through our cleanup
511 * process without warnings. */
512 rockchip_snd_txctrl(i2s, 0);
513 rockchip_snd_rxctrl(i2s, 0);
518 static int rk29_i2s_register_dai(struct snd_soc_dai *dai)
520 struct snd_soc_dai_ops *ops = dai->ops;
522 ops->trigger = rockchip_i2s_trigger;
524 ops->hw_params = rockchip_i2s_hw_params;
525 ops->set_fmt = rockchip_i2s_set_fmt;
526 ops->set_clkdiv = rockchip_i2s_set_clkdiv;
527 ops->set_sysclk = rockchip_i2s_set_sysclk;
529 dai->suspend = rockchip_i2s_suspend;
530 dai->resume = rockchip_i2s_resume;
532 return snd_soc_register_dai(dai);
535 static int __devinit rockchip_i2s_probe(struct platform_device *pdev)
537 struct rk29_i2s_info *i2s;
538 struct snd_soc_dai *dai;
541 I2S_DBG("Enter %s, %d pdev->id = %d >>>>>>>>>>>\n", __func__, __LINE__, pdev->id);
543 if(pdev->id >= MAX_I2S) {
544 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
548 i2s = &rk29_i2s[pdev->id];
549 dai = &rk29_i2s_dai[pdev->id];
550 dai->dev = &pdev->dev;
551 dai->name = "rk29_i2s";
553 dai->symmetric_rates = 1;
555 dai->playback.channels_min = 2;
556 dai->playback.channels_max = 8;
558 dai->playback.channels_min = 2;
559 dai->playback.channels_max = 2;
561 dai->playback.rates = ROCKCHIP_I2S_RATES;
562 dai->playback.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE;
563 dai->capture.channels_min = 2;
564 dai->capture.channels_max = 2;
565 dai->capture.rates = SNDRV_PCM_RATE_44100;//ROCKCHIP_I2S_RATES;
566 dai->capture.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE;
567 dai->probe = rockchip_i2s_dai_probe;
568 dai->ops = &rockchip_i2s_dai_ops;
570 //i2s->feature |= S3C_FEATURE_CDCLKCON;
572 i2s->dma_capture = &rk29_i2s_pcm_stereo_in[pdev->id];
573 i2s->dma_playback = &rk29_i2s_pcm_stereo_out[pdev->id];
576 i2s->dma_capture->channel = DMACH_I2S_2CH_RX;
577 i2s->dma_capture->dma_addr = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF;
578 i2s->dma_playback->channel = DMACH_I2S_2CH_TX;
579 i2s->dma_playback->dma_addr = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF;
581 i2s->dma_capture->channel = DMACH_I2S_8CH_RX;
582 i2s->dma_capture->dma_addr = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF;
583 i2s->dma_playback->channel = DMACH_I2S_8CH_TX;
584 i2s->dma_playback->dma_addr = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF;
587 i2s->dma_capture->client = &rk29_dma_client_in;
588 i2s->dma_capture->dma_size = 4;
589 i2s->dma_playback->client = &rk29_dma_client_out;
590 i2s->dma_playback->dma_size = 4;
592 i2s->iis_clk = clk_get(&pdev->dev, "i2s");
593 I2S_DBG("Enter:%s, %d, iis_clk=%d\n", __FUNCTION__, __LINE__, i2s->iis_clk);
594 if (IS_ERR(i2s->iis_clk)) {
595 dev_err(&pdev->dev, "failed to get i2s clk\n");
596 ret = PTR_ERR(i2s->iis_clk);
600 clk_enable(i2s->iis_clk);
601 clk_set_rate(i2s->iis_clk, 11289600);
602 ret = rk29_i2s_probe(pdev, dai, i2s, 0);
606 ret = rk29_i2s_register_dai(dai);
613 /* Not implemented for I2Sv2 core yet */
615 clk_put(i2s->iis_clk);
621 static int __devexit rockchip_i2s_remove(struct platform_device *pdev)
623 snd_soc_unregister_dai(&rk29_i2s_dai);
628 static struct platform_driver rockchip_i2s_driver = {
629 .probe = rockchip_i2s_probe,
630 .remove = __devexit_p(rockchip_i2s_remove),
633 .owner = THIS_MODULE,
637 static int __init rockchip_i2s_init(void)
639 I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
641 return platform_driver_register(&rockchip_i2s_driver);
643 module_init(rockchip_i2s_init);
645 static void __exit rockchip_i2s_exit(void)
647 platform_driver_unregister(&rockchip_i2s_driver);
649 module_exit(rockchip_i2s_exit);
651 /* Module information */
652 MODULE_AUTHOR("rockchip");
653 MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface");
654 MODULE_LICENSE("GPL");