Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2014 MediaTek Inc.
0004  * Author: James Liao <jamesjj.liao@mediatek.com>
0005  */
0006 
0007 #include <linux/bitops.h>
0008 #include <linux/clk-provider.h>
0009 #include <linux/err.h>
0010 #include <linux/io.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_device.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/slab.h>
0017 
0018 #include "clk-mtk.h"
0019 #include "clk-gate.h"
0020 
0021 struct clk_hw_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
0022 {
0023     int i;
0024     struct clk_hw_onecell_data *clk_data;
0025 
0026     clk_data = kzalloc(struct_size(clk_data, hws, clk_num), GFP_KERNEL);
0027     if (!clk_data)
0028         return NULL;
0029 
0030     clk_data->num = clk_num;
0031 
0032     for (i = 0; i < clk_num; i++)
0033         clk_data->hws[i] = ERR_PTR(-ENOENT);
0034 
0035     return clk_data;
0036 }
0037 EXPORT_SYMBOL_GPL(mtk_alloc_clk_data);
0038 
0039 void mtk_free_clk_data(struct clk_hw_onecell_data *clk_data)
0040 {
0041     kfree(clk_data);
0042 }
0043 EXPORT_SYMBOL_GPL(mtk_free_clk_data);
0044 
0045 int mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
0046                 struct clk_hw_onecell_data *clk_data)
0047 {
0048     int i;
0049     struct clk_hw *hw;
0050 
0051     if (!clk_data)
0052         return -ENOMEM;
0053 
0054     for (i = 0; i < num; i++) {
0055         const struct mtk_fixed_clk *rc = &clks[i];
0056 
0057         if (!IS_ERR_OR_NULL(clk_data->hws[rc->id])) {
0058             pr_warn("Trying to register duplicate clock ID: %d\n", rc->id);
0059             continue;
0060         }
0061 
0062         hw = clk_hw_register_fixed_rate(NULL, rc->name, rc->parent, 0,
0063                           rc->rate);
0064 
0065         if (IS_ERR(hw)) {
0066             pr_err("Failed to register clk %s: %pe\n", rc->name,
0067                    hw);
0068             goto err;
0069         }
0070 
0071         clk_data->hws[rc->id] = hw;
0072     }
0073 
0074     return 0;
0075 
0076 err:
0077     while (--i >= 0) {
0078         const struct mtk_fixed_clk *rc = &clks[i];
0079 
0080         if (IS_ERR_OR_NULL(clk_data->hws[rc->id]))
0081             continue;
0082 
0083         clk_unregister_fixed_rate(clk_data->hws[rc->id]->clk);
0084         clk_data->hws[rc->id] = ERR_PTR(-ENOENT);
0085     }
0086 
0087     return PTR_ERR(hw);
0088 }
0089 EXPORT_SYMBOL_GPL(mtk_clk_register_fixed_clks);
0090 
0091 void mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
0092                    struct clk_hw_onecell_data *clk_data)
0093 {
0094     int i;
0095 
0096     if (!clk_data)
0097         return;
0098 
0099     for (i = num; i > 0; i--) {
0100         const struct mtk_fixed_clk *rc = &clks[i - 1];
0101 
0102         if (IS_ERR_OR_NULL(clk_data->hws[rc->id]))
0103             continue;
0104 
0105         clk_unregister_fixed_rate(clk_data->hws[rc->id]->clk);
0106         clk_data->hws[rc->id] = ERR_PTR(-ENOENT);
0107     }
0108 }
0109 EXPORT_SYMBOL_GPL(mtk_clk_unregister_fixed_clks);
0110 
0111 int mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
0112                  struct clk_hw_onecell_data *clk_data)
0113 {
0114     int i;
0115     struct clk_hw *hw;
0116 
0117     if (!clk_data)
0118         return -ENOMEM;
0119 
0120     for (i = 0; i < num; i++) {
0121         const struct mtk_fixed_factor *ff = &clks[i];
0122 
0123         if (!IS_ERR_OR_NULL(clk_data->hws[ff->id])) {
0124             pr_warn("Trying to register duplicate clock ID: %d\n", ff->id);
0125             continue;
0126         }
0127 
0128         hw = clk_hw_register_fixed_factor(NULL, ff->name, ff->parent_name,
0129                 CLK_SET_RATE_PARENT, ff->mult, ff->div);
0130 
0131         if (IS_ERR(hw)) {
0132             pr_err("Failed to register clk %s: %pe\n", ff->name,
0133                    hw);
0134             goto err;
0135         }
0136 
0137         clk_data->hws[ff->id] = hw;
0138     }
0139 
0140     return 0;
0141 
0142 err:
0143     while (--i >= 0) {
0144         const struct mtk_fixed_factor *ff = &clks[i];
0145 
0146         if (IS_ERR_OR_NULL(clk_data->hws[ff->id]))
0147             continue;
0148 
0149         clk_unregister_fixed_factor(clk_data->hws[ff->id]->clk);
0150         clk_data->hws[ff->id] = ERR_PTR(-ENOENT);
0151     }
0152 
0153     return PTR_ERR(hw);
0154 }
0155 EXPORT_SYMBOL_GPL(mtk_clk_register_factors);
0156 
0157 void mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
0158                 struct clk_hw_onecell_data *clk_data)
0159 {
0160     int i;
0161 
0162     if (!clk_data)
0163         return;
0164 
0165     for (i = num; i > 0; i--) {
0166         const struct mtk_fixed_factor *ff = &clks[i - 1];
0167 
0168         if (IS_ERR_OR_NULL(clk_data->hws[ff->id]))
0169             continue;
0170 
0171         clk_unregister_fixed_factor(clk_data->hws[ff->id]->clk);
0172         clk_data->hws[ff->id] = ERR_PTR(-ENOENT);
0173     }
0174 }
0175 EXPORT_SYMBOL_GPL(mtk_clk_unregister_factors);
0176 
0177 static struct clk_hw *mtk_clk_register_composite(const struct mtk_composite *mc,
0178         void __iomem *base, spinlock_t *lock)
0179 {
0180     struct clk_hw *hw;
0181     struct clk_mux *mux = NULL;
0182     struct clk_gate *gate = NULL;
0183     struct clk_divider *div = NULL;
0184     struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
0185     const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
0186     const char * const *parent_names;
0187     const char *parent;
0188     int num_parents;
0189     int ret;
0190 
0191     if (mc->mux_shift >= 0) {
0192         mux = kzalloc(sizeof(*mux), GFP_KERNEL);
0193         if (!mux)
0194             return ERR_PTR(-ENOMEM);
0195 
0196         mux->reg = base + mc->mux_reg;
0197         mux->mask = BIT(mc->mux_width) - 1;
0198         mux->shift = mc->mux_shift;
0199         mux->lock = lock;
0200         mux->flags = mc->mux_flags;
0201         mux_hw = &mux->hw;
0202         mux_ops = &clk_mux_ops;
0203 
0204         parent_names = mc->parent_names;
0205         num_parents = mc->num_parents;
0206     } else {
0207         parent = mc->parent;
0208         parent_names = &parent;
0209         num_parents = 1;
0210     }
0211 
0212     if (mc->gate_shift >= 0) {
0213         gate = kzalloc(sizeof(*gate), GFP_KERNEL);
0214         if (!gate) {
0215             ret = -ENOMEM;
0216             goto err_out;
0217         }
0218 
0219         gate->reg = base + mc->gate_reg;
0220         gate->bit_idx = mc->gate_shift;
0221         gate->flags = CLK_GATE_SET_TO_DISABLE;
0222         gate->lock = lock;
0223 
0224         gate_hw = &gate->hw;
0225         gate_ops = &clk_gate_ops;
0226     }
0227 
0228     if (mc->divider_shift >= 0) {
0229         div = kzalloc(sizeof(*div), GFP_KERNEL);
0230         if (!div) {
0231             ret = -ENOMEM;
0232             goto err_out;
0233         }
0234 
0235         div->reg = base + mc->divider_reg;
0236         div->shift = mc->divider_shift;
0237         div->width = mc->divider_width;
0238         div->lock = lock;
0239 
0240         div_hw = &div->hw;
0241         div_ops = &clk_divider_ops;
0242     }
0243 
0244     hw = clk_hw_register_composite(NULL, mc->name, parent_names, num_parents,
0245         mux_hw, mux_ops,
0246         div_hw, div_ops,
0247         gate_hw, gate_ops,
0248         mc->flags);
0249 
0250     if (IS_ERR(hw)) {
0251         ret = PTR_ERR(hw);
0252         goto err_out;
0253     }
0254 
0255     return hw;
0256 err_out:
0257     kfree(div);
0258     kfree(gate);
0259     kfree(mux);
0260 
0261     return ERR_PTR(ret);
0262 }
0263 
0264 static void mtk_clk_unregister_composite(struct clk_hw *hw)
0265 {
0266     struct clk_composite *composite;
0267     struct clk_mux *mux = NULL;
0268     struct clk_gate *gate = NULL;
0269     struct clk_divider *div = NULL;
0270 
0271     if (!hw)
0272         return;
0273 
0274     composite = to_clk_composite(hw);
0275     if (composite->mux_hw)
0276         mux = to_clk_mux(composite->mux_hw);
0277     if (composite->gate_hw)
0278         gate = to_clk_gate(composite->gate_hw);
0279     if (composite->rate_hw)
0280         div = to_clk_divider(composite->rate_hw);
0281 
0282     clk_hw_unregister_composite(hw);
0283     kfree(div);
0284     kfree(gate);
0285     kfree(mux);
0286 }
0287 
0288 int mtk_clk_register_composites(const struct mtk_composite *mcs, int num,
0289                 void __iomem *base, spinlock_t *lock,
0290                 struct clk_hw_onecell_data *clk_data)
0291 {
0292     struct clk_hw *hw;
0293     int i;
0294 
0295     if (!clk_data)
0296         return -ENOMEM;
0297 
0298     for (i = 0; i < num; i++) {
0299         const struct mtk_composite *mc = &mcs[i];
0300 
0301         if (!IS_ERR_OR_NULL(clk_data->hws[mc->id])) {
0302             pr_warn("Trying to register duplicate clock ID: %d\n",
0303                 mc->id);
0304             continue;
0305         }
0306 
0307         hw = mtk_clk_register_composite(mc, base, lock);
0308 
0309         if (IS_ERR(hw)) {
0310             pr_err("Failed to register clk %s: %pe\n", mc->name,
0311                    hw);
0312             goto err;
0313         }
0314 
0315         clk_data->hws[mc->id] = hw;
0316     }
0317 
0318     return 0;
0319 
0320 err:
0321     while (--i >= 0) {
0322         const struct mtk_composite *mc = &mcs[i];
0323 
0324         if (IS_ERR_OR_NULL(clk_data->hws[mcs->id]))
0325             continue;
0326 
0327         mtk_clk_unregister_composite(clk_data->hws[mc->id]);
0328         clk_data->hws[mc->id] = ERR_PTR(-ENOENT);
0329     }
0330 
0331     return PTR_ERR(hw);
0332 }
0333 EXPORT_SYMBOL_GPL(mtk_clk_register_composites);
0334 
0335 void mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
0336                    struct clk_hw_onecell_data *clk_data)
0337 {
0338     int i;
0339 
0340     if (!clk_data)
0341         return;
0342 
0343     for (i = num; i > 0; i--) {
0344         const struct mtk_composite *mc = &mcs[i - 1];
0345 
0346         if (IS_ERR_OR_NULL(clk_data->hws[mc->id]))
0347             continue;
0348 
0349         mtk_clk_unregister_composite(clk_data->hws[mc->id]);
0350         clk_data->hws[mc->id] = ERR_PTR(-ENOENT);
0351     }
0352 }
0353 EXPORT_SYMBOL_GPL(mtk_clk_unregister_composites);
0354 
0355 int mtk_clk_register_dividers(const struct mtk_clk_divider *mcds, int num,
0356                   void __iomem *base, spinlock_t *lock,
0357                   struct clk_hw_onecell_data *clk_data)
0358 {
0359     struct clk_hw *hw;
0360     int i;
0361 
0362     if (!clk_data)
0363         return -ENOMEM;
0364 
0365     for (i = 0; i <  num; i++) {
0366         const struct mtk_clk_divider *mcd = &mcds[i];
0367 
0368         if (!IS_ERR_OR_NULL(clk_data->hws[mcd->id])) {
0369             pr_warn("Trying to register duplicate clock ID: %d\n",
0370                 mcd->id);
0371             continue;
0372         }
0373 
0374         hw = clk_hw_register_divider(NULL, mcd->name, mcd->parent_name,
0375             mcd->flags, base +  mcd->div_reg, mcd->div_shift,
0376             mcd->div_width, mcd->clk_divider_flags, lock);
0377 
0378         if (IS_ERR(hw)) {
0379             pr_err("Failed to register clk %s: %pe\n", mcd->name,
0380                    hw);
0381             goto err;
0382         }
0383 
0384         clk_data->hws[mcd->id] = hw;
0385     }
0386 
0387     return 0;
0388 
0389 err:
0390     while (--i >= 0) {
0391         const struct mtk_clk_divider *mcd = &mcds[i];
0392 
0393         if (IS_ERR_OR_NULL(clk_data->hws[mcd->id]))
0394             continue;
0395 
0396         mtk_clk_unregister_composite(clk_data->hws[mcd->id]);
0397         clk_data->hws[mcd->id] = ERR_PTR(-ENOENT);
0398     }
0399 
0400     return PTR_ERR(hw);
0401 }
0402 
0403 void mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
0404                  struct clk_hw_onecell_data *clk_data)
0405 {
0406     int i;
0407 
0408     if (!clk_data)
0409         return;
0410 
0411     for (i = num; i > 0; i--) {
0412         const struct mtk_clk_divider *mcd = &mcds[i - 1];
0413 
0414         if (IS_ERR_OR_NULL(clk_data->hws[mcd->id]))
0415             continue;
0416 
0417         clk_unregister_divider(clk_data->hws[mcd->id]->clk);
0418         clk_data->hws[mcd->id] = ERR_PTR(-ENOENT);
0419     }
0420 }
0421 
0422 int mtk_clk_simple_probe(struct platform_device *pdev)
0423 {
0424     const struct mtk_clk_desc *mcd;
0425     struct clk_hw_onecell_data *clk_data;
0426     struct device_node *node = pdev->dev.of_node;
0427     int r;
0428 
0429     mcd = of_device_get_match_data(&pdev->dev);
0430     if (!mcd)
0431         return -EINVAL;
0432 
0433     clk_data = mtk_alloc_clk_data(mcd->num_clks);
0434     if (!clk_data)
0435         return -ENOMEM;
0436 
0437     r = mtk_clk_register_gates(node, mcd->clks, mcd->num_clks, clk_data);
0438     if (r)
0439         goto free_data;
0440 
0441     r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
0442     if (r)
0443         goto unregister_clks;
0444 
0445     platform_set_drvdata(pdev, clk_data);
0446 
0447     if (mcd->rst_desc) {
0448         r = mtk_register_reset_controller_with_dev(&pdev->dev,
0449                                mcd->rst_desc);
0450         if (r)
0451             goto unregister_clks;
0452     }
0453 
0454     return r;
0455 
0456 unregister_clks:
0457     mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
0458 free_data:
0459     mtk_free_clk_data(clk_data);
0460     return r;
0461 }
0462 
0463 int mtk_clk_simple_remove(struct platform_device *pdev)
0464 {
0465     const struct mtk_clk_desc *mcd = of_device_get_match_data(&pdev->dev);
0466     struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
0467     struct device_node *node = pdev->dev.of_node;
0468 
0469     of_clk_del_provider(node);
0470     mtk_clk_unregister_gates(mcd->clks, mcd->num_clks, clk_data);
0471     mtk_free_clk_data(clk_data);
0472 
0473     return 0;
0474 }
0475 
0476 MODULE_LICENSE("GPL");