Merge branch 'renesas/fixes-2' into next/dt64
[cascardo/linux.git] / drivers / clk / clk-axi-clkgen.c
index 3bcd42f..3294db3 100644 (file)
 #include <linux/module.h>
 #include <linux/err.h>
 
-#define AXI_CLKGEN_V1_REG_UPDATE_ENABLE        0x04
-#define AXI_CLKGEN_V1_REG_CLK_OUT1     0x08
-#define AXI_CLKGEN_V1_REG_CLK_OUT2     0x0c
-#define AXI_CLKGEN_V1_REG_CLK_DIV      0x10
-#define AXI_CLKGEN_V1_REG_CLK_FB1      0x14
-#define AXI_CLKGEN_V1_REG_CLK_FB2      0x18
-#define AXI_CLKGEN_V1_REG_LOCK1                0x1c
-#define AXI_CLKGEN_V1_REG_LOCK2                0x20
-#define AXI_CLKGEN_V1_REG_LOCK3                0x24
-#define AXI_CLKGEN_V1_REG_FILTER1      0x28
-#define AXI_CLKGEN_V1_REG_FILTER2      0x2c
-
 #define AXI_CLKGEN_V2_REG_RESET                0x40
+#define AXI_CLKGEN_V2_REG_CLKSEL       0x44
 #define AXI_CLKGEN_V2_REG_DRP_CNTRL    0x70
 #define AXI_CLKGEN_V2_REG_DRP_STATUS   0x74
 
 #define MMCM_REG_FILTER1       0x4e
 #define MMCM_REG_FILTER2       0x4f
 
-struct axi_clkgen;
-
-struct axi_clkgen_mmcm_ops {
-       void (*enable)(struct axi_clkgen *axi_clkgen, bool enable);
-       int (*write)(struct axi_clkgen *axi_clkgen, unsigned int reg,
-                    unsigned int val, unsigned int mask);
-       int (*read)(struct axi_clkgen *axi_clkgen, unsigned int reg,
-                   unsigned int *val);
-};
-
 struct axi_clkgen {
        void __iomem *base;
-       const struct axi_clkgen_mmcm_ops *mmcm_ops;
        struct clk_hw clk_hw;
 };
 
-static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen,
-       bool enable)
-{
-       axi_clkgen->mmcm_ops->enable(axi_clkgen, enable);
-}
-
-static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
-       unsigned int reg, unsigned int val, unsigned int mask)
-{
-       return axi_clkgen->mmcm_ops->write(axi_clkgen, reg, val, mask);
-}
-
-static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
-       unsigned int reg, unsigned int *val)
-{
-       return axi_clkgen->mmcm_ops->read(axi_clkgen, reg, val);
-}
-
 static uint32_t axi_clkgen_lookup_filter(unsigned int m)
 {
        switch (m) {
@@ -207,70 +167,6 @@ static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
        *val = readl(axi_clkgen->base + reg);
 }
 
-static unsigned int axi_clkgen_v1_map_mmcm_reg(unsigned int reg)
-{
-       switch (reg) {
-       case MMCM_REG_CLKOUT0_1:
-               return AXI_CLKGEN_V1_REG_CLK_OUT1;
-       case MMCM_REG_CLKOUT0_2:
-               return AXI_CLKGEN_V1_REG_CLK_OUT2;
-       case MMCM_REG_CLK_FB1:
-               return AXI_CLKGEN_V1_REG_CLK_FB1;
-       case MMCM_REG_CLK_FB2:
-               return AXI_CLKGEN_V1_REG_CLK_FB2;
-       case MMCM_REG_CLK_DIV:
-               return AXI_CLKGEN_V1_REG_CLK_DIV;
-       case MMCM_REG_LOCK1:
-               return AXI_CLKGEN_V1_REG_LOCK1;
-       case MMCM_REG_LOCK2:
-               return AXI_CLKGEN_V1_REG_LOCK2;
-       case MMCM_REG_LOCK3:
-               return AXI_CLKGEN_V1_REG_LOCK3;
-       case MMCM_REG_FILTER1:
-               return AXI_CLKGEN_V1_REG_FILTER1;
-       case MMCM_REG_FILTER2:
-               return AXI_CLKGEN_V1_REG_FILTER2;
-       default:
-               return 0;
-       }
-}
-
-static int axi_clkgen_v1_mmcm_write(struct axi_clkgen *axi_clkgen,
-       unsigned int reg, unsigned int val, unsigned int mask)
-{
-       reg = axi_clkgen_v1_map_mmcm_reg(reg);
-       if (reg == 0)
-               return -EINVAL;
-
-       axi_clkgen_write(axi_clkgen, reg, val);
-
-       return 0;
-}
-
-static int axi_clkgen_v1_mmcm_read(struct axi_clkgen *axi_clkgen,
-       unsigned int reg, unsigned int *val)
-{
-       reg = axi_clkgen_v1_map_mmcm_reg(reg);
-       if (reg == 0)
-               return -EINVAL;
-
-       axi_clkgen_read(axi_clkgen, reg, val);
-
-       return 0;
-}
-
-static void axi_clkgen_v1_mmcm_enable(struct axi_clkgen *axi_clkgen,
-       bool enable)
-{
-       axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V1_REG_UPDATE_ENABLE, enable);
-}
-
-static const struct axi_clkgen_mmcm_ops axi_clkgen_v1_mmcm_ops = {
-       .write = axi_clkgen_v1_mmcm_write,
-       .read = axi_clkgen_v1_mmcm_read,
-       .enable = axi_clkgen_v1_mmcm_enable,
-};
-
 static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
 {
        unsigned int timeout = 10000;
@@ -286,7 +182,7 @@ static int axi_clkgen_wait_non_busy(struct axi_clkgen *axi_clkgen)
        return val & 0xffff;
 }
 
