1ebafb63dSStephen Boyd // SPDX-License-Identifier: GPL-2.0 2266e4e9dSDong Aisheng /* 3266e4e9dSDong Aisheng * Copyright 2017 NXP 4266e4e9dSDong Aisheng * 5266e4e9dSDong Aisheng * Dong Aisheng <aisheng.dong@nxp.com> 6266e4e9dSDong Aisheng */ 7266e4e9dSDong Aisheng 8266e4e9dSDong Aisheng #include <linux/clk.h> 9616e45dfSDong Aisheng #include <linux/clk-provider.h> 10266e4e9dSDong Aisheng #include <linux/device.h> 11266e4e9dSDong Aisheng #include <linux/export.h> 12cfdc0411SDong Aisheng #include <linux/of.h> 13616e45dfSDong Aisheng #include <linux/slab.h> 14cfdc0411SDong Aisheng 15cfdc0411SDong Aisheng static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks, 16cfdc0411SDong Aisheng struct clk_bulk_data *clks) 17cfdc0411SDong Aisheng { 18cfdc0411SDong Aisheng int ret; 19cfdc0411SDong Aisheng int i; 20cfdc0411SDong Aisheng 21*7f81c242SBjorn Andersson for (i = 0; i < num_clks; i++) { 22*7f81c242SBjorn Andersson clks[i].id = NULL; 23cfdc0411SDong Aisheng clks[i].clk = NULL; 24*7f81c242SBjorn Andersson } 25cfdc0411SDong Aisheng 26cfdc0411SDong Aisheng for (i = 0; i < num_clks; i++) { 27*7f81c242SBjorn Andersson of_property_read_string_index(np, "clock-names", i, &clks[i].id); 28cfdc0411SDong Aisheng clks[i].clk = of_clk_get(np, i); 29cfdc0411SDong Aisheng if (IS_ERR(clks[i].clk)) { 30cfdc0411SDong Aisheng ret = PTR_ERR(clks[i].clk); 31cfdc0411SDong Aisheng pr_err("%pOF: Failed to get clk index: %d ret: %d\n", 32cfdc0411SDong Aisheng np, i, ret); 33cfdc0411SDong Aisheng clks[i].clk = NULL; 34cfdc0411SDong Aisheng goto err; 35cfdc0411SDong Aisheng } 36cfdc0411SDong Aisheng } 37cfdc0411SDong Aisheng 38cfdc0411SDong Aisheng return 0; 39cfdc0411SDong Aisheng 40cfdc0411SDong Aisheng err: 41cfdc0411SDong Aisheng clk_bulk_put(i, clks); 42cfdc0411SDong Aisheng 43cfdc0411SDong Aisheng return ret; 44cfdc0411SDong Aisheng } 45266e4e9dSDong Aisheng 46616e45dfSDong Aisheng static int __must_check of_clk_bulk_get_all(struct device_node *np, 47616e45dfSDong Aisheng struct clk_bulk_data **clks) 48616e45dfSDong Aisheng { 49616e45dfSDong Aisheng struct clk_bulk_data *clk_bulk; 50616e45dfSDong Aisheng int num_clks; 51616e45dfSDong Aisheng int ret; 52616e45dfSDong Aisheng 53616e45dfSDong Aisheng num_clks = of_clk_get_parent_count(np); 54616e45dfSDong Aisheng if (!num_clks) 55616e45dfSDong Aisheng return 0; 56616e45dfSDong Aisheng 57616e45dfSDong Aisheng clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL); 58616e45dfSDong Aisheng if (!clk_bulk) 59616e45dfSDong Aisheng return -ENOMEM; 60616e45dfSDong Aisheng 61616e45dfSDong Aisheng ret = of_clk_bulk_get(np, num_clks, clk_bulk); 62616e45dfSDong Aisheng if (ret) { 63616e45dfSDong Aisheng kfree(clk_bulk); 64616e45dfSDong Aisheng return ret; 65616e45dfSDong Aisheng } 66616e45dfSDong Aisheng 67616e45dfSDong Aisheng *clks = clk_bulk; 68616e45dfSDong Aisheng 69616e45dfSDong Aisheng return num_clks; 70616e45dfSDong Aisheng } 71616e45dfSDong Aisheng 72266e4e9dSDong Aisheng void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) 73266e4e9dSDong Aisheng { 74266e4e9dSDong Aisheng while (--num_clks >= 0) { 75266e4e9dSDong Aisheng clk_put(clks[num_clks].clk); 76266e4e9dSDong Aisheng clks[num_clks].clk = NULL; 77266e4e9dSDong Aisheng } 78266e4e9dSDong Aisheng } 79266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_put); 80266e4e9dSDong Aisheng 812f25528eSSylwester Nawrocki static int __clk_bulk_get(struct device *dev, int num_clks, 822f25528eSSylwester Nawrocki struct clk_bulk_data *clks, bool optional) 83266e4e9dSDong Aisheng { 84266e4e9dSDong Aisheng int ret; 85266e4e9dSDong Aisheng int i; 86266e4e9dSDong Aisheng 87266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) 88266e4e9dSDong Aisheng clks[i].clk = NULL; 89266e4e9dSDong Aisheng 90266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) { 91266e4e9dSDong Aisheng clks[i].clk = clk_get(dev, clks[i].id); 92266e4e9dSDong Aisheng if (IS_ERR(clks[i].clk)) { 93266e4e9dSDong Aisheng ret = PTR_ERR(clks[i].clk); 942f25528eSSylwester Nawrocki clks[i].clk = NULL; 952f25528eSSylwester Nawrocki 962f25528eSSylwester Nawrocki if (ret == -ENOENT && optional) 972f25528eSSylwester Nawrocki continue; 982f25528eSSylwester Nawrocki 99329470f2SJerome Brunet if (ret != -EPROBE_DEFER) 100266e4e9dSDong Aisheng dev_err(dev, "Failed to get clk '%s': %d\n", 101266e4e9dSDong Aisheng clks[i].id, ret); 102266e4e9dSDong Aisheng goto err; 103266e4e9dSDong Aisheng } 104266e4e9dSDong Aisheng } 105266e4e9dSDong Aisheng 106266e4e9dSDong Aisheng return 0; 107266e4e9dSDong Aisheng 108266e4e9dSDong Aisheng err: 109266e4e9dSDong Aisheng clk_bulk_put(i, clks); 110266e4e9dSDong Aisheng 111266e4e9dSDong Aisheng return ret; 112266e4e9dSDong Aisheng } 1132f25528eSSylwester Nawrocki 1142f25528eSSylwester Nawrocki int __must_check clk_bulk_get(struct device *dev, int num_clks, 1152f25528eSSylwester Nawrocki struct clk_bulk_data *clks) 1162f25528eSSylwester Nawrocki { 1172f25528eSSylwester Nawrocki return __clk_bulk_get(dev, num_clks, clks, false); 1182f25528eSSylwester Nawrocki } 119266e4e9dSDong Aisheng EXPORT_SYMBOL(clk_bulk_get); 120266e4e9dSDong Aisheng 1212f25528eSSylwester Nawrocki int __must_check clk_bulk_get_optional(struct device *dev, int num_clks, 1222f25528eSSylwester Nawrocki struct clk_bulk_data *clks) 1232f25528eSSylwester Nawrocki { 1242f25528eSSylwester Nawrocki return __clk_bulk_get(dev, num_clks, clks, true); 1252f25528eSSylwester Nawrocki } 1262f25528eSSylwester Nawrocki EXPORT_SYMBOL_GPL(clk_bulk_get_optional); 1272f25528eSSylwester Nawrocki 128616e45dfSDong Aisheng void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks) 129616e45dfSDong Aisheng { 130616e45dfSDong Aisheng if (IS_ERR_OR_NULL(clks)) 131616e45dfSDong Aisheng return; 132616e45dfSDong Aisheng 133616e45dfSDong Aisheng clk_bulk_put(num_clks, clks); 134616e45dfSDong Aisheng 135616e45dfSDong Aisheng kfree(clks); 136616e45dfSDong Aisheng } 137616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_put_all); 138616e45dfSDong Aisheng 139616e45dfSDong Aisheng int __must_check clk_bulk_get_all(struct device *dev, 140616e45dfSDong Aisheng struct clk_bulk_data **clks) 141616e45dfSDong Aisheng { 142616e45dfSDong Aisheng struct device_node *np = dev_of_node(dev); 143616e45dfSDong Aisheng 144616e45dfSDong Aisheng if (!np) 145616e45dfSDong Aisheng return 0; 146616e45dfSDong Aisheng 147616e45dfSDong Aisheng return of_clk_bulk_get_all(np, clks); 148616e45dfSDong Aisheng } 149616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_get_all); 150616e45dfSDong Aisheng 151266e4e9dSDong Aisheng #ifdef CONFIG_HAVE_CLK_PREPARE 152266e4e9dSDong Aisheng 153266e4e9dSDong Aisheng /** 154266e4e9dSDong Aisheng * clk_bulk_unprepare - undo preparation of a set of clock sources 155266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 156266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being unprepared 157266e4e9dSDong Aisheng * 158266e4e9dSDong Aisheng * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable. 159266e4e9dSDong Aisheng * Returns 0 on success, -EERROR otherwise. 160266e4e9dSDong Aisheng */ 161266e4e9dSDong Aisheng void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks) 162266e4e9dSDong Aisheng { 163266e4e9dSDong Aisheng while (--num_clks >= 0) 164266e4e9dSDong Aisheng clk_unprepare(clks[num_clks].clk); 165266e4e9dSDong Aisheng } 166266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_unprepare); 167266e4e9dSDong Aisheng 168266e4e9dSDong Aisheng /** 169266e4e9dSDong Aisheng * clk_bulk_prepare - prepare a set of clocks 170266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 171266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being prepared 172266e4e9dSDong Aisheng * 173266e4e9dSDong Aisheng * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable. 174266e4e9dSDong Aisheng * Returns 0 on success, -EERROR otherwise. 175266e4e9dSDong Aisheng */ 176266e4e9dSDong Aisheng int __must_check clk_bulk_prepare(int num_clks, 177266e4e9dSDong Aisheng const struct clk_bulk_data *clks) 178266e4e9dSDong Aisheng { 179266e4e9dSDong Aisheng int ret; 180266e4e9dSDong Aisheng int i; 181266e4e9dSDong Aisheng 182266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) { 183266e4e9dSDong Aisheng ret = clk_prepare(clks[i].clk); 184266e4e9dSDong Aisheng if (ret) { 185266e4e9dSDong Aisheng pr_err("Failed to prepare clk '%s': %d\n", 186266e4e9dSDong Aisheng clks[i].id, ret); 187266e4e9dSDong Aisheng goto err; 188266e4e9dSDong Aisheng } 189266e4e9dSDong Aisheng } 190266e4e9dSDong Aisheng 191266e4e9dSDong Aisheng return 0; 192266e4e9dSDong Aisheng 193266e4e9dSDong Aisheng err: 194266e4e9dSDong Aisheng clk_bulk_unprepare(i, clks); 195266e4e9dSDong Aisheng 196266e4e9dSDong Aisheng return ret; 197266e4e9dSDong Aisheng } 1989792bf5aSBjorn Andersson EXPORT_SYMBOL_GPL(clk_bulk_prepare); 199266e4e9dSDong Aisheng 200266e4e9dSDong Aisheng #endif /* CONFIG_HAVE_CLK_PREPARE */ 201266e4e9dSDong Aisheng 202266e4e9dSDong Aisheng /** 203266e4e9dSDong Aisheng * clk_bulk_disable - gate a set of clocks 204266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 205266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being gated 206266e4e9dSDong Aisheng * 207266e4e9dSDong Aisheng * clk_bulk_disable must not sleep, which differentiates it from 208266e4e9dSDong Aisheng * clk_bulk_unprepare. clk_bulk_disable must be called before 209266e4e9dSDong Aisheng * clk_bulk_unprepare. 210266e4e9dSDong Aisheng */ 211266e4e9dSDong Aisheng void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks) 212266e4e9dSDong Aisheng { 213266e4e9dSDong Aisheng 214266e4e9dSDong Aisheng while (--num_clks >= 0) 215266e4e9dSDong Aisheng clk_disable(clks[num_clks].clk); 216266e4e9dSDong Aisheng } 217266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_disable); 218266e4e9dSDong Aisheng 219266e4e9dSDong Aisheng /** 220266e4e9dSDong Aisheng * clk_bulk_enable - ungate a set of clocks 221266e4e9dSDong Aisheng * @num_clks: the number of clk_bulk_data 222266e4e9dSDong Aisheng * @clks: the clk_bulk_data table being ungated 223266e4e9dSDong Aisheng * 224266e4e9dSDong Aisheng * clk_bulk_enable must not sleep 225266e4e9dSDong Aisheng * Returns 0 on success, -EERROR otherwise. 226266e4e9dSDong Aisheng */ 227266e4e9dSDong Aisheng int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks) 228266e4e9dSDong Aisheng { 229266e4e9dSDong Aisheng int ret; 230266e4e9dSDong Aisheng int i; 231266e4e9dSDong Aisheng 232266e4e9dSDong Aisheng for (i = 0; i < num_clks; i++) { 233266e4e9dSDong Aisheng ret = clk_enable(clks[i].clk); 234266e4e9dSDong Aisheng if (ret) { 235266e4e9dSDong Aisheng pr_err("Failed to enable clk '%s': %d\n", 236266e4e9dSDong Aisheng clks[i].id, ret); 237266e4e9dSDong Aisheng goto err; 238266e4e9dSDong Aisheng } 239266e4e9dSDong Aisheng } 240266e4e9dSDong Aisheng 241266e4e9dSDong Aisheng return 0; 242266e4e9dSDong Aisheng 243266e4e9dSDong Aisheng err: 244266e4e9dSDong Aisheng clk_bulk_disable(i, clks); 245266e4e9dSDong Aisheng 246266e4e9dSDong Aisheng return ret; 247266e4e9dSDong Aisheng } 248266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_enable); 249