2 * rk30_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>
20 #include <linux/version.h>
22 #include <linux/of_gpio.h>
23 #include <linux/clk.h>
25 #include <linux/platform_device.h>
26 #include <linux/pm_runtime.h>
27 #include <linux/regmap.h>
28 #include <linux/slab.h>
31 #include <sound/core.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/initval.h>
35 #include <sound/soc.h>
36 #include <sound/dmaengine_pcm.h>
39 #include <linux/spinlock.h>
45 #define I2S_DBG(x...) printk(KERN_INFO x)
47 #define I2S_DBG(x...) do { } while (0)
50 #define pheadi2s ((pI2S_REG)(i2s->regs))
54 static DEFINE_SPINLOCK(lock);
56 struct rk30_i2s_info {
59 struct clk *i2s_clk;// i2s clk ,is bclk lrck
60 struct clk *i2s_mclk;//i2s mclk,rk32xx can different i2s clk.
62 struct snd_dmaengine_dai_dma_data capture_dma_data;
63 struct snd_dmaengine_dai_dma_data playback_dma_data;
65 bool i2s_tx_status;//active = true;
69 #define I2S_CLR_ERROR_COUNT 10// check I2S_CLR reg
70 static struct rk30_i2s_info *rk30_i2s;
72 #if defined (CONFIG_RK_HDMI) && defined (CONFIG_SND_RK_SOC_HDMI_I2S)
73 extern int hdmi_get_hotplug(void);
75 #define hdmi_get_hotplug() 0
78 static inline struct rk30_i2s_info *to_info(struct snd_soc_dai *dai)
80 return snd_soc_dai_get_drvdata(dai);
84 *Turn on or off the transmission path.
86 static void rockchip_snd_txctrl(struct rk30_i2s_info *i2s, int on)
90 bool is_need_delay = false;
91 int clr_error_count = I2S_CLR_ERROR_COUNT;
93 spin_lock_irqsave(&lock, flags);
95 opr = readl(&(pheadi2s->I2S_DMACR));
96 xfer = readl(&(pheadi2s->I2S_XFER));
97 clr = readl(&(pheadi2s->I2S_CLR));
99 I2S_DBG("rockchip_snd_txctrl: %s\n", on ? "on" : "off");
102 if ((opr & I2S_TRAN_DMA_ENABLE) == 0) {
103 opr |= I2S_TRAN_DMA_ENABLE;
104 writel(opr, &(pheadi2s->I2S_DMACR));
107 if ((xfer & I2S_TX_TRAN_START) == 0 || (xfer & I2S_RX_TRAN_START) == 0) {
108 xfer |= I2S_TX_TRAN_START;
109 xfer |= I2S_RX_TRAN_START;
110 writel(xfer, &(pheadi2s->I2S_XFER));
113 i2s->i2s_tx_status = 1;
116 i2s->i2s_tx_status = 0;
117 opr &= ~I2S_TRAN_DMA_ENABLE;
118 writel(opr, &(pheadi2s->I2S_DMACR));
120 if (i2s->i2s_rx_status == 0 && hdmi_get_hotplug() == 0) {
121 xfer &= ~I2S_TX_TRAN_START;
122 xfer &= ~I2S_RX_TRAN_START;
123 writel(xfer, &(pheadi2s->I2S_XFER));
127 writel(clr, &(pheadi2s->I2S_CLR));
129 is_need_delay = true;
131 I2S_DBG("rockchip_snd_txctrl: stop xfer\n");
135 spin_unlock_irqrestore(&lock, flags);
138 while(readl(&(pheadi2s->I2S_CLR)) && clr_error_count){
141 if(clr_error_count == 0)
142 printk("%s: i2s clr reg warning =%d",__FUNCTION__,readl(&(pheadi2s->I2S_CLR)));
147 static void rockchip_snd_rxctrl(struct rk30_i2s_info *i2s, int on)
151 bool is_need_delay = false;
152 int clr_error_count = I2S_CLR_ERROR_COUNT;
154 spin_lock_irqsave(&lock, flags);
156 opr = readl(&(pheadi2s->I2S_DMACR));
157 xfer = readl(&(pheadi2s->I2S_XFER));
158 clr = readl(&(pheadi2s->I2S_CLR));
160 I2S_DBG("rockchip_snd_rxctrl: %s\n", on ? "on" : "off");
163 if ((opr & I2S_RECE_DMA_ENABLE) == 0) {
164 opr |= I2S_RECE_DMA_ENABLE;
165 writel(opr, &(pheadi2s->I2S_DMACR));
168 if ((xfer & I2S_TX_TRAN_START)==0 || (xfer & I2S_RX_TRAN_START) == 0) {
169 xfer |= I2S_RX_TRAN_START;
170 xfer |= I2S_TX_TRAN_START;
171 writel(xfer, &(pheadi2s->I2S_XFER));
174 i2s->i2s_rx_status = 1;
176 i2s->i2s_rx_status = 0;
178 opr &= ~I2S_RECE_DMA_ENABLE;
179 writel(opr, &(pheadi2s->I2S_DMACR));
181 if (i2s->i2s_tx_status == 0 && hdmi_get_hotplug() == 0) {
182 xfer &= ~I2S_RX_TRAN_START;
183 xfer &= ~I2S_TX_TRAN_START;
184 writel(xfer, &(pheadi2s->I2S_XFER));
188 writel(clr, &(pheadi2s->I2S_CLR));
190 is_need_delay = true;
192 I2S_DBG("rockchip_snd_rxctrl: stop xfer\n");
196 spin_unlock_irqrestore(&lock, flags);
199 while(readl(&(pheadi2s->I2S_CLR)) && clr_error_count){
202 if(clr_error_count == 0)
203 printk("%s: i2s clr reg warning =%d",__FUNCTION__,readl(&(pheadi2s->I2S_CLR)));
209 * Set Rockchip I2S DAI format
211 static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
214 struct rk30_i2s_info *i2s = to_info(cpu_dai);
216 u32 iis_ckr_value;//clock generation register
220 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
222 spin_lock_irqsave(&lock, flags);
224 tx_ctl = readl(&(pheadi2s->I2S_TXCR));
225 iis_ckr_value = readl(&(pheadi2s->I2S_CKR));
227 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
228 case SND_SOC_DAIFMT_CBM_CFM:
229 //Codec is master, so set cpu slave.
230 iis_ckr_value &= ~I2S_MODE_MASK;
231 iis_ckr_value |= I2S_SLAVE_MODE;
233 case SND_SOC_DAIFMT_CBS_CFS:
234 //Codec is slave, so set cpu master.
235 iis_ckr_value &= ~I2S_MODE_MASK;
236 iis_ckr_value |= I2S_MASTER_MODE;
239 I2S_DBG("unknwon master/slave format\n");
244 writel(iis_ckr_value, &(pheadi2s->I2S_CKR));
246 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
247 case SND_SOC_DAIFMT_RIGHT_J:
248 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
249 tx_ctl |= I2S_BUS_MODE_RSJM;
251 case SND_SOC_DAIFMT_LEFT_J:
252 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
253 tx_ctl |= I2S_BUS_MODE_LSJM;
255 case SND_SOC_DAIFMT_I2S:
256 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
257 tx_ctl |= I2S_BUS_MODE_NOR;
260 I2S_DBG("Unknown data format\n");
265 I2S_DBG("Enter::%s----%d, I2S_TXCR=0x%X\n",__FUNCTION__,__LINE__,tx_ctl);
267 writel(tx_ctl, &(pheadi2s->I2S_TXCR));
269 rx_ctl = tx_ctl & 0x00007FFF;
270 writel(rx_ctl, &(pheadi2s->I2S_RXCR));
274 spin_unlock_irqrestore(&lock, flags);
279 static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
280 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
282 struct rk30_i2s_info *i2s = to_info(dai);
287 I2S_DBG("Enter %s, %d \n", __func__, __LINE__);
289 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
290 dai->playback_dma_data = &i2s->playback_dma_data;
292 dai->capture_dma_data = &i2s->capture_dma_data;
294 spin_lock_irqsave(&lock, flags);
296 /* Working copies of register */
297 iismod = readl(&(pheadi2s->I2S_TXCR));
299 iismod &= (~((1<<5)-1));
300 switch (params_format(params)) {
301 case SNDRV_PCM_FORMAT_S8:
302 iismod |= SAMPLE_DATA_8bit;
304 case SNDRV_PCM_FORMAT_S16_LE:
305 iismod |= I2S_DATA_WIDTH(15);
307 case SNDRV_PCM_FORMAT_S20_3LE:
308 iismod |= I2S_DATA_WIDTH(19);
310 case SNDRV_PCM_FORMAT_S24_LE:
311 iismod |= I2S_DATA_WIDTH(23);
313 case SNDRV_PCM_FORMAT_S32_LE:
314 iismod |= I2S_DATA_WIDTH(31);
318 // writel((16<<24) |(16<<18)|(16<<12)|(16<<6)|16, &(pheadi2s->I2S_FIFOLR));
319 dmarc = readl(&(pheadi2s->I2S_DMACR));
321 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
322 dmarc = ((dmarc & 0xFFFFFE00) | 16);
324 dmarc = ((dmarc & 0xFE00FFFF) | 16<<16);
326 writel(dmarc, &(pheadi2s->I2S_DMACR));
328 I2S_DBG("Enter %s, %d I2S_TXCR=0x%08X\n", __func__, __LINE__, iismod);
330 writel(iismod, &(pheadi2s->I2S_TXCR));
332 iismod = iismod & 0x00007FFF;
333 writel(iismod, &(pheadi2s->I2S_RXCR));
335 spin_unlock_irqrestore(&lock, flags);
340 static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
342 struct rk30_i2s_info *i2s = to_info(dai);
345 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
348 case SNDRV_PCM_TRIGGER_START:
349 case SNDRV_PCM_TRIGGER_RESUME:
350 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
351 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
352 rockchip_snd_rxctrl(i2s, 1);
354 rockchip_snd_txctrl(i2s, 1);
356 case SNDRV_PCM_TRIGGER_SUSPEND:
357 case SNDRV_PCM_TRIGGER_STOP:
358 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
359 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
360 rockchip_snd_rxctrl(i2s, 0);
362 rockchip_snd_txctrl(i2s, 0);
373 * Set Rockchip I2S MCLK source
375 static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
376 int clk_id, unsigned int freq, int dir)
378 struct rk30_i2s_info *i2s = to_info(cpu_dai);
380 I2S_DBG("Enter:%s, %d, i2s=0x%p, freq=%d\n", __FUNCTION__, __LINE__, i2s, freq);
382 /*add scu clk source and enable clk*/
383 clk_set_rate(i2s->i2s_clk, freq);
388 * Set Rockchip Clock dividers
390 static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
393 struct rk30_i2s_info *i2s;
398 i2s = to_info(cpu_dai);
400 spin_lock_irqsave(&lock, flags);
402 //stereo mode MCLK/SCK=4
403 reg = readl(&(pheadi2s->I2S_CKR));
405 I2S_DBG("Enter:%s, %d, div_id=0x%08X, div=0x%08X\n", __FUNCTION__, __LINE__, div_id, div);
407 //when i2s in master mode ,must set codec pll div
409 case ROCKCHIP_DIV_BCLK:
410 reg &= ~I2S_TX_SCLK_DIV_MASK;
411 reg |= I2S_TX_SCLK_DIV(div);
412 reg &= ~I2S_RX_SCLK_DIV_MASK;
413 reg |= I2S_RX_SCLK_DIV(div);
415 case ROCKCHIP_DIV_MCLK:
416 reg &= ~I2S_MCLK_DIV_MASK;
417 reg |= I2S_MCLK_DIV(div);
419 case ROCKCHIP_DIV_PRESCALER:
425 writel(reg, &(pheadi2s->I2S_CKR));
428 spin_unlock_irqrestore(&lock, flags);
433 static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
434 .trigger = rockchip_i2s_trigger,
435 .hw_params = rockchip_i2s_hw_params,
436 .set_fmt = rockchip_i2s_set_fmt,
437 .set_clkdiv = rockchip_i2s_set_clkdiv,
438 .set_sysclk = rockchip_i2s_set_sysclk,
441 #define ROCKCHIP_I2S_STEREO_RATES SNDRV_PCM_RATE_8000_96000
442 #define ROCKCHIP_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
443 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
445 struct snd_soc_dai_driver rockchip_i2s_dai[] = {
447 .name = "rockchip-i2s.0",
452 .rates = ROCKCHIP_I2S_STEREO_RATES,
453 .formats = ROCKCHIP_I2S_FORMATS,
458 .rates = ROCKCHIP_I2S_STEREO_RATES,
459 .formats = ROCKCHIP_I2S_FORMATS,
461 .ops = &rockchip_i2s_dai_ops,
462 .symmetric_rates = 1,
465 .name = "rockchip-i2s.1",
470 .rates = ROCKCHIP_I2S_STEREO_RATES,
471 .formats = ROCKCHIP_I2S_FORMATS,
476 .rates = ROCKCHIP_I2S_STEREO_RATES,
477 .formats = ROCKCHIP_I2S_FORMATS,
479 .ops = &rockchip_i2s_dai_ops,
480 .symmetric_rates = 1,
484 static const struct snd_soc_component_driver rockchip_i2s_component = {
485 .name = "rockchip-i2s",
489 static int rockchip_i2s_suspend_noirq(struct device *dev)
491 I2S_DBG("Enter %s, %d\n", __func__, __LINE__);
493 return pinctrl_select_state(dev->pins->p, dev->pins->sleep_state);
496 static int rockchip_i2s_resume_noirq(struct device *dev)
498 I2S_DBG("Enter %s, %d\n", __func__, __LINE__);
500 return pinctrl_select_state(dev->pins->p, dev->pins->default_state);
503 #define rockchip_i2s_suspend_noirq NULL
504 #define rockchip_i2s_resume_noirq NULL
507 static int rockchip_i2s_probe(struct platform_device *pdev)
509 struct device_node *node = pdev->dev.of_node;
510 struct rk30_i2s_info *i2s;
511 struct resource *mem, *memregion;
515 I2S_DBG("%s()\n", __FUNCTION__);
517 ret = of_property_read_u32(node, "i2s-id", &pdev->id);
519 dev_err(&pdev->dev, "%s() Can not read property: id\n", __FUNCTION__);
524 if(pdev->id >= MAX_I2S) {
525 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
530 i2s = devm_kzalloc(&pdev->dev, sizeof(struct rk30_i2s_info), GFP_KERNEL);
532 dev_err(&pdev->dev, "Can't allocate i2s info\n");
537 i2s->i2s_clk= clk_get(&pdev->dev, "i2s_clk");
538 if (IS_ERR(i2s->i2s_clk)) {
539 dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
540 ret = PTR_ERR(i2s->i2s_clk);
543 clk_set_rate(i2s->i2s_clk, 11289600);
544 clk_prepare_enable(i2s->i2s_clk);
546 i2s->i2s_mclk= clk_get(&pdev->dev, "i2s_mclk");
547 if(IS_ERR(i2s->i2s_mclk) ) {
548 printk("This platfrom have not i2s_mclk,no need to set i2s_mclk.\n");
550 clk_set_rate(i2s->i2s_mclk, 11289600);
551 clk_prepare_enable(i2s->i2s_mclk);
554 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
556 dev_err(&pdev->dev, "No memory resource\n");
561 memregion = devm_request_mem_region(&pdev->dev, mem->start,
562 resource_size(mem), "rockchip-i2s");
564 dev_err(&pdev->dev, "Memory region already claimed\n");
569 i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
571 dev_err(&pdev->dev, "ioremap failed\n");
576 regs_base = mem->start;
578 i2s->playback_dma_data.addr = regs_base + I2S_TXR_BUFF;
579 i2s->playback_dma_data.addr_width = 4;
580 i2s->playback_dma_data.maxburst = 1;
582 i2s->capture_dma_data.addr = regs_base + I2S_RXR_BUFF;
583 i2s->capture_dma_data.addr_width = 4;
584 i2s->capture_dma_data.maxburst = 1;
586 i2s->i2s_tx_status = false;
587 i2s->i2s_rx_status = false;
589 pm_runtime_enable(&pdev->dev);
590 if (!pm_runtime_enabled(&pdev->dev)) {
591 ret = rockchip_i2s_resume_noirq(&pdev->dev);
596 //set dev name to driver->name.id for sound card register
597 dev_set_name(&pdev->dev, "%s.%d", pdev->dev.driver->name, pdev->id);
599 ret = snd_soc_register_component(&pdev->dev, &rockchip_i2s_component,
600 &rockchip_i2s_dai[pdev->id], 1);
603 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
608 ret = rockchip_pcm_platform_register(&pdev->dev);
610 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
611 goto err_unregister_component;
614 /* Mark ourselves as in TXRX mode so we can run through our cleanup
615 * process without warnings. */
616 rockchip_snd_txctrl(i2s, 0);
617 rockchip_snd_rxctrl(i2s, 0);
619 dev_set_drvdata(&pdev->dev, i2s);
624 err_unregister_component:
625 snd_soc_unregister_component(&pdev->dev);
627 if (!pm_runtime_status_suspended(&pdev->dev))
628 rockchip_i2s_suspend_noirq(&pdev->dev);
630 pm_runtime_disable(&pdev->dev);
632 clk_put(i2s->i2s_clk);
638 static int rockchip_i2s_remove(struct platform_device *pdev)
640 rockchip_pcm_platform_unregister(&pdev->dev);
641 snd_soc_unregister_component(&pdev->dev);
647 static const struct of_device_id exynos_i2s_match[] = {
648 { .compatible = "rockchip-i2s"},
651 MODULE_DEVICE_TABLE(of, exynos_i2s_match);
654 static const struct dev_pm_ops rockchip_i2s_pm_ops = {
655 SET_RUNTIME_PM_OPS(rockchip_i2s_suspend_noirq,
656 rockchip_i2s_resume_noirq, NULL)
659 static struct platform_driver rockchip_i2s_driver = {
660 .probe = rockchip_i2s_probe,
661 .remove = rockchip_i2s_remove,
663 .name = "rockchip-i2s",
664 .owner = THIS_MODULE,
665 .of_match_table = of_match_ptr(exynos_i2s_match),
666 .pm = &rockchip_i2s_pm_ops,
669 module_platform_driver(rockchip_i2s_driver);
671 /* Module information */
672 MODULE_AUTHOR("rockchip");
673 MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface");
674 MODULE_LICENSE("GPL");
677 #ifdef CONFIG_PROC_FS
678 #include <linux/proc_fs.h>
679 #include <linux/seq_file.h>
680 static int proc_i2s_show(struct seq_file *s, void *v)
683 struct rk30_i2s_info *i2s = rk30_i2s;
685 printk("========Show I2S reg========\n");
687 printk("I2S_TXCR = 0x%08X\n", readl(&(pheadi2s->I2S_TXCR)));
688 printk("I2S_RXCR = 0x%08X\n", readl(&(pheadi2s->I2S_RXCR)));
689 printk("I2S_CKR = 0x%08X\n", readl(&(pheadi2s->I2S_CKR)));
690 printk("I2S_DMACR = 0x%08X\n", readl(&(pheadi2s->I2S_DMACR)));
691 printk("I2S_INTCR = 0x%08X\n", readl(&(pheadi2s->I2S_INTCR)));
692 printk("I2S_INTSR = 0x%08X\n", readl(&(pheadi2s->I2S_INTSR)));
693 printk("I2S_XFER = 0x%08X\n", readl(&(pheadi2s->I2S_XFER)));
695 printk("========Show I2S reg========\n");
697 writel(0x0000000F, &(pheadi2s->I2S_TXCR));
698 writel(0x0000000F, &(pheadi2s->I2S_RXCR));
699 writel(0x00071f1F, &(pheadi2s->I2S_CKR));
700 writel(0x001F0110, &(pheadi2s->I2S_DMACR));
701 writel(0x00000003, &(pheadi2s->I2S_XFER));
704 writel(0x5555aaaa, &(pheadi2s->I2S_TXDR));
710 static ssize_t i2s_reg_write(struct file *file,
711 const char __user *user_buf, size_t count, loff_t *ppos)
713 struct rk30_i2s_info *i2s=rk30_i2s;
720 buf_size = min(count, (sizeof(buf)-1));
721 if (copy_from_user(buf, user_buf, buf_size))
725 while (*start == ' ')
727 value = simple_strtoul(start, &start, 10);
729 printk("test --- freq = %ld ret=%d\n",value,clk_set_rate(i2s->i2s_clk, value));
733 static int proc_i2s_open(struct inode *inode, struct file *file)
735 return single_open(file, proc_i2s_show, NULL);
738 static const struct file_operations proc_i2s_fops = {
739 .open = proc_i2s_open,
741 .write = i2s_reg_write,
743 .release = single_release,
746 static int __init i2s_proc_init(void)
748 proc_create("i2s_reg", 0, NULL, &proc_i2s_fops);
751 late_initcall(i2s_proc_init);
752 #endif /* CONFIG_PROC_FS */