-static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen,
+static int axi_clkgen_mmcm_read(struct axi_clkgen *axi_clkgen,
        unsigned int reg, unsigned int *val)
 {
        unsigned int reg_val;
@@ -310,7 +206,7 @@ static int axi_clkgen_v2_mmcm_read(struct axi_clkgen *axi_clkgen,
        return 0;
 }
 
-static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen,
+static int axi_clkgen_mmcm_write(struct axi_clkgen *axi_clkgen,
        unsigned int reg, unsigned int val, unsigned int mask)
 {
        unsigned int reg_val = 0;
@@ -321,7 +217,7 @@ static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen,
                return ret;
 
        if (mask != 0xffff) {
-               axi_clkgen_v2_mmcm_read(axi_clkgen, reg, &reg_val);
+               axi_clkgen_mmcm_read(axi_clkgen, reg, &reg_val);
                reg_val &= ~mask;
        }
 
@@ -332,7 +228,7 @@ static int axi_clkgen_v2_mmcm_write(struct axi_clkgen *axi_clkgen,
        return 0;
 }
 
-static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen,
+static void axi_clkgen_mmcm_enable(struct axi_clkgen *axi_clkgen,
        bool enable)
 {
        unsigned int val = AXI_CLKGEN_V2_RESET_ENABLE;
@@ -343,12 +239,6 @@ static void axi_clkgen_v2_mmcm_enable(struct axi_clkgen *axi_clkgen,
        axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_RESET, val);
 }
 
-static const struct axi_clkgen_mmcm_ops axi_clkgen_v2_mmcm_ops = {
-       .write = axi_clkgen_v2_mmcm_write,
-       .read = axi_clkgen_v2_mmcm_read,
-       .enable = axi_clkgen_v2_mmcm_enable,
-};
-
 static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
 {
        return container_of(clk_hw, struct axi_clkgen, clk_hw);
@@ -438,10 +328,7 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
        tmp = (unsigned long long)(parent_rate / d) * m;
        do_div(tmp, dout);
 
-       if (tmp > ULONG_MAX)
-               return ULONG_MAX;
-
-       return tmp;
+       return min_t(unsigned long long, tmp, ULONG_MAX);
 }
 
 static int axi_clkgen_enable(struct clk_hw *clk_hw)
@@ -460,21 +347,38 @@ static void axi_clkgen_disable(struct clk_hw *clk_hw)
        axi_clkgen_mmcm_enable(axi_clkgen, false);
 }
 
+static int axi_clkgen_set_parent(struct clk_hw *clk_hw, u8 index)
+{
+       struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
+
+       axi_clkgen_write(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, index);
+
+       return 0;
+}
+
+static u8 axi_clkgen_get_parent(struct clk_hw *clk_hw)
+{
+       struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
+       unsigned int parent;
+
+       axi_clkgen_read(axi_clkgen, AXI_CLKGEN_V2_REG_CLKSEL, &parent);
+
+       return parent;
+}
+
 static const struct clk_ops axi_clkgen_ops = {
        .recalc_rate = axi_clkgen_recalc_rate,
        .round_rate = axi_clkgen_round_rate,
        .set_rate = axi_clkgen_set_rate,
        .enable = axi_clkgen_enable,
        .disable = axi_clkgen_disable,
+       .set_parent = axi_clkgen_set_parent,
+       .get_parent = axi_clkgen_get_parent,
 };
 
 static const struct of_device_id axi_clkgen_ids[] = {
        {
-               .compatible = "adi,axi-clkgen-1.00.a",
-               .data = &axi_clkgen_v1_mmcm_ops
-       }, {
                .compatible = "adi,axi-clkgen-2.00.a",
-               .data = &axi_clkgen_v2_mmcm_ops,
        },
        { },
 };
@@ -485,10 +389,11 @@ static int axi_clkgen_probe(struct platform_device *pdev)
        const struct of_device_id *id;
        struct axi_clkgen *axi_clkgen;
        struct clk_init_data init;
-       const char *parent_name;
+       const char *parent_names[2];
        const char *clk_name;
        struct resource *mem;
        struct clk *clk;
+       unsigned int i;
 
        if (!pdev->dev.of_node)
                return -ENODEV;
@@ -501,26 +406,29 @@ static int axi_clkgen_probe(struct platform_device *pdev)
        if (!axi_clkgen)
                return -ENOMEM;
 
-       axi_clkgen->mmcm_ops = id->data;
-
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
        if (IS_ERR(axi_clkgen->base))
                return PTR_ERR(axi_clkgen->base);
 
-       parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
-       if (!parent_name)
+       init.num_parents = of_clk_get_parent_count(pdev->dev.of_node);
+       if (init.num_parents < 1 || init.num_parents > 2)
                return -EINVAL;
 
+       for (i = 0; i < init.num_parents; i++) {
+               parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i);
+               if (!parent_names[i])
+                       return -EINVAL;
+       }
+
        clk_name = pdev->dev.of_node->name;
        of_property_read_string(pdev->dev.of_node, "clock-output-names",
                &clk_name);
 
        init.name = clk_name;
        init.ops = &axi_clkgen_ops;
-       init.flags = CLK_SET_RATE_GATE;
-       init.parent_names = &parent_name;
-       init.num_parents = 1;
+       init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+       init.parent_names = parent_names;
 
        axi_clkgen_mmcm_enable(axi_clkgen, false);