Merge commit 'v2.6.36-rc1' into kbuild/rc-fixes
[pandora-kernel.git] / arch / arm / mach-ep93xx / clock.c
index 7f30397..8bf3cec 100644 (file)
@@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
 
 static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
 static int set_div_rate(struct clk *clk, unsigned long rate);
-
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
 
 static struct clk clk_xtali = {
        .rate           = EP93XX_EXT_CLK_RATE,
@@ -112,6 +113,29 @@ static struct clk clk_video = {
        .set_rate       = set_div_rate,
 };
 
+static struct clk clk_i2s_mclk = {
+       .sw_locked      = 1,
+       .enable_reg     = EP93XX_SYSCON_I2SCLKDIV,
+       .enable_mask    = EP93XX_SYSCON_CLKDIV_ENABLE,
+       .set_rate       = set_div_rate,
+};
+
+static struct clk clk_i2s_sclk = {
+       .sw_locked      = 1,
+       .parent         = &clk_i2s_mclk,
+       .enable_reg     = EP93XX_SYSCON_I2SCLKDIV,
+       .enable_mask    = EP93XX_SYSCON_I2SCLKDIV_SENA,
+       .set_rate       = set_i2s_sclk_rate,
+};
+
+static struct clk clk_i2s_lrclk = {
+       .sw_locked      = 1,
+       .parent         = &clk_i2s_sclk,
+       .enable_reg     = EP93XX_SYSCON_I2SCLKDIV,
+       .enable_mask    = EP93XX_SYSCON_I2SCLKDIV_SENA,
+       .set_rate       = set_i2s_lrclk_rate,
+};
+
 /* DMA Clocks */
 static struct clk clk_m2p0 = {
        .parent         = &clk_h,
@@ -191,6 +215,9 @@ static struct clk_lookup clocks[] = {
        INIT_CK("ep93xx-keypad",        NULL,           &clk_keypad),
        INIT_CK("ep93xx-fb",            NULL,           &clk_video),
        INIT_CK("ep93xx-spi.0",         NULL,           &clk_spi),
+       INIT_CK("ep93xx-i2s",           "mclk",         &clk_i2s_mclk),
+       INIT_CK("ep93xx-i2s",           "sclk",         &clk_i2s_sclk),
+       INIT_CK("ep93xx-i2s",           "lrclk",        &clk_i2s_lrclk),
        INIT_CK(NULL,                   "pwm_clk",      &clk_pwm),
        INIT_CK(NULL,                   "m2p0",         &clk_m2p0),
        INIT_CK(NULL,                   "m2p1",         &clk_m2p1),
@@ -401,6 +428,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned val = __raw_readl(clk->enable_reg);
+
+       if (rate == clk_i2s_mclk.rate / 2)
+               ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, 
+                                            clk->enable_reg);
+       else if (rate == clk_i2s_mclk.rate / 4)
+               ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, 
+                                            clk->enable_reg);
+       else
+               return -EINVAL;
+
+       clk_i2s_sclk.rate = rate;
+       return 0;
+}
+
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned val = __raw_readl(clk->enable_reg) & 
+               ~EP93XX_I2SCLKDIV_LRDIV_MASK;
+       
+       if (rate == clk_i2s_sclk.rate / 32)
+               ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
+                                            clk->enable_reg);
+       else if (rate == clk_i2s_sclk.rate / 64)
+               ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
+                                            clk->enable_reg);
+       else if (rate == clk_i2s_sclk.rate / 128)
+               ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
+                                            clk->enable_reg);
+       else
+               return -EINVAL;
+
+       clk_i2s_lrclk.rate = rate;
+       return 0;
+}
+
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
        if (clk->set_rate)