1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/clk.h> 3 #include <linux/device.h> 4 #include <linux/export.h> 5 #include <linux/gfp.h> 6 7 struct devm_clk_state { 8 struct clk *clk; 9 void (*exit)(struct clk *clk); 10 }; 11 12 static void devm_clk_release(struct device *dev, void *res) 13 { 14 struct devm_clk_state *state = *(struct devm_clk_state **)res; 15 16 if (state->exit) 17 state->exit(state->clk); 18 19 clk_put(state->clk); 20 } 21 22 static struct clk *__devm_clk_get(struct device *dev, const char *id, 23 struct clk *(*get)(struct device *dev, const char *id), 24 int (*init)(struct clk *clk), 25 void (*exit)(struct clk *clk)) 26 { 27 struct devm_clk_state *state; 28 struct clk *clk; 29 int ret; 30 31 state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL); 32 if (!state) 33 return ERR_PTR(-ENOMEM); 34 35 clk = get(dev, id); 36 if (IS_ERR(clk)) { 37 ret = PTR_ERR(clk); 38 goto err_clk_get; 39 } 40 41 if (init) { 42 ret = init(clk); 43 if (ret) 44 goto err_clk_init; 45 } 46 47 state->clk = clk; 48 state->exit = exit; 49 50 devres_add(dev, state); 51 52 return clk; 53 54 err_clk_init: 55 56 clk_put(clk); 57 err_clk_get: 58 59 devres_free(state); 60 return ERR_PTR(ret); 61 } 62 63 struct clk *devm_clk_get(struct device *dev, const char *id) 64 { 65 return __devm_clk_get(dev, id, clk_get, NULL, NULL); 66 } 67 EXPORT_SYMBOL(devm_clk_get); 68 69 struct clk *devm_clk_get_optional(struct device *dev, const char *id) 70 { 71 return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL); 72 } 73 EXPORT_SYMBOL(devm_clk_get_optional); 74 75 struct clk_bulk_devres { 76 struct clk_bulk_data *clks; 77 int num_clks; 78 }; 79 80 static void devm_clk_bulk_release(struct device *dev, void *res) 81 { 82 struct clk_bulk_devres *devres = res; 83 84 clk_bulk_put(devres->num_clks, devres->clks); 85 } 86 87 static int __devm_clk_bulk_get(struct device *dev, int num_clks, 88 struct clk_bulk_data *clks, bool optional) 89 { 90 struct clk_bulk_devres *devres; 91 int ret; 92 93 devres = devres_alloc(devm_clk_bulk_release, 94 sizeof(*devres), GFP_KERNEL); 95 if (!devres) 96 return -ENOMEM; 97 98 if (optional) 99 ret = clk_bulk_get_optional(dev, num_clks, clks); 100 else 101 ret = clk_bulk_get(dev, num_clks, clks); 102 if (!ret) { 103 devres->clks = clks; 104 devres->num_clks = num_clks; 105 devres_add(dev, devres); 106 } else { 107 devres_free(devres); 108 } 109 110 return ret; 111 } 112 113 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, 114 struct clk_bulk_data *clks) 115 { 116 return __devm_clk_bulk_get(dev, num_clks, clks, false); 117 } 118 EXPORT_SYMBOL_GPL(devm_clk_bulk_get); 119 120 int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, 121 struct clk_bulk_data *clks) 122 { 123 return __devm_clk_bulk_get(dev, num_clks, clks, true); 124 } 125 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional); 126 127 static void devm_clk_bulk_release_all(struct device *dev, void *res) 128 { 129 struct clk_bulk_devres *devres = res; 130 131 clk_bulk_put_all(devres->num_clks, devres->clks); 132 } 133 134 int __must_check devm_clk_bulk_get_all(struct device *dev, 135 struct clk_bulk_data **clks) 136 { 137 struct clk_bulk_devres *devres; 138 int ret; 139 140 devres = devres_alloc(devm_clk_bulk_release_all, 141 sizeof(*devres), GFP_KERNEL); 142 if (!devres) 143 return -ENOMEM; 144 145 ret = clk_bulk_get_all(dev, &devres->clks); 146 if (ret > 0) { 147 *clks = devres->clks; 148 devres->num_clks = ret; 149 devres_add(dev, devres); 150 } else { 151 devres_free(devres); 152 } 153 154 return ret; 155 } 156 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); 157 158 static int devm_clk_match(struct device *dev, void *res, void *data) 159 { 160 struct clk **c = res; 161 if (!c || !*c) { 162 WARN_ON(!c || !*c); 163 return 0; 164 } 165 return *c == data; 166 } 167 168 void devm_clk_put(struct device *dev, struct clk *clk) 169 { 170 int ret; 171 172 ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); 173 174 WARN_ON(ret); 175 } 176 EXPORT_SYMBOL(devm_clk_put); 177 178 struct clk *devm_get_clk_from_child(struct device *dev, 179 struct device_node *np, const char *con_id) 180 { 181 struct clk **ptr, *clk; 182 183 ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); 184 if (!ptr) 185 return ERR_PTR(-ENOMEM); 186 187 clk = of_clk_get_by_name(np, con_id); 188 if (!IS_ERR(clk)) { 189 *ptr = clk; 190 devres_add(dev, ptr); 191 } else { 192 devres_free(ptr); 193 } 194 195 return clk; 196 } 197 EXPORT_SYMBOL(devm_get_clk_from_child); 198