Merge tag 'stable/for-linus-3.16-rc1-tag' of git://git.kernel.org/pub/scm/linux/kerne...
[cascardo/linux.git] / drivers / clk / socfpga / clk-periph.c
index 81623a3..46531c3 100644 (file)
@@ -29,12 +29,18 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
                                             unsigned long parent_rate)
 {
        struct socfpga_periph_clk *socfpgaclk = to_socfpga_periph_clk(hwclk);
-       u32 div;
+       u32 div, val;
 
-       if (socfpgaclk->fixed_div)
+       if (socfpgaclk->fixed_div) {
                div = socfpgaclk->fixed_div;
-       else
+       } else {
+               if (socfpgaclk->div_reg) {
+                       val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+                       val &= div_mask(socfpgaclk->width);
+                       parent_rate /= (val + 1);
+               }
                div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1);
+       }
 
        return parent_rate / div;
 }
@@ -54,6 +60,7 @@ static __init void __socfpga_periph_init(struct device_node *node,
        struct clk_init_data init;
        int rc;
        u32 fixed_div;
+       u32 div_reg[3];
 
        of_property_read_u32(node, "reg", &reg);
 
@@ -63,6 +70,15 @@ static __init void __socfpga_periph_init(struct device_node *node,
 
        periph_clk->hw.reg = clk_mgr_base_addr + reg;
 
+       rc = of_property_read_u32_array(node, "div-reg", div_reg, 3);
+       if (!rc) {
+               periph_clk->div_reg = clk_mgr_base_addr + div_reg[0];
+               periph_clk->shift = div_reg[1];
+               periph_clk->width = div_reg[2];
+       } else {
+               periph_clk->div_reg = 0;
+       }
+
        rc = of_property_read_u32(node, "fixed-divider", &fixed_div);
        if (rc)
                periph_clk->fixed_div = 0;