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 static void devm_clk_release(struct device *dev, void *res) 8 { 9 clk_put(*(struct clk **)res); 10 } 11 12 struct 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 } 30 EXPORT_SYMBOL(devm_clk_get); 31 32 struct 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 } 41 EXPORT_SYMBOL(devm_clk_get_optional); 42 43 struct clk_bulk_devres { 44 struct clk_bulk_data *clks; 45 int num_clks; 46 }; 47 48 static 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 55 static int __devm_clk_bulk_get(struct device *dev, int num_clks, 56 struct clk_bulk_data *clks, bool optional) 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 if (optional) 67 ret = clk_bulk_get_optional(dev, num_clks, clks); 68 else 69 ret = clk_bulk_get(dev, num_clks, clks); 70 if (!ret) { 71 devres->clks = clks; 72 devres->num_clks = num_clks; 73 devres_add(dev, devres); 74 } else { 75 devres_free(devres); 76 } 77 78 return ret; 79 } 80 81 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, 82 struct clk_bulk_data *clks) 83 { 84 return __devm_clk_bulk_get(dev, num_clks, clks, false); 85 } 86 EXPORT_SYMBOL_GPL(devm_clk_bulk_get); 87 88 int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, 89 struct clk_bulk_data *clks) 90 { 91 return __devm_clk_bulk_get(dev, num_clks, clks, true); 92 } 93 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional); 94 95 static void devm_clk_bulk_release_all(struct device *dev, void *res) 96 { 97 struct clk_bulk_devres *devres = res; 98 99 clk_bulk_put_all(devres->num_clks, devres->clks); 100 } 101 102 int __must_check devm_clk_bulk_get_all(struct device *dev, 103 struct clk_bulk_data **clks) 104 { 105 struct clk_bulk_devres *devres; 106 int ret; 107 108 devres = devres_alloc(devm_clk_bulk_release_all, 109 sizeof(*devres), GFP_KERNEL); 110 if (!devres) 111 return -ENOMEM; 112 113 ret = clk_bulk_get_all(dev, &devres->clks); 114 if (ret > 0) { 115 *clks = devres->clks; 116 devres->num_clks = ret; 117 devres_add(dev, devres); 118 } else { 119 devres_free(devres); 120 } 121 122 return ret; 123 } 124 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); 125 126 static int devm_clk_match(struct device *dev, void *res, void *data) 127 { 128 struct clk **c = res; 129 if (!c || !*c) { 130 WARN_ON(!c || !*c); 131 return 0; 132 } 133 return *c == data; 134 } 135 136 void devm_clk_put(struct device *dev, struct clk *clk) 137 { 138 int ret; 139 140 ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); 141 142 WARN_ON(ret); 143 } 144 EXPORT_SYMBOL(devm_clk_put); 145 146 struct clk *devm_get_clk_from_child(struct device *dev, 147 struct device_node *np, const char *con_id) 148 { 149 struct clk **ptr, *clk; 150 151 ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); 152 if (!ptr) 153 return ERR_PTR(-ENOMEM); 154 155 clk = of_clk_get_by_name(np, con_id); 156 if (!IS_ERR(clk)) { 157 *ptr = clk; 158 devres_add(dev, ptr); 159 } else { 160 devres_free(ptr); 161 } 162 163 return clk; 164 } 165 EXPORT_SYMBOL(devm_get_clk_from_child); 166