Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/clk.h>
0003 #include <linux/device.h>
0004 #include <linux/export.h>
0005 #include <linux/gfp.h>
0006 
0007 struct devm_clk_state {
0008     struct clk *clk;
0009     void (*exit)(struct clk *clk);
0010 };
0011 
0012 static void devm_clk_release(struct device *dev, void *res)
0013 {
0014     struct devm_clk_state *state = res;
0015 
0016     if (state->exit)
0017         state->exit(state->clk);
0018 
0019     clk_put(state->clk);
0020 }
0021 
0022 static struct clk *__devm_clk_get(struct device *dev, const char *id,
0023                   struct clk *(*get)(struct device *dev, const char *id),
0024                   int (*init)(struct clk *clk),
0025                   void (*exit)(struct clk *clk))
0026 {
0027     struct devm_clk_state *state;
0028     struct clk *clk;
0029     int ret;
0030 
0031     state = devres_alloc(devm_clk_release, sizeof(*state), GFP_KERNEL);
0032     if (!state)
0033         return ERR_PTR(-ENOMEM);
0034 
0035     clk = get(dev, id);
0036     if (IS_ERR(clk)) {
0037         ret = PTR_ERR(clk);
0038         goto err_clk_get;
0039     }
0040 
0041     if (init) {
0042         ret = init(clk);
0043         if (ret)
0044             goto err_clk_init;
0045     }
0046 
0047     state->clk = clk;
0048     state->exit = exit;
0049 
0050     devres_add(dev, state);
0051 
0052     return clk;
0053 
0054 err_clk_init:
0055 
0056     clk_put(clk);
0057 err_clk_get:
0058 
0059     devres_free(state);
0060     return ERR_PTR(ret);
0061 }
0062 
0063 struct clk *devm_clk_get(struct device *dev, const char *id)
0064 {
0065     return __devm_clk_get(dev, id, clk_get, NULL, NULL);
0066 }
0067 EXPORT_SYMBOL(devm_clk_get);
0068 
0069 struct clk *devm_clk_get_prepared(struct device *dev, const char *id)
0070 {
0071     return __devm_clk_get(dev, id, clk_get, clk_prepare, clk_unprepare);
0072 }
0073 EXPORT_SYMBOL_GPL(devm_clk_get_prepared);
0074 
0075 struct clk *devm_clk_get_enabled(struct device *dev, const char *id)
0076 {
0077     return __devm_clk_get(dev, id, clk_get,
0078                   clk_prepare_enable, clk_disable_unprepare);
0079 }
0080 EXPORT_SYMBOL_GPL(devm_clk_get_enabled);
0081 
0082 struct clk *devm_clk_get_optional(struct device *dev, const char *id)
0083 {
0084     return __devm_clk_get(dev, id, clk_get_optional, NULL, NULL);
0085 }
0086 EXPORT_SYMBOL(devm_clk_get_optional);
0087 
0088 struct clk *devm_clk_get_optional_prepared(struct device *dev, const char *id)
0089 {
0090     return __devm_clk_get(dev, id, clk_get_optional,
0091                   clk_prepare, clk_unprepare);
0092 }
0093 EXPORT_SYMBOL_GPL(devm_clk_get_optional_prepared);
0094 
0095 struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
0096 {
0097     return __devm_clk_get(dev, id, clk_get_optional,
0098                   clk_prepare_enable, clk_disable_unprepare);
0099 }
0100 EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
0101 
0102 struct clk_bulk_devres {
0103     struct clk_bulk_data *clks;
0104     int num_clks;
0105 };
0106 
0107 static void devm_clk_bulk_release(struct device *dev, void *res)
0108 {
0109     struct clk_bulk_devres *devres = res;
0110 
0111     clk_bulk_put(devres->num_clks, devres->clks);
0112 }
0113 
0114 static int __devm_clk_bulk_get(struct device *dev, int num_clks,
0115                    struct clk_bulk_data *clks, bool optional)
0116 {
0117     struct clk_bulk_devres *devres;
0118     int ret;
0119 
0120     devres = devres_alloc(devm_clk_bulk_release,
0121                   sizeof(*devres), GFP_KERNEL);
0122     if (!devres)
0123         return -ENOMEM;
0124 
0125     if (optional)
0126         ret = clk_bulk_get_optional(dev, num_clks, clks);
0127     else
0128         ret = clk_bulk_get(dev, num_clks, clks);
0129     if (!ret) {
0130         devres->clks = clks;
0131         devres->num_clks = num_clks;
0132         devres_add(dev, devres);
0133     } else {
0134         devres_free(devres);
0135     }
0136 
0137     return ret;
0138 }
0139 
0140 int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
0141               struct clk_bulk_data *clks)
0142 {
0143     return __devm_clk_bulk_get(dev, num_clks, clks, false);
0144 }
0145 EXPORT_SYMBOL_GPL(devm_clk_bulk_get);
0146 
0147 int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
0148               struct clk_bulk_data *clks)
0149 {
0150     return __devm_clk_bulk_get(dev, num_clks, clks, true);
0151 }
0152 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_optional);
0153 
0154 static void devm_clk_bulk_release_all(struct device *dev, void *res)
0155 {
0156     struct clk_bulk_devres *devres = res;
0157 
0158     clk_bulk_put_all(devres->num_clks, devres->clks);
0159 }
0160 
0161 int __must_check devm_clk_bulk_get_all(struct device *dev,
0162                        struct clk_bulk_data **clks)
0163 {
0164     struct clk_bulk_devres *devres;
0165     int ret;
0166 
0167     devres = devres_alloc(devm_clk_bulk_release_all,
0168                   sizeof(*devres), GFP_KERNEL);
0169     if (!devres)
0170         return -ENOMEM;
0171 
0172     ret = clk_bulk_get_all(dev, &devres->clks);
0173     if (ret > 0) {
0174         *clks = devres->clks;
0175         devres->num_clks = ret;
0176         devres_add(dev, devres);
0177     } else {
0178         devres_free(devres);
0179     }
0180 
0181     return ret;
0182 }
0183 EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all);
0184 
0185 static int devm_clk_match(struct device *dev, void *res, void *data)
0186 {
0187     struct clk **c = res;
0188     if (!c || !*c) {
0189         WARN_ON(!c || !*c);
0190         return 0;
0191     }
0192     return *c == data;
0193 }
0194 
0195 void devm_clk_put(struct device *dev, struct clk *clk)
0196 {
0197     int ret;
0198 
0199     ret = devres_release(dev, devm_clk_release, devm_clk_match, clk);
0200 
0201     WARN_ON(ret);
0202 }
0203 EXPORT_SYMBOL(devm_clk_put);
0204 
0205 struct clk *devm_get_clk_from_child(struct device *dev,
0206                     struct device_node *np, const char *con_id)
0207 {
0208     struct clk **ptr, *clk;
0209 
0210     ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL);
0211     if (!ptr)
0212         return ERR_PTR(-ENOMEM);
0213 
0214     clk = of_clk_get_by_name(np, con_id);
0215     if (!IS_ERR(clk)) {
0216         *ptr = clk;
0217         devres_add(dev, ptr);
0218     } else {
0219         devres_free(ptr);
0220     }
0221 
0222     return clk;
0223 }
0224 EXPORT_SYMBOL(devm_get_clk_from_child);