Merge tag 'lsk-android-14.04' into develop-3.10
[firefly-linux-kernel-4.4.55.git] / sound / soc / rockchip / rk30_i2s.c
index 9a761a3a5e080b768b5f2a117584694600b684c0..dd4a6fa89f5f3d03d8179e33eddb8d89575c2781 100755 (executable)
@@ -26,7 +26,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
-
 #include <asm/dma.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 #include <asm/io.h>
-
 #include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#define CLK_SET_lATER
 
 #include "rk_pcm.h"
 #include "rk_i2s.h"
@@ -56,13 +57,17 @@ static DEFINE_SPINLOCK(lock);
 struct rk30_i2s_info {
        void __iomem    *regs;
 
-       struct clk *i2s_clk;
-
+       struct clk *i2s_clk;// i2s clk ,is bclk lrck
+       struct clk *i2s_mclk;//i2s mclk,rk32xx can different i2s clk.
+       struct clk *i2s_hclk;
        struct snd_dmaengine_dai_dma_data capture_dma_data;
        struct snd_dmaengine_dai_dma_data playback_dma_data;
 
        bool i2s_tx_status;//active = true;
        bool i2s_rx_status;
+#ifdef CLK_SET_lATER
+       struct delayed_work clk_delayed_work;
+#endif 
 };
 
 #define I2S_CLR_ERROR_COUNT 10// check I2S_CLR reg 
@@ -214,6 +219,7 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        u32 tx_ctl,rx_ctl;
        u32 iis_ckr_value;//clock generation register
        unsigned long flags;
+       int ret = 0;
 
        I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
 
@@ -235,7 +241,8 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                break;
        default:
                I2S_DBG("unknwon master/slave format\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_;
        }
 
        writel(iis_ckr_value, &(pheadi2s->I2S_CKR));
@@ -255,7 +262,8 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                break;
        default:
                I2S_DBG("Unknown data format\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_;
        }
 
        I2S_DBG("Enter::%s----%d, I2S_TXCR=0x%X\n",__FUNCTION__,__LINE__,tx_ctl);
@@ -265,8 +273,11 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
        rx_ctl = tx_ctl & 0x00007FFF;
        writel(rx_ctl, &(pheadi2s->I2S_RXCR));
 
+out_:
+
        spin_unlock_irqrestore(&lock, flags);
-       return 0;
+
+       return ret;
 }
 
 static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
@@ -386,6 +397,7 @@ static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
        struct rk30_i2s_info *i2s;
        u32 reg;
        unsigned long flags;
+       int ret = 0;
 
        i2s = to_info(cpu_dai);
 
@@ -411,12 +423,15 @@ static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
        case ROCKCHIP_DIV_PRESCALER:
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out_;
        }
        writel(reg, &(pheadi2s->I2S_CKR));
+
+out_:
        spin_unlock_irqrestore(&lock, flags);
 
-       return 0;
+       return ret;
 }
 
 static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
@@ -493,6 +508,16 @@ static int rockchip_i2s_resume_noirq(struct device *dev)
 #define rockchip_i2s_resume_noirq NULL
 #endif
 
+#ifdef CLK_SET_lATER
+static void set_clk_later_work(struct work_struct *work)
+{
+       struct rk30_i2s_info *i2s = rk30_i2s;
+       clk_set_rate(i2s->i2s_clk, 11289600);
+       if(!IS_ERR(i2s->i2s_mclk) )
+               clk_set_rate(i2s->i2s_mclk, 11289600);
+}
+#endif
+
 static int rockchip_i2s_probe(struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
@@ -523,14 +548,40 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
                goto err;
        }
 
-       i2s->i2s_clk= clk_get(&pdev->dev, NULL);
+       rk30_i2s = i2s;
+
+       i2s->i2s_hclk = clk_get(&pdev->dev, "i2s_hclk");
+       if(IS_ERR(i2s->i2s_hclk) ) {
+                dev_err(&pdev->dev, "get i2s_hclk failed.\n");
+        } else{
+               clk_prepare_enable(i2s->i2s_hclk);
+       }
+
+       i2s->i2s_clk= clk_get(&pdev->dev, "i2s_clk");
        if (IS_ERR(i2s->i2s_clk)) {
                dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
                ret = PTR_ERR(i2s->i2s_clk);
                goto err;
        }
+#ifdef CLK_SET_lATER
+       INIT_DELAYED_WORK(&i2s->clk_delayed_work, set_clk_later_work);
+       schedule_delayed_work(&i2s->clk_delayed_work, msecs_to_jiffies(10));
+#else
+       clk_set_rate(i2s->iis_clk, 11289600);
+#endif 
        clk_prepare_enable(i2s->i2s_clk);
-       clk_set_rate(i2s->i2s_clk, 11289600);
+
+       i2s->i2s_mclk= clk_get(&pdev->dev, "i2s_mclk");
+       if(IS_ERR(i2s->i2s_mclk) ) {
+               printk("This platfrom have not i2s_mclk,no need to set i2s_mclk.\n");
+       }else{
+       #ifdef CLK_SET_lATER
+               
+       #else
+               clk_set_rate(i2s->i2s_mclk, 11289600);
+       #endif
+               clk_prepare_enable(i2s->i2s_mclk);
+       }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem) {
@@ -598,8 +649,6 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
        rockchip_snd_rxctrl(i2s, 0);
 
        dev_set_drvdata(&pdev->dev, i2s);
-
-       rk30_i2s = i2s;
        return 0;
 
 err_unregister_component: