1266e4e9dSDong Aisheng /* 2266e4e9dSDong Aisheng * Copyright 2017 NXP 3266e4e9dSDong Aisheng * 4266e4e9dSDong Aisheng * Dong Aisheng <aisheng.dong@nxp.com> 5266e4e9dSDong Aisheng * 6266e4e9dSDong Aisheng * This program is free software; you can redistribute it and/or modify it 7266e4e9dSDong Aisheng * under the terms and conditions of the GNU General Public License, 8266e4e9dSDong Aisheng * version 2, as published by the Free Software Foundation. 9266e4e9dSDong Aisheng * 10266e4e9dSDong Aisheng * This program is distributed in the hope it will be useful, but WITHOUT 11266e4e9dSDong Aisheng * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12266e4e9dSDong Aisheng * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13266e4e9dSDong Aisheng * more details. 14266e4e9dSDong Aisheng * 15266e4e9dSDong Aisheng * You should have received a copy of the GNU General Public License 16266e4e9dSDong Aisheng * along with this program. If not, see <http://www.gnu.org/licenses/>. 17266e4e9dSDong Aisheng */ 18266e4e9dSDong Aisheng 19266e4e9dSDong Aisheng #include <linux/clk.h> 20*616e45dfSDong Aisheng #include <linux/clk-provider.h> 21266e4e9dSDong Aisheng #include <linux/device.h> 22266e4e9dSDong Aisheng #include <linux/export.h> 23cfdc0411SDong Aisheng #include <linux/of.h> 24*616e45dfSDong Aisheng #include <linux/slab.h> 25cfdc0411SDong Aisheng 26cfdc0411SDong Aisheng static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks, 27cfdc0411SDong Aisheng struct clk_bulk_data *clks) 28cfdc0411SDong Aisheng { 29cfdc0411SDong Aisheng int ret; 30cfdc0411SDong Aisheng int i; 31cfdc0411SDong Aisheng 32cfdc0411SDong Aisheng for (i = 0; i < num_clks; i++) 33cfdc0411SDong Aisheng clks[i].clk = NULL; 34cfdc0411SDong Aisheng 35cfdc0411SDong Aisheng for (i = 0; i < num_clks; i++) { 36cfdc0411SDong Aisheng clks[i].clk = of_clk_get(np, i); 37cfdc0411SDong Aisheng if (IS_ERR(clks[i].clk)) { 38cfdc0411SDong Aisheng ret = PTR_ERR(clks[i].clk); 39cfdc0411SDong Aisheng pr_err("%pOF: Failed to get clk index: %d ret: %d\n", 40cfdc0411SDong Aisheng np, i, ret); 41cfdc0411SDong Aisheng clks[i].clk = NULL; 42cfdc0411SDong Aisheng goto err; 43cfdc0411SDong Aisheng } 44cfdc0411SDong Aisheng } 45cfdc0411SDong Aisheng 46cfdc0411SDong Aisheng return 0; 47cfdc0411SDong Aisheng 48cfdc0411SDong Aisheng err: 49cfdc0411SDong Aisheng clk_bulk_put(i, clks); 50cfdc0411SDong Aisheng 51cfdc0411SDong Aisheng return ret; 52cfdc0411SDong Aisheng } 53266e4e9dSDong Aisheng 54*616e45dfSDong Aisheng static int __must_check of_clk_bulk_get_all(struct device_node *np, 55*616e45dfSDong Aisheng struct clk_bulk_data **clks) 56*616e45dfSDong Aisheng { 57*616e45dfSDong Aisheng struct clk_bulk_data *clk_bulk; 58*616e45dfSDong Aisheng int num_clks; 59*616e45dfSDong Aisheng int ret; 60*616e45dfSDong Aisheng 61*616e45dfSDong Aisheng num_clks = of_clk_get_parent_count(np); 62*616e45dfSDong Aisheng if (!num_clks) 63*616e45dfSDong Aisheng return 0; 64*616e45dfSDong Aisheng 65*616e45dfSDong Aisheng clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL); 66*616e45dfSDong Aisheng if (!clk_bulk) 67*616e45dfSDong Aisheng return -ENOMEM; 68*616e45dfSDong Aisheng 69*616e45dfSDong Aisheng ret = of_clk_bulk_get(np, num_clks, clk_bulk); 70*616e45dfSDong Aisheng if (ret) { 71*616e45dfSDong Aisheng kfree(clk_bulk); 72*616e45dfSDong Aisheng return ret; 73*616e45dfSDong Aisheng } 74*616e45dfSDong Aisheng 75*616e45dfSDong Aisheng *clks = clk_bulk; 76*616e45dfSDong Aisheng 77*616e45dfSDong Aisheng return num_clks; 78*616e45dfSDong Aisheng } 79*616e45dfSDong Aisheng 80266e4e9dSDong Aisheng void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) 81266e4e9dSDong Aisheng { 82266e4e9dSDong Aisheng while (--num_clks >= 0) { 83266e4e9dSDong Aisheng clk_put(clks[num_clks].clk); 84266e4e9dSDong Aisheng clks[num_clks].clk = NULL; 85266e4e9dSDong Aisheng } 86266e4e9dSDong Aisheng } 87266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_put); 88266e4e9dSDong Aisheng 89266e4e9dSDong Aisheng int __must_check clk_bulk_get(struct device *dev, int num_clks, 90266e4e9dSDong Aisheng struct clk_bulk_data *clks) 91266e4e9dSDong Aisheng { 92266e4e9dSDong Aisheng int ret; 93266e4e9dSDong Aisheng int i; 94266e4e9dSDong Aisheng 95266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) 96266e4e9dSDong Aisheng clks[i].clk = NULL; 97266e4e9dSDong Aisheng 98266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) { 99266e4e9dSDong Aisheng clks[i].clk = clk_get(dev, clks[i].id); 100266e4e9dSDong Aisheng if (IS_ERR(clks[i].clk)) { 101266e4e9dSDong Aisheng ret = PTR_ERR(clks[i].clk); 102329470f2SJerome Brunet if (ret != -EPROBE_DEFER) 103266e4e9dSDong Aisheng dev_err(dev, "Failed to get clk '%s': %d\n", 104266e4e9dSDong Aisheng clks[i].id, ret); 105266e4e9dSDong Aisheng clks[i].clk = NULL; 106266e4e9dSDong Aisheng goto err; 107266e4e9dSDong Aisheng } 108266e4e9dSDong Aisheng } 109266e4e9dSDong Aisheng 110266e4e9dSDong Aisheng return 0; 111266e4e9dSDong Aisheng 112266e4e9dSDong Aisheng err: 113266e4e9dSDong Aisheng clk_bulk_put(i, clks); 114266e4e9dSDong Aisheng 115266e4e9dSDong Aisheng return ret; 116266e4e9dSDong Aisheng } 117266e4e9dSDong Aisheng EXPORT_SYMBOL(clk_bulk_get); 118266e4e9dSDong Aisheng 119*616e45dfSDong Aisheng void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks) 120*616e45dfSDong Aisheng { 121*616e45dfSDong Aisheng if (IS_ERR_OR_NULL(clks)) 122*616e45dfSDong Aisheng return; 123*616e45dfSDong Aisheng 124*616e45dfSDong Aisheng clk_bulk_put(num_clks, clks); 125*616e45dfSDong Aisheng 126*616e45dfSDong Aisheng kfree(clks); 127*616e45dfSDong Aisheng } 128*616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_put_all); 129*616e45dfSDong Aisheng 130*616e45dfSDong Aisheng int __must_check clk_bulk_get_all(struct device *dev, 131*616e45dfSDong Aisheng struct clk_bulk_data **clks) 132*616e45dfSDong Aisheng { 133*616e45dfSDong Aisheng struct device_node *np = dev_of_node(dev); 134*616e45dfSDong Aisheng 135*616e45dfSDong Aisheng if (!np) 136*616e45dfSDong Aisheng return 0; 137*616e45dfSDong Aisheng 138*616e45dfSDong Aisheng return of_clk_bulk_get_all(np, clks); 139*616e45dfSDong Aisheng } 140*616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_get_all); 141*616e45dfSDong Aisheng 142266e4e9dSDong Aisheng #ifdef CONFIG_HAVE_CLK_PREPARE 143266e4e9dSDong Aisheng 144266e4e9dSDong Aisheng /** 145266e4e9dSDong Aisheng * clk_bulk_unprepare - undo preparation of a set of clock sources 146266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 147266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being unprepared 148266e4e9dSDong Aisheng * 149266e4e9dSDong Aisheng * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable. 150266e4e9dSDong Aisheng * Returns 0 on success, -EERROR otherwise. 151266e4e9dSDong Aisheng */ 152266e4e9dSDong Aisheng void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks) 153266e4e9dSDong Aisheng { 154266e4e9dSDong Aisheng while (--num_clks >= 0) 155266e4e9dSDong Aisheng clk_unprepare(clks[num_clks].clk); 156266e4e9dSDong Aisheng } 157266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_unprepare); 158266e4e9dSDong Aisheng 159266e4e9dSDong Aisheng /** 160266e4e9dSDong Aisheng * clk_bulk_prepare - prepare a set of clocks 161266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 162266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being prepared 163266e4e9dSDong Aisheng * 164266e4e9dSDong Aisheng * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable. 165266e4e9dSDong Aisheng * Returns 0 on success, -EERROR otherwise. 166266e4e9dSDong Aisheng */ 167266e4e9dSDong Aisheng int __must_check clk_bulk_prepare(int num_clks, 168266e4e9dSDong Aisheng const struct clk_bulk_data *clks) 169266e4e9dSDong Aisheng { 170266e4e9dSDong Aisheng int ret; 171266e4e9dSDong Aisheng int i; 172266e4e9dSDong Aisheng 173266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) { 174266e4e9dSDong Aisheng ret = clk_prepare(clks[i].clk); 175266e4e9dSDong Aisheng if (ret) { 176266e4e9dSDong Aisheng pr_err("Failed to prepare clk '%s': %d\n", 177266e4e9dSDong Aisheng clks[i].id, ret); 178266e4e9dSDong Aisheng goto err; 179266e4e9dSDong Aisheng } 180266e4e9dSDong Aisheng } 181266e4e9dSDong Aisheng 182266e4e9dSDong Aisheng return 0; 183266e4e9dSDong Aisheng 184266e4e9dSDong Aisheng err: 185266e4e9dSDong Aisheng clk_bulk_unprepare(i, clks); 186266e4e9dSDong Aisheng 187266e4e9dSDong Aisheng return ret; 188266e4e9dSDong Aisheng } 1899792bf5aSBjorn Andersson EXPORT_SYMBOL_GPL(clk_bulk_prepare); 190266e4e9dSDong Aisheng 191266e4e9dSDong Aisheng #endif /* CONFIG_HAVE_CLK_PREPARE */ 192266e4e9dSDong Aisheng 193266e4e9dSDong Aisheng /** 194266e4e9dSDong Aisheng * clk_bulk_disable - gate a set of clocks 195266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 196266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being gated 197266e4e9dSDong Aisheng * 198266e4e9dSDong Aisheng * clk_bulk_disable must not sleep, which differentiates it from 199266e4e9dSDong Aisheng * clk_bulk_unprepare. clk_bulk_disable must be called before 200266e4e9dSDong Aisheng * clk_bulk_unprepare. 201266e4e9dSDong Aisheng */ 202266e4e9dSDong Aisheng void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks) 203266e4e9dSDong Aisheng { 204266e4e9dSDong Aisheng 205266e4e9dSDong Aisheng while (--num_clks >= 0) 206266e4e9dSDong Aisheng clk_disable(clks[num_clks].clk); 207266e4e9dSDong Aisheng } 208266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_disable); 209266e4e9dSDong Aisheng 210266e4e9dSDong Aisheng /** 211266e4e9dSDong Aisheng * clk_bulk_enable - ungate a set of clocks 212266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 213266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being ungated 214266e4e9dSDong Aisheng * 215266e4e9dSDong Aisheng * clk_bulk_enable must not sleep 216266e4e9dSDong Aisheng * Returns 0 on success, -EERROR otherwise. 217266e4e9dSDong Aisheng */ 218266e4e9dSDong Aisheng int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks) 219266e4e9dSDong Aisheng { 220266e4e9dSDong Aisheng int ret; 221266e4e9dSDong Aisheng int i; 222266e4e9dSDong Aisheng 223266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) { 224266e4e9dSDong Aisheng ret = clk_enable(clks[i].clk); 225266e4e9dSDong Aisheng if (ret) { 226266e4e9dSDong Aisheng pr_err("Failed to enable clk '%s': %d\n", 227266e4e9dSDong Aisheng clks[i].id, ret); 228266e4e9dSDong Aisheng goto err; 229266e4e9dSDong Aisheng } 230266e4e9dSDong Aisheng } 231266e4e9dSDong Aisheng 232266e4e9dSDong Aisheng return 0; 233266e4e9dSDong Aisheng 234266e4e9dSDong Aisheng err: 235266e4e9dSDong Aisheng clk_bulk_disable(i, clks); 236266e4e9dSDong Aisheng 237266e4e9dSDong Aisheng return ret; 238266e4e9dSDong Aisheng } 239266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_enable); 240