clk: axi-clkgen: Add multi-parent support
authorLars-Peter Clausen <lars@metafoo.de>
Mon, 30 Nov 2015 16:54:56 +0000 (17:54 +0100)
committerStephen Boyd <sboyd@codeaurora.org>
Sat, 30 Jan 2016 01:06:14 +0000 (17:06 -0800)
The clock generator has two clock inputs that can be used as the reference
clock. Add support for switching between them at runtime.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Documentation/devicetree/bindings/clock/axi-clkgen.txt
drivers/clk/clk-axi-clkgen.c

index 20e1704e7df2110c518ce71ca07e94a0b4db574a..fb40da303d25c8f13093aafe43df83eaf2f88f47 100644 (file)
@@ -8,7 +8,10 @@ Required properties:
 - compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a".
 - #clock-cells : from common clock binding; Should always be set to 0.
 - reg : Address and length of the axi-clkgen register set.
-- clocks : Phandle and clock specifier for the parent clock.
+- clocks : Phandle and clock specifier for the parent clock(s). This must
+       either reference one clock if only the first clock input is connected or two
+       if both clock inputs are connected. For the later case the clock connected
+       to the first input must be specified first.
 
 Optional properties:
 - clock-output-names : From common clock binding.
index 8dedc600e7111b2033661835213a3a7f49ab249c..9a0744c9947c5fc3dc439f679b5c85e88b9b3c86 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/err.h>
 
 #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
 
@@ -349,12 +350,33 @@ 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[] = {
@@ -370,10 +392,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;
@@ -391,19 +414,24 @@ static int axi_clkgen_probe(struct platform_device *pdev)
        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);