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/rockchip/cpu.h>
29 #include <linux/rockchip/cru.h>
30 #include <linux/rockchip/grf.h>
31 #include <linux/slab.h>
33 #include <sound/core.h>
34 #include <sound/pcm.h>
35 #include <sound/pcm_params.h>
36 #include <sound/initval.h>
37 #include <sound/soc.h>
38 #include <sound/dmaengine_pcm.h>
40 #include <linux/spinlock.h>
41 #include <linux/workqueue.h>
49 #define I2S_DBG(x...) printk(KERN_INFO x)
51 #define I2S_DBG(x...) do { } while (0)
54 #define pheadi2s ((pI2S_REG)(i2s->regs))
58 static DEFINE_SPINLOCK(lock);
60 struct rk30_i2s_info {
63 struct clk *i2s_clk;// i2s clk ,is bclk lrck
64 struct clk *i2s_mclk;//i2s mclk,rk32xx can different i2s clk.
66 struct snd_dmaengine_dai_dma_data capture_dma_data;
67 struct snd_dmaengine_dai_dma_data playback_dma_data;
69 bool i2s_tx_status;//active = true;
72 struct delayed_work clk_delayed_work;
76 #define I2S_CLR_ERROR_COUNT 10// check I2S_CLR reg
77 static struct rk30_i2s_info *rk30_i2s;
79 #if defined (CONFIG_RK_HDMI) && defined (CONFIG_SND_RK_SOC_HDMI_I2S)
80 extern int hdmi_get_hotplug(void);
82 #define hdmi_get_hotplug() 0
85 static inline struct rk30_i2s_info *to_info(struct snd_soc_dai *dai)
87 return snd_soc_dai_get_drvdata(dai);
91 *Turn on or off the transmission path.
93 static void rockchip_snd_txctrl(struct rk30_i2s_info *i2s, int on)
97 bool is_need_delay = false;
98 int clr_error_count = I2S_CLR_ERROR_COUNT;
100 spin_lock_irqsave(&lock, flags);
102 opr = readl(&(pheadi2s->I2S_DMACR));
103 xfer = readl(&(pheadi2s->I2S_XFER));
104 clr = readl(&(pheadi2s->I2S_CLR));
106 I2S_DBG("rockchip_snd_txctrl: %s\n", on ? "on" : "off");
109 if ((opr & I2S_TRAN_DMA_ENABLE) == 0) {
110 opr |= I2S_TRAN_DMA_ENABLE;
111 writel(opr, &(pheadi2s->I2S_DMACR));
114 if ((xfer & I2S_TX_TRAN_START) == 0 || (xfer & I2S_RX_TRAN_START) == 0) {
115 xfer |= I2S_TX_TRAN_START;
116 xfer |= I2S_RX_TRAN_START;
117 writel(xfer, &(pheadi2s->I2S_XFER));
120 i2s->i2s_tx_status = 1;
123 i2s->i2s_tx_status = 0;
124 opr &= ~I2S_TRAN_DMA_ENABLE;
125 writel(opr, &(pheadi2s->I2S_DMACR));
127 if (i2s->i2s_rx_status == 0 && hdmi_get_hotplug() == 0) {
128 xfer &= ~I2S_TX_TRAN_START;
129 xfer &= ~I2S_RX_TRAN_START;
130 writel(xfer, &(pheadi2s->I2S_XFER));
134 writel(clr, &(pheadi2s->I2S_CLR));
136 is_need_delay = true;
138 I2S_DBG("rockchip_snd_txctrl: stop xfer\n");
142 spin_unlock_irqrestore(&lock, flags);
145 while(readl(&(pheadi2s->I2S_CLR)) && clr_error_count){
148 if(clr_error_count == 0)
149 printk("%s: i2s clr reg warning =%d\n",__FUNCTION__,readl(&(pheadi2s->I2S_CLR)));
154 static void rockchip_snd_rxctrl(struct rk30_i2s_info *i2s, int on)
158 bool is_need_delay = false;
159 int clr_error_count = I2S_CLR_ERROR_COUNT;
161 spin_lock_irqsave(&lock, flags);
163 opr = readl(&(pheadi2s->I2S_DMACR));
164 xfer = readl(&(pheadi2s->I2S_XFER));
165 clr = readl(&(pheadi2s->I2S_CLR));
167 I2S_DBG("rockchip_snd_rxctrl: %s\n", on ? "on" : "off");
170 if ((opr & I2S_RECE_DMA_ENABLE) == 0) {
171 opr |= I2S_RECE_DMA_ENABLE;
172 writel(opr, &(pheadi2s->I2S_DMACR));
175 if ((xfer & I2S_TX_TRAN_START)==0 || (xfer & I2S_RX_TRAN_START) == 0) {
176 xfer |= I2S_RX_TRAN_START;
177 xfer |= I2S_TX_TRAN_START;
178 writel(xfer, &(pheadi2s->I2S_XFER));
181 i2s->i2s_rx_status = 1;
183 i2s->i2s_rx_status = 0;
185 opr &= ~I2S_RECE_DMA_ENABLE;
186 writel(opr, &(pheadi2s->I2S_DMACR));
188 if (i2s->i2s_tx_status == 0 && hdmi_get_hotplug() == 0) {
189 xfer &= ~I2S_RX_TRAN_START;
190 xfer &= ~I2S_TX_TRAN_START;
191 writel(xfer, &(pheadi2s->I2S_XFER));
195 writel(clr, &(pheadi2s->I2S_CLR));
197 is_need_delay = true;
199 I2S_DBG("rockchip_snd_rxctrl: stop xfer\n");
203 spin_unlock_irqrestore(&lock, flags);
206 while(readl(&(pheadi2s->I2S_CLR)) && clr_error_count){
209 if(clr_error_count == 0)
210 printk("%s: i2s clr reg warning =%d\n",__FUNCTION__,readl(&(pheadi2s->I2S_CLR)));
216 * Set Rockchip I2S DAI format
218 static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
221 struct rk30_i2s_info *i2s = to_info(cpu_dai);
223 u32 iis_ckr_value;//clock generation register
227 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
229 spin_lock_irqsave(&lock, flags);
231 tx_ctl = readl(&(pheadi2s->I2S_TXCR));
232 iis_ckr_value = readl(&(pheadi2s->I2S_CKR));
234 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
235 case SND_SOC_DAIFMT_CBM_CFM:
236 //Codec is master, so set cpu slave.
237 iis_ckr_value &= ~I2S_MODE_MASK;
238 iis_ckr_value |= I2S_SLAVE_MODE;
240 case SND_SOC_DAIFMT_CBS_CFS:
241 //Codec is slave, so set cpu master.
242 iis_ckr_value &= ~I2S_MODE_MASK;
243 iis_ckr_value |= I2S_MASTER_MODE;
246 I2S_DBG("unknwon master/slave format\n");
251 writel(iis_ckr_value, &(pheadi2s->I2S_CKR));
253 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
254 case SND_SOC_DAIFMT_RIGHT_J:
255 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
256 tx_ctl |= I2S_BUS_MODE_RSJM;
258 case SND_SOC_DAIFMT_LEFT_J:
259 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
260 tx_ctl |= I2S_BUS_MODE_LSJM;
262 case SND_SOC_DAIFMT_I2S:
263 tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode
264 tx_ctl |= I2S_BUS_MODE_NOR;
267 I2S_DBG("Unknown data format\n");
272 I2S_DBG("Enter::%s----%d, I2S_TXCR=0x%X\n",__FUNCTION__,__LINE__,tx_ctl);
274 writel(tx_ctl, &(pheadi2s->I2S_TXCR));
276 rx_ctl = tx_ctl & 0x00007FFF;
277 writel(rx_ctl, &(pheadi2s->I2S_RXCR));
281 spin_unlock_irqrestore(&lock, flags);
286 static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
287 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
289 struct rk30_i2s_info *i2s = to_info(dai);
294 I2S_DBG("Enter %s, %d \n", __func__, __LINE__);
296 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
297 dai->playback_dma_data = &i2s->playback_dma_data;
299 dai->capture_dma_data = &i2s->capture_dma_data;
301 spin_lock_irqsave(&lock, flags);
303 /* Working copies of register */
304 iismod = readl(&(pheadi2s->I2S_TXCR));
306 iismod &= (~((1<<5)-1));
307 switch (params_format(params)) {
308 case SNDRV_PCM_FORMAT_S8:
309 iismod |= SAMPLE_DATA_8bit;
311 case SNDRV_PCM_FORMAT_S16_LE:
312 iismod |= I2S_DATA_WIDTH(15);
314 case SNDRV_PCM_FORMAT_S20_3LE:
315 iismod |= I2S_DATA_WIDTH(19);
317 case SNDRV_PCM_FORMAT_S24_LE:
318 iismod |= I2S_DATA_WIDTH(23);
320 case SNDRV_PCM_FORMAT_S32_LE:
321 iismod |= I2S_DATA_WIDTH(31);
325 // writel((16<<24) |(16<<18)|(16<<12)|(16<<6)|16, &(pheadi2s->I2S_FIFOLR));
326 dmarc = readl(&(pheadi2s->I2S_DMACR));
328 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
329 dmarc = ((dmarc & 0xFFFFFE00) | 16);
331 dmarc = ((dmarc & 0xFE00FFFF) | 16<<16);
333 writel(dmarc, &(pheadi2s->I2S_DMACR));
335 I2S_DBG("Enter %s, %d I2S_TXCR=0x%08X\n", __func__, __LINE__, iismod);
337 writel(iismod, &(pheadi2s->I2S_TXCR));
339 iismod = iismod & 0x00007FFF;
340 writel(iismod, &(pheadi2s->I2S_RXCR));
342 spin_unlock_irqrestore(&lock, flags);
347 static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
349 struct rk30_i2s_info *i2s = to_info(dai);
352 I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
355 case SNDRV_PCM_TRIGGER_START:
356 case SNDRV_PCM_TRIGGER_RESUME:
357 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
358 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
359 rockchip_snd_rxctrl(i2s, 1);
361 rockchip_snd_txctrl(i2s, 1);
363 case SNDRV_PCM_TRIGGER_SUSPEND:
364 case SNDRV_PCM_TRIGGER_STOP:
365 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
366 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
367 rockchip_snd_rxctrl(i2s, 0);
369 rockchip_snd_txctrl(i2s, 0);
380 * Set Rockchip I2S MCLK source
382 static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
383 int clk_id, unsigned int freq, int dir)
385 struct rk30_i2s_info *i2s = to_info(cpu_dai);
387 I2S_DBG("Enter:%s, %d, i2s=0x%p, freq=%d\n", __FUNCTION__, __LINE__, i2s, freq);
389 /*add scu clk source and enable clk*/
390 clk_set_rate(i2s->i2s_clk, freq);
395 * Set Rockchip Clock dividers
397 static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
400 struct rk30_i2s_info *i2s;
405 i2s = to_info(cpu_dai);
407 spin_lock_irqsave(&lock, flags);
409 //stereo mode MCLK/SCK=4
410 reg = readl(&(pheadi2s->I2S_CKR));
412 I2S_DBG("Enter:%s, %d, div_id=0x%08X, div=0x%08X\n", __FUNCTION__, __LINE__, div_id, div);
414 //when i2s in master mode ,must set codec pll div
416 case ROCKCHIP_DIV_BCLK:
417 reg &= ~I2S_TX_SCLK_DIV_MASK;
418 reg |= I2S_TX_SCLK_DIV(div);
419 reg &= ~I2S_RX_SCLK_DIV_MASK;
420 reg |= I2S_RX_SCLK_DIV(div);
422 case ROCKCHIP_DIV_MCLK:
423 reg &= ~I2S_MCLK_DIV_MASK;
424 reg |= I2S_MCLK_DIV(div);
426 case ROCKCHIP_DIV_PRESCALER:
432 writel(reg, &(pheadi2s->I2S_CKR));
435 spin_unlock_irqrestore(&lock, flags);
440 static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
441 .trigger = rockchip_i2s_trigger,
442 .hw_params = rockchip_i2s_hw_params,
443 .set_fmt = rockchip_i2s_set_fmt,
444 .set_clkdiv = rockchip_i2s_set_clkdiv,
445 .set_sysclk = rockchip_i2s_set_sysclk,
448 #define ROCKCHIP_I2S_STEREO_RATES SNDRV_PCM_RATE_8000_96000
449 #define ROCKCHIP_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
450 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
452 struct snd_soc_dai_driver rockchip_i2s_dai[] = {
454 .name = "rockchip-i2s.0",
459 .rates = ROCKCHIP_I2S_STEREO_RATES,
460 .formats = ROCKCHIP_I2S_FORMATS,
465 .rates = ROCKCHIP_I2S_STEREO_RATES,
466 .formats = ROCKCHIP_I2S_FORMATS,
468 .ops = &rockchip_i2s_dai_ops,
469 .symmetric_rates = 1,
472 .name = "rockchip-i2s.1",
477 .rates = ROCKCHIP_I2S_STEREO_RATES,
478 .formats = ROCKCHIP_I2S_FORMATS,
483 .rates = ROCKCHIP_I2S_STEREO_RATES,
484 .formats = ROCKCHIP_I2S_FORMATS,
486 .ops = &rockchip_i2s_dai_ops,
487 .symmetric_rates = 1,
491 static const struct snd_soc_component_driver rockchip_i2s_component = {
492 .name = "rockchip-i2s",
496 static int rockchip_i2s_suspend_noirq(struct device *dev)
498 I2S_DBG("Enter %s, %d\n", __func__, __LINE__);
500 return pinctrl_pm_select_sleep_state(dev);
503 static int rockchip_i2s_resume_noirq(struct device *dev)
505 I2S_DBG("Enter %s, %d\n", __func__, __LINE__);
507 return pinctrl_pm_select_default_state(dev);
510 #define rockchip_i2s_suspend_noirq NULL
511 #define rockchip_i2s_resume_noirq NULL
515 static void set_clk_later_work(struct work_struct *work)
517 struct rk30_i2s_info *i2s = rk30_i2s;
518 clk_set_rate(i2s->i2s_clk, 11289600);
519 if(!IS_ERR(i2s->i2s_mclk) )
520 clk_set_rate(i2s->i2s_mclk, 11289600);
524 static int rockchip_i2s_probe(struct platform_device *pdev)
526 struct device_node *node = pdev->dev.of_node;
527 struct rk30_i2s_info *i2s;
528 struct resource *mem, *memregion;
532 I2S_DBG("%s()\n", __FUNCTION__);
534 ret = of_property_read_u32(node, "i2s-id", &pdev->id);
536 dev_err(&pdev->dev, "%s() Can not read property: id\n", __FUNCTION__);
541 if (soc_is_rk3126b()) {
544 /* rk3126b has no i2s1 controller(i2s_8ch) */
546 pr_info("rk3126b has no i2s1 controller\n");
551 ret = of_property_read_u32(node, "sdi_source",
560 val = readl_relaxed(RK_GRF_VIRT + 0x0140);
561 val = val | 0x04000400;
562 writel_relaxed(val, RK_GRF_VIRT + 0x0140);
566 if(pdev->id >= MAX_I2S) {
567 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
572 i2s = devm_kzalloc(&pdev->dev, sizeof(struct rk30_i2s_info), GFP_KERNEL);
574 dev_err(&pdev->dev, "Can't allocate i2s info\n");
581 i2s->i2s_hclk = clk_get(&pdev->dev, "i2s_hclk");
582 if(IS_ERR(i2s->i2s_hclk) ) {
583 dev_err(&pdev->dev, "get i2s_hclk failed.\n");
585 clk_prepare_enable(i2s->i2s_hclk);
588 i2s->i2s_clk= clk_get(&pdev->dev, "i2s_clk");
589 if (IS_ERR(i2s->i2s_clk)) {
590 dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
591 ret = PTR_ERR(i2s->i2s_clk);
595 INIT_DELAYED_WORK(&i2s->clk_delayed_work, set_clk_later_work);
596 schedule_delayed_work(&i2s->clk_delayed_work, msecs_to_jiffies(10));
598 clk_set_rate(i2s->iis_clk, 11289600);
600 clk_prepare_enable(i2s->i2s_clk);
602 i2s->i2s_mclk= clk_get(&pdev->dev, "i2s_mclk");
603 if(IS_ERR(i2s->i2s_mclk) ) {
604 printk("This platfrom have not i2s_mclk,no need to set i2s_mclk.\n");
609 clk_set_rate(i2s->i2s_mclk, 11289600);
611 clk_prepare_enable(i2s->i2s_mclk);
614 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
616 dev_err(&pdev->dev, "No memory resource\n");
621 memregion = devm_request_mem_region(&pdev->dev, mem->start,
622 resource_size(mem), "rockchip-i2s");
624 dev_err(&pdev->dev, "Memory region already claimed\n");
629 i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
631 dev_err(&pdev->dev, "ioremap failed\n");
636 regs_base = mem->start;
638 i2s->playback_dma_data.addr = regs_base + I2S_TXR_BUFF;
639 i2s->playback_dma_data.addr_width = 4;
640 i2s->playback_dma_data.maxburst = 1;
642 i2s->capture_dma_data.addr = regs_base + I2S_RXR_BUFF;
643 i2s->capture_dma_data.addr_width = 4;
644 i2s->capture_dma_data.maxburst = 1;
646 i2s->i2s_tx_status = false;
647 i2s->i2s_rx_status = false;
649 pm_runtime_enable(&pdev->dev);
650 if (!pm_runtime_enabled(&pdev->dev)) {
651 ret = rockchip_i2s_resume_noirq(&pdev->dev);
656 //set dev name to driver->name.id for sound card register
657 dev_set_name(&pdev->dev, "%s.%d", pdev->dev.driver->name, pdev->id);
659 ret = snd_soc_register_component(&pdev->dev, &rockchip_i2s_component,
660 &rockchip_i2s_dai[pdev->id], 1);
663 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
668 ret = rockchip_pcm_platform_register(&pdev->dev);
670 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
671 goto err_unregister_component;
674 /* Mark ourselves as in TXRX mode so we can run through our cleanup
675 * process without warnings. */
676 rockchip_snd_txctrl(i2s, 0);
677 rockchip_snd_rxctrl(i2s, 0);
679 dev_set_drvdata(&pdev->dev, i2s);
682 err_unregister_component:
683 snd_soc_unregister_component(&pdev->dev);
685 if (!pm_runtime_status_suspended(&pdev->dev))
686 rockchip_i2s_suspend_noirq(&pdev->dev);
688 pm_runtime_disable(&pdev->dev);
690 clk_put(i2s->i2s_clk);
696 static int rockchip_i2s_remove(struct platform_device *pdev)
698 rockchip_pcm_platform_unregister(&pdev->dev);
699 snd_soc_unregister_component(&pdev->dev);
705 static const struct of_device_id exynos_i2s_match[] = {
706 { .compatible = "rockchip-i2s"},
709 MODULE_DEVICE_TABLE(of, exynos_i2s_match);
712 static const struct dev_pm_ops rockchip_i2s_pm_ops = {
713 .suspend_noirq = rockchip_i2s_suspend_noirq,
714 .resume_noirq = rockchip_i2s_resume_noirq,
717 static struct platform_driver rockchip_i2s_driver = {
718 .probe = rockchip_i2s_probe,
719 .remove = rockchip_i2s_remove,
721 .name = "rockchip-i2s",
722 .owner = THIS_MODULE,
723 .of_match_table = of_match_ptr(exynos_i2s_match),
724 .pm = &rockchip_i2s_pm_ops,
728 static int __init rockchip_i2s_init(void)
730 return platform_driver_register(&rockchip_i2s_driver);
732 subsys_initcall_sync(rockchip_i2s_init);
734 static void __exit rockchip_i2s_exit(void)
736 platform_driver_unregister(&rockchip_i2s_driver);
738 module_exit(rockchip_i2s_exit);
740 /* Module information */
741 MODULE_AUTHOR("rockchip");
742 MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface");
743 MODULE_LICENSE("GPL");
746 #ifdef CONFIG_PROC_FS
747 #include <linux/proc_fs.h>
748 #include <linux/seq_file.h>
749 static int proc_i2s_show(struct seq_file *s, void *v)
752 struct rk30_i2s_info *i2s = rk30_i2s;
754 printk("========Show I2S reg========\n");
756 printk("I2S_TXCR = 0x%08X\n", readl(&(pheadi2s->I2S_TXCR)));
757 printk("I2S_RXCR = 0x%08X\n", readl(&(pheadi2s->I2S_RXCR)));
758 printk("I2S_CKR = 0x%08X\n", readl(&(pheadi2s->I2S_CKR)));
759 printk("I2S_DMACR = 0x%08X\n", readl(&(pheadi2s->I2S_DMACR)));
760 printk("I2S_INTCR = 0x%08X\n", readl(&(pheadi2s->I2S_INTCR)));
761 printk("I2S_INTSR = 0x%08X\n", readl(&(pheadi2s->I2S_INTSR)));
762 printk("I2S_XFER = 0x%08X\n", readl(&(pheadi2s->I2S_XFER)));
764 printk("========Show I2S reg========\n");
766 writel(0x0000000F, &(pheadi2s->I2S_TXCR));
767 writel(0x0000000F, &(pheadi2s->I2S_RXCR));
768 writel(0x00071f1F, &(pheadi2s->I2S_CKR));
769 writel(0x001F0110, &(pheadi2s->I2S_DMACR));
770 writel(0x00000003, &(pheadi2s->I2S_XFER));
773 writel(0x5555aaaa, &(pheadi2s->I2S_TXDR));
779 static ssize_t i2s_reg_write(struct file *file,
780 const char __user *user_buf, size_t count, loff_t *ppos)
782 struct rk30_i2s_info *i2s=rk30_i2s;
789 buf_size = min(count, (sizeof(buf)-1));
790 if (copy_from_user(buf, user_buf, buf_size))
794 while (*start == ' ')
796 value = simple_strtoul(start, &start, 10);
798 printk("test --- freq = %ld ret=%d\n",value,clk_set_rate(i2s->i2s_clk, value));
802 static int proc_i2s_open(struct inode *inode, struct file *file)
804 return single_open(file, proc_i2s_show, NULL);
807 static const struct file_operations proc_i2s_fops = {
808 .open = proc_i2s_open,
810 .write = i2s_reg_write,
812 .release = single_release,
815 static int __init i2s_proc_init(void)
817 proc_create("i2s_reg", 0, NULL, &proc_i2s_fops);
820 late_initcall(i2s_proc_init);
821 #endif /* CONFIG_PROC_FS */