Branch data Line data Source code
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 : 1 : static void devm_clk_release(struct device *dev, void *res) 8 : : { 9 : 1 : clk_put(*(struct clk **)res); 10 : 1 : } 11 : : 12 : 3 : 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 : 3 : if (!ptr) 18 : : return ERR_PTR(-ENOMEM); 19 : : 20 : 3 : clk = clk_get(dev, id); 21 : 3 : if (!IS_ERR(clk)) { 22 : 3 : *ptr = clk; 23 : 3 : devres_add(dev, ptr); 24 : : } else { 25 : 3 : devres_free(ptr); 26 : : } 27 : : 28 : 3 : return clk; 29 : : } 30 : : EXPORT_SYMBOL(devm_clk_get); 31 : : 32 : 0 : struct clk *devm_clk_get_optional(struct device *dev, const char *id) 33 : : { 34 : 0 : struct clk *clk = devm_clk_get(dev, id); 35 : : 36 : 0 : if (clk == ERR_PTR(-ENOENT)) 37 : : return NULL; 38 : : 39 : 0 : 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 : 0 : static void devm_clk_bulk_release(struct device *dev, void *res) 49 : : { 50 : : struct clk_bulk_devres *devres = res; 51 : : 52 : 0 : clk_bulk_put(devres->num_clks, devres->clks); 53 : 0 : } 54 : : 55 : 0 : 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 : 0 : if (!devres) 64 : : return -ENOMEM; 65 : : 66 : 0 : if (optional) 67 : 0 : ret = clk_bulk_get_optional(dev, num_clks, clks); 68 : : else 69 : 0 : ret = clk_bulk_get(dev, num_clks, clks); 70 : 0 : if (!ret) { 71 : 0 : devres->clks = clks; 72 : 0 : devres->num_clks = num_clks; 73 : 0 : devres_add(dev, devres); 74 : : } else { 75 : 0 : devres_free(devres); 76 : : } 77 : : 78 : 0 : return ret; 79 : : } 80 : : 81 : 0 : int __must_check devm_clk_bulk_get(struct device *dev, int num_clks, 82 : : struct clk_bulk_data *clks) 83 : : { 84 : 0 : return __devm_clk_bulk_get(dev, num_clks, clks, false); 85 : : } 86 : : EXPORT_SYMBOL_GPL(devm_clk_bulk_get); 87 : : 88 : 0 : int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks, 89 : : struct clk_bulk_data *clks) 90 : : { 91 : 0 : return __devm_clk_bulk_get(dev, num_clks, clks, true); 92 : : } 93 : : EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional); 94 : : 95 : 0 : int __must_check devm_clk_bulk_get_all(struct device *dev, 96 : : struct clk_bulk_data **clks) 97 : : { 98 : : struct clk_bulk_devres *devres; 99 : : int ret; 100 : : 101 : : devres = devres_alloc(devm_clk_bulk_release, 102 : : sizeof(*devres), GFP_KERNEL); 103 : 0 : if (!devres) 104 : : return -ENOMEM; 105 : : 106 : 0 : ret = clk_bulk_get_all(dev, &devres->clks); 107 : 0 : if (ret > 0) { 108 : 0 : *clks = devres->clks; 109 : 0 : devres->num_clks = ret; 110 : 0 : devres_add(dev, devres); 111 : : } else { 112 : 0 : devres_free(devres); 113 : : } 114 : : 115 : 0 : return ret; 116 : : } 117 : : EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all); 118 : : 119 : 0 : static int devm_clk_match(struct device *dev, void *res, void *data) 120 : : { 121 : : struct clk **c = res; 122 : 0 : if (!c || !*c) { 123 : 0 : WARN_ON(!c || !*c); 124 : : return 0; 125 : : } 126 : 0 : return *c == data; 127 : : } 128 : : 129 : 0 : void devm_clk_put(struct device *dev, struct clk *clk) 130 : : { 131 : : int ret; 132 : : 133 : 0 : ret = devres_release(dev, devm_clk_release, devm_clk_match, clk); 134 : : 135 : 0 : WARN_ON(ret); 136 : 0 : } 137 : : EXPORT_SYMBOL(devm_clk_put); 138 : : 139 : 0 : struct clk *devm_get_clk_from_child(struct device *dev, 140 : : struct device_node *np, const char *con_id) 141 : : { 142 : : struct clk **ptr, *clk; 143 : : 144 : : ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); 145 : 0 : if (!ptr) 146 : : return ERR_PTR(-ENOMEM); 147 : : 148 : 0 : clk = of_clk_get_by_name(np, con_id); 149 : 0 : if (!IS_ERR(clk)) { 150 : 0 : *ptr = clk; 151 : 0 : devres_add(dev, ptr); 152 : : } else { 153 : 0 : devres_free(ptr); 154 : : } 155 : : 156 : 0 : return clk; 157 : : } 158 : : EXPORT_SYMBOL(devm_get_clk_from_child);