at v5.2-rc7 142 lines 2.8 kB view raw
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 7static void devm_clk_release(struct device *dev, void *res) 8{ 9 clk_put(*(struct clk **)res); 10} 11 12struct clk *devm_clk_get(struct device *dev, const char *id) 13{ 14 struct clk **ptr, *clk; 15 16 ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); 17 if (!ptr) 18 return ERR_PTR(-ENOMEM); 19 20 clk = clk_get(dev, id); 21 if (!IS_ERR(clk)) { 22 *ptr = clk; 23 devres_add(dev, ptr); 24 } else { 25 devres_free(ptr); 26 } 27 28 return clk; 29} 30EXPORT_SYMBOL(devm_clk_get); 31 32struct clk *devm_clk_get_optional(struct device *dev, const char *id) 33{ 34 struct clk *clk = devm_clk_get(dev, id); 35 36 if (clk == ERR_PTR(-ENOENT)) 37 return NULL; 38 39 return clk; 40} 41EXPORT_SYMBOL(devm_clk_get_optional); 42 43struct clk_bulk_devres { 44 struct clk_bulk_data *clks; 45 int num_clks; 46}; 47 48static void devm_clk_bulk_release(struct device *dev, void *res) 49{ 50 struct clk_bulk_devres *devres = res; 51 52 clk_bulk_put(devres->num_clks, devres->clks); 53} 54 55int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, 56 struct clk_bulk_data *clks) 57{ 58 struct clk_bulk_devres *devres; 59 int ret; 60 61 devres = devres_alloc(devm_clk_bulk_release, 62 sizeof(*devres), GFP_KERNEL); 63 if (!devres) 64 return -ENOMEM; 65 66 ret = clk_bulk_get(dev, num_clks, clks); 67 if (!ret) { 68 devres->clks = clks; 69 devres->num_clks = num_clks; 70 devres_add(dev, devres); 71 } else { 72 devres_free(devres); 73 } 74 75 return ret; 76} 77EXPORT_SYMBOL_GPL(devm_clk_bulk_get); 78 79int __must_check devm_clk_bulk_get_all(struct device *dev, 80 struct clk_bulk_data **clks) 81{ 82 struct clk_bulk_devres *devres; 83 int ret; 84 85 devres = devres_alloc(devm_clk_bulk_release, 86 sizeof(*devres), GFP_KERNEL); 87 if (!devres) 88 return -ENOMEM; 89 90 ret = clk_bulk_get_all(dev, &devres->clks); 91 if (ret > 0) { 92 *clks = devres->clks; 93 devres->num_clks = ret; 94 devres_add(dev, devres); 95 } else { 96 devres_free(devres); 97 } 98 99 return ret; 100} 101EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); 102 103static int devm_clk_match(struct device *dev, void *res, void *data) 104{ 105 struct clk **c = res; 106 if (!c || !*c) { 107 WARN_ON(!c || !*c); 108 return 0; 109 } 110 return *c == data; 111} 112 113void devm_clk_put(struct device *dev, struct clk *clk) 114{ 115 int ret; 116 117 ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); 118 119 WARN_ON(ret); 120} 121EXPORT_SYMBOL(devm_clk_put); 122 123struct clk *devm_get_clk_from_child(struct device *dev, 124 struct device_node *np, const char *con_id) 125{ 126 struct clk **ptr, *clk; 127 128 ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); 129 if (!ptr) 130 return ERR_PTR(-ENOMEM); 131 132 clk = of_clk_get_by_name(np, con_id); 133 if (!IS_ERR(clk)) { 134 *ptr = clk; 135 devres_add(dev, ptr); 136 } else { 137 devres_free(ptr); 138 } 139 140 return clk; 141} 142EXPORT_SYMBOL(devm_get_clk_from_child);