clk: shmobile: Add R-Car Gen2 RCAN clock support
authorSergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Mon, 5 Jan 2015 21:25:08 +0000 (00:25 +0300)
committerGeert Uytterhoeven <geert+renesas@glider.be>
Thu, 8 Jan 2015 15:14:31 +0000 (16:14 +0100)
Add the RCAN clock support to the R-Car generation 2 CPG driver.  This clock
gets derived from  the USB_EXTAL clock, dividing  it by 6.  The layout of the
RCANCKCR register is similar to those of the clocks supported by the 'clk-div6'
driver but has no divider field, and so can't be supported by that driver...

Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
drivers/clk/shmobile/clk-rcar-gen2.c

index fc7ef9946f40fbf9871ab5a684ad0eda6d757dbc..5b704b5ab8ab2139c81e86839f8dc209264ffbfc 100644 (file)
@@ -14,10 +14,11 @@ Required Properties:
 
   - reg: Base address and length of the memory resource used by the CPG
 
-  - clocks: Reference to the parent clock
+  - clocks: References to the parent clocks: first to the EXTAL clock, second
+    to the USB_EXTAL clock
   - #clock-cells: Must be 1
   - clock-output-names: The names of the clocks. Supported clocks are "main",
-    "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z"
+    "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", "z", and "rcan"
 
 
 Example
@@ -27,8 +28,9 @@ Example
                compatible = "renesas,r8a7790-cpg-clocks",
                             "renesas,rcar-gen2-cpg-clocks";
                reg = <0 0xe6150000 0 0x1000>;
-               clocks = <&extal_clk>;
+               clocks = <&extal_clk &usb_extal_clk>;
                #clock-cells = <1>;
                clock-output-names = "main", "pll0, "pll1", "pll3",
-                                    "lb", "qspi", "sdh", "sd0", "sd1", "z";
+                                    "lb", "qspi", "sdh", "sd0", "sd1", "z",
+                                    "rcan";
        };
index e996425d06a920728cd4f32448c19d08efb5a776..08076ee7cd7bfb13325eaa22c97588bdc7a441bc 100644 (file)
@@ -33,6 +33,7 @@ struct rcar_gen2_cpg {
 #define CPG_FRQCRC                     0x000000e0
 #define CPG_FRQCRC_ZFC_MASK            (0x1f << 8)
 #define CPG_FRQCRC_ZFC_SHIFT           8
+#define CPG_RCANCKCR                   0x00000270
 
 /* -----------------------------------------------------------------------------
  * Z Clock
@@ -161,6 +162,43 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
        return clk;
 }
 
+static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
+                                                struct device_node *np)
+{
+       const char *parent_name = of_clk_get_parent_name(np, 1);
+       struct clk_fixed_factor *fixed;
+       struct clk_gate *gate;
+       struct clk *clk;
+
+       fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+       if (!fixed)
+               return ERR_PTR(-ENOMEM);
+
+       fixed->mult = 1;
+       fixed->div = 6;
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate) {
+               kfree(fixed);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       gate->reg = cpg->reg + CPG_RCANCKCR;
+       gate->bit_idx = 8;
+       gate->flags = CLK_GATE_SET_TO_DISABLE;
+       gate->lock = &cpg->lock;
+
+       clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
+                                    &fixed->hw, &clk_fixed_factor_ops,
+                                    &gate->hw, &clk_gate_ops, 0);
+       if (IS_ERR(clk)) {
+               kfree(gate);
+               kfree(fixed);
+       }
+
+       return clk;
+}
+
 /* -----------------------------------------------------------------------------
  * CPG Clock Data
  */
@@ -263,6 +301,8 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                shift = 0;
        } else if (!strcmp(name, "z")) {
                return cpg_z_clk_register(cpg);
+       } else if (!strcmp(name, "rcan")) {
+               return cpg_rcan_clk_register(cpg, np);
        } else {
                return ERR_PTR(-EINVAL);
        }