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_bulk_devres { 33 struct clk_bulk_data *clks; 34 int num_clks; 35 }; 36 37 static void devm_clk_bulk_release(struct device *dev, void *res) 38 { 39 struct clk_bulk_devres *devres = res; 40 41 clk_bulk_put(devres->num_clks, devres->clks); 42 } 43 44 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, 45 struct clk_bulk_data *clks) 46 { 47 struct clk_bulk_devres *devres; 48 int ret; 49 50 devres = devres_alloc(devm_clk_bulk_release, 51 sizeof(*devres), GFP_KERNEL); 52 if (!devres) 53 return -ENOMEM; 54 55 ret = clk_bulk_get(dev, num_clks, clks); 56 if (!ret) { 57 devres->clks = clks; 58 devres->num_clks = num_clks; 59 devres_add(dev, devres); 60 } else { 61 devres_free(devres); 62 } 63 64 return ret; 65 } 66 EXPORT_SYMBOL_GPL(devm_clk_bulk_get); 67 68 int __must_check devm_clk_bulk_get_all(struct device *dev, 69 struct clk_bulk_data **clks) 70 { 71 struct clk_bulk_devres *devres; 72 int ret; 73 74 devres = devres_alloc(devm_clk_bulk_release, 75 sizeof(*devres), GFP_KERNEL); 76 if (!devres) 77 return -ENOMEM; 78 79 ret = clk_bulk_get_all(dev, &devres->clks); 80 if (ret > 0) { 81 *clks = devres->clks; 82 devres->num_clks = ret; 83 devres_add(dev, devres); 84 } else { 85 devres_free(devres); 86 } 87 88 return ret; 89 } 90 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); 91 92 static int devm_clk_match(struct device *dev, void *res, void *data) 93 { 94 struct clk **c = res; 95 if (!c || !*c) { 96 WARN_ON(!c || !*c); 97 return 0; 98 } 99 return *c == data; 100 } 101 102 void devm_clk_put(struct device *dev, struct clk *clk) 103 { 104 int ret; 105 106 ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); 107 108 WARN_ON(ret); 109 } 110 EXPORT_SYMBOL(devm_clk_put); 111 112 struct clk *devm_get_clk_from_child(struct device *dev, 113 struct device_node *np, const char *con_id) 114 { 115 struct clk **ptr, *clk; 116 117 ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); 118 if (!ptr) 119 return ERR_PTR(-ENOMEM); 120 121 clk = of_clk_get_by_name(np, con_id); 122 if (!IS_ERR(clk)) { 123 *ptr = clk; 124 devres_add(dev, ptr); 125 } else { 126 devres_free(ptr); 127 } 128 129 return clk; 130 } 131 EXPORT_SYMBOL(devm_get_clk_from_child); 132