1*86be408bSSylwester Nawrocki /* 2*86be408bSSylwester Nawrocki * Copyright (C) 2014 Samsung Electronics Co., Ltd. 3*86be408bSSylwester Nawrocki * Sylwester Nawrocki <s.nawrocki@samsung.com> 4*86be408bSSylwester Nawrocki * 5*86be408bSSylwester Nawrocki * This program is free software; you can redistribute it and/or modify 6*86be408bSSylwester Nawrocki * it under the terms of the GNU General Public License version 2 as 7*86be408bSSylwester Nawrocki * published by the Free Software Foundation. 8*86be408bSSylwester Nawrocki */ 9*86be408bSSylwester Nawrocki 10*86be408bSSylwester Nawrocki #include <linux/clk.h> 11*86be408bSSylwester Nawrocki #include <linux/clk-provider.h> 12*86be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h> 13*86be408bSSylwester Nawrocki #include <linux/device.h> 14*86be408bSSylwester Nawrocki #include <linux/of.h> 15*86be408bSSylwester Nawrocki #include <linux/printk.h> 16*86be408bSSylwester Nawrocki #include "clk.h" 17*86be408bSSylwester Nawrocki 18*86be408bSSylwester Nawrocki static int __set_clk_parents(struct device_node *node, bool clk_supplier) 19*86be408bSSylwester Nawrocki { 20*86be408bSSylwester Nawrocki struct of_phandle_args clkspec; 21*86be408bSSylwester Nawrocki int index, rc, num_parents; 22*86be408bSSylwester Nawrocki struct clk *clk, *pclk; 23*86be408bSSylwester Nawrocki 24*86be408bSSylwester Nawrocki num_parents = of_count_phandle_with_args(node, "assigned-clock-parents", 25*86be408bSSylwester Nawrocki "#clock-cells"); 26*86be408bSSylwester Nawrocki if (num_parents == -EINVAL) 27*86be408bSSylwester Nawrocki pr_err("clk: invalid value of clock-parents property at %s\n", 28*86be408bSSylwester Nawrocki node->full_name); 29*86be408bSSylwester Nawrocki 30*86be408bSSylwester Nawrocki for (index = 0; index < num_parents; index++) { 31*86be408bSSylwester Nawrocki rc = of_parse_phandle_with_args(node, "assigned-clock-parents", 32*86be408bSSylwester Nawrocki "#clock-cells", index, &clkspec); 33*86be408bSSylwester Nawrocki if (rc < 0) { 34*86be408bSSylwester Nawrocki /* skip empty (null) phandles */ 35*86be408bSSylwester Nawrocki if (rc == -ENOENT) 36*86be408bSSylwester Nawrocki continue; 37*86be408bSSylwester Nawrocki else 38*86be408bSSylwester Nawrocki return rc; 39*86be408bSSylwester Nawrocki } 40*86be408bSSylwester Nawrocki if (clkspec.np == node && !clk_supplier) 41*86be408bSSylwester Nawrocki return 0; 42*86be408bSSylwester Nawrocki pclk = of_clk_get_by_clkspec(&clkspec); 43*86be408bSSylwester Nawrocki if (IS_ERR(pclk)) { 44*86be408bSSylwester Nawrocki pr_warn("clk: couldn't get parent clock %d for %s\n", 45*86be408bSSylwester Nawrocki index, node->full_name); 46*86be408bSSylwester Nawrocki return PTR_ERR(pclk); 47*86be408bSSylwester Nawrocki } 48*86be408bSSylwester Nawrocki 49*86be408bSSylwester Nawrocki rc = of_parse_phandle_with_args(node, "assigned-clocks", 50*86be408bSSylwester Nawrocki "#clock-cells", index, &clkspec); 51*86be408bSSylwester Nawrocki if (rc < 0) 52*86be408bSSylwester Nawrocki goto err; 53*86be408bSSylwester Nawrocki if (clkspec.np == node && !clk_supplier) { 54*86be408bSSylwester Nawrocki rc = 0; 55*86be408bSSylwester Nawrocki goto err; 56*86be408bSSylwester Nawrocki } 57*86be408bSSylwester Nawrocki clk = of_clk_get_by_clkspec(&clkspec); 58*86be408bSSylwester Nawrocki if (IS_ERR(pclk)) { 59*86be408bSSylwester Nawrocki pr_warn("clk: couldn't get parent clock %d for %s\n", 60*86be408bSSylwester Nawrocki index, node->full_name); 61*86be408bSSylwester Nawrocki rc = PTR_ERR(pclk); 62*86be408bSSylwester Nawrocki goto err; 63*86be408bSSylwester Nawrocki } 64*86be408bSSylwester Nawrocki 65*86be408bSSylwester Nawrocki rc = clk_set_parent(clk, pclk); 66*86be408bSSylwester Nawrocki if (rc < 0) 67*86be408bSSylwester Nawrocki pr_err("clk: failed to reparent %s to %s: %d\n", 68*86be408bSSylwester Nawrocki __clk_get_name(clk), __clk_get_name(pclk), rc); 69*86be408bSSylwester Nawrocki clk_put(clk); 70*86be408bSSylwester Nawrocki clk_put(pclk); 71*86be408bSSylwester Nawrocki } 72*86be408bSSylwester Nawrocki return 0; 73*86be408bSSylwester Nawrocki err: 74*86be408bSSylwester Nawrocki clk_put(pclk); 75*86be408bSSylwester Nawrocki return rc; 76*86be408bSSylwester Nawrocki } 77*86be408bSSylwester Nawrocki 78*86be408bSSylwester Nawrocki static int __set_clk_rates(struct device_node *node, bool clk_supplier) 79*86be408bSSylwester Nawrocki { 80*86be408bSSylwester Nawrocki struct of_phandle_args clkspec; 81*86be408bSSylwester Nawrocki struct property *prop; 82*86be408bSSylwester Nawrocki const __be32 *cur; 83*86be408bSSylwester Nawrocki int rc, index = 0; 84*86be408bSSylwester Nawrocki struct clk *clk; 85*86be408bSSylwester Nawrocki u32 rate; 86*86be408bSSylwester Nawrocki 87*86be408bSSylwester Nawrocki of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) { 88*86be408bSSylwester Nawrocki if (rate) { 89*86be408bSSylwester Nawrocki rc = of_parse_phandle_with_args(node, "assigned-clocks", 90*86be408bSSylwester Nawrocki "#clock-cells", index, &clkspec); 91*86be408bSSylwester Nawrocki if (rc < 0) { 92*86be408bSSylwester Nawrocki /* skip empty (null) phandles */ 93*86be408bSSylwester Nawrocki if (rc == -ENOENT) 94*86be408bSSylwester Nawrocki continue; 95*86be408bSSylwester Nawrocki else 96*86be408bSSylwester Nawrocki return rc; 97*86be408bSSylwester Nawrocki } 98*86be408bSSylwester Nawrocki if (clkspec.np == node && !clk_supplier) 99*86be408bSSylwester Nawrocki return 0; 100*86be408bSSylwester Nawrocki 101*86be408bSSylwester Nawrocki clk = of_clk_get_by_clkspec(&clkspec); 102*86be408bSSylwester Nawrocki if (IS_ERR(clk)) { 103*86be408bSSylwester Nawrocki pr_warn("clk: couldn't get clock %d for %s\n", 104*86be408bSSylwester Nawrocki index, node->full_name); 105*86be408bSSylwester Nawrocki return PTR_ERR(clk); 106*86be408bSSylwester Nawrocki } 107*86be408bSSylwester Nawrocki 108*86be408bSSylwester Nawrocki rc = clk_set_rate(clk, rate); 109*86be408bSSylwester Nawrocki if (rc < 0) 110*86be408bSSylwester Nawrocki pr_err("clk: couldn't set %s clock rate: %d\n", 111*86be408bSSylwester Nawrocki __clk_get_name(clk), rc); 112*86be408bSSylwester Nawrocki clk_put(clk); 113*86be408bSSylwester Nawrocki } 114*86be408bSSylwester Nawrocki index++; 115*86be408bSSylwester Nawrocki } 116*86be408bSSylwester Nawrocki return 0; 117*86be408bSSylwester Nawrocki } 118*86be408bSSylwester Nawrocki 119*86be408bSSylwester Nawrocki /** 120*86be408bSSylwester Nawrocki * of_clk_set_defaults() - parse and set assigned clocks configuration 121*86be408bSSylwester Nawrocki * @node: device node to apply clock settings for 122*86be408bSSylwester Nawrocki * @clk_supplier: true if clocks supplied by @node should also be considered 123*86be408bSSylwester Nawrocki * 124*86be408bSSylwester Nawrocki * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties 125*86be408bSSylwester Nawrocki * and sets any specified clock parents and rates. The @clk_supplier argument 126*86be408bSSylwester Nawrocki * should be set to true if @node may be also a clock supplier of any clock 127*86be408bSSylwester Nawrocki * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties. 128*86be408bSSylwester Nawrocki * If @clk_supplier is false the function exits returnning 0 as soon as it 129*86be408bSSylwester Nawrocki * determines the @node is also a supplier of any of the clocks. 130*86be408bSSylwester Nawrocki */ 131*86be408bSSylwester Nawrocki int of_clk_set_defaults(struct device_node *node, bool clk_supplier) 132*86be408bSSylwester Nawrocki { 133*86be408bSSylwester Nawrocki int rc; 134*86be408bSSylwester Nawrocki 135*86be408bSSylwester Nawrocki if (!node) 136*86be408bSSylwester Nawrocki return 0; 137*86be408bSSylwester Nawrocki 138*86be408bSSylwester Nawrocki rc = __set_clk_parents(node, clk_supplier); 139*86be408bSSylwester Nawrocki if (rc < 0) 140*86be408bSSylwester Nawrocki return rc; 141*86be408bSSylwester Nawrocki 142*86be408bSSylwester Nawrocki return __set_clk_rates(node, clk_supplier); 143*86be408bSSylwester Nawrocki } 144