Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Hisilicon clock driver
0004  *
0005  * Copyright (c) 2012-2013 Hisilicon Limited.
0006  * Copyright (c) 2012-2013 Linaro Limited.
0007  *
0008  * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
0009  *     Xin Li <li.xin@linaro.org>
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/clkdev.h>
0014 #include <linux/clk-provider.h>
0015 #include <linux/delay.h>
0016 #include <linux/io.h>
0017 #include <linux/of.h>
0018 #include <linux/of_address.h>
0019 #include <linux/of_device.h>
0020 #include <linux/slab.h>
0021 
0022 #include "clk.h"
0023 
0024 static DEFINE_SPINLOCK(hisi_clk_lock);
0025 
0026 struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev,
0027                         int nr_clks)
0028 {
0029     struct hisi_clock_data *clk_data;
0030     struct resource *res;
0031     struct clk **clk_table;
0032 
0033     clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
0034     if (!clk_data)
0035         return NULL;
0036 
0037     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0038     if (!res)
0039         return NULL;
0040     clk_data->base = devm_ioremap(&pdev->dev,
0041                 res->start, resource_size(res));
0042     if (!clk_data->base)
0043         return NULL;
0044 
0045     clk_table = devm_kmalloc_array(&pdev->dev, nr_clks,
0046                        sizeof(*clk_table),
0047                        GFP_KERNEL);
0048     if (!clk_table)
0049         return NULL;
0050 
0051     clk_data->clk_data.clks = clk_table;
0052     clk_data->clk_data.clk_num = nr_clks;
0053 
0054     return clk_data;
0055 }
0056 EXPORT_SYMBOL_GPL(hisi_clk_alloc);
0057 
0058 struct hisi_clock_data *hisi_clk_init(struct device_node *np,
0059                          int nr_clks)
0060 {
0061     struct hisi_clock_data *clk_data;
0062     struct clk **clk_table;
0063     void __iomem *base;
0064 
0065     base = of_iomap(np, 0);
0066     if (!base) {
0067         pr_err("%s: failed to map clock registers\n", __func__);
0068         goto err;
0069     }
0070 
0071     clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
0072     if (!clk_data)
0073         goto err;
0074 
0075     clk_data->base = base;
0076     clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL);
0077     if (!clk_table)
0078         goto err_data;
0079 
0080     clk_data->clk_data.clks = clk_table;
0081     clk_data->clk_data.clk_num = nr_clks;
0082     of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
0083     return clk_data;
0084 err_data:
0085     kfree(clk_data);
0086 err:
0087     return NULL;
0088 }
0089 EXPORT_SYMBOL_GPL(hisi_clk_init);
0090 
0091 int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
0092                      int nums, struct hisi_clock_data *data)
0093 {
0094     struct clk *clk;
0095     int i;
0096 
0097     for (i = 0; i < nums; i++) {
0098         clk = clk_register_fixed_rate(NULL, clks[i].name,
0099                           clks[i].parent_name,
0100                           clks[i].flags,
0101                           clks[i].fixed_rate);
0102         if (IS_ERR(clk)) {
0103             pr_err("%s: failed to register clock %s\n",
0104                    __func__, clks[i].name);
0105             goto err;
0106         }
0107         data->clk_data.clks[clks[i].id] = clk;
0108     }
0109 
0110     return 0;
0111 
0112 err:
0113     while (i--)
0114         clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
0115 
0116     return PTR_ERR(clk);
0117 }
0118 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
0119 
0120 int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
0121                        int nums,
0122                        struct hisi_clock_data *data)
0123 {
0124     struct clk *clk;
0125     int i;
0126 
0127     for (i = 0; i < nums; i++) {
0128         clk = clk_register_fixed_factor(NULL, clks[i].name,
0129                         clks[i].parent_name,
0130                         clks[i].flags, clks[i].mult,
0131                         clks[i].div);
0132         if (IS_ERR(clk)) {
0133             pr_err("%s: failed to register clock %s\n",
0134                    __func__, clks[i].name);
0135             goto err;
0136         }
0137         data->clk_data.clks[clks[i].id] = clk;
0138     }
0139 
0140     return 0;
0141 
0142 err:
0143     while (i--)
0144         clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
0145 
0146     return PTR_ERR(clk);
0147 }
0148 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
0149 
0150 int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
0151                   int nums, struct hisi_clock_data *data)
0152 {
0153     struct clk *clk;
0154     void __iomem *base = data->base;
0155     int i;
0156 
0157     for (i = 0; i < nums; i++) {
0158         u32 mask = BIT(clks[i].width) - 1;
0159 
0160         clk = clk_register_mux_table(NULL, clks[i].name,
0161                     clks[i].parent_names,
0162                     clks[i].num_parents, clks[i].flags,
0163                     base + clks[i].offset, clks[i].shift,
0164                     mask, clks[i].mux_flags,
0165                     clks[i].table, &hisi_clk_lock);
0166         if (IS_ERR(clk)) {
0167             pr_err("%s: failed to register clock %s\n",
0168                    __func__, clks[i].name);
0169             goto err;
0170         }
0171 
0172         if (clks[i].alias)
0173             clk_register_clkdev(clk, clks[i].alias, NULL);
0174 
0175         data->clk_data.clks[clks[i].id] = clk;
0176     }
0177 
0178     return 0;
0179 
0180 err:
0181     while (i--)
0182         clk_unregister_mux(data->clk_data.clks[clks[i].id]);
0183 
0184     return PTR_ERR(clk);
0185 }
0186 EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
0187 
0188 int hisi_clk_register_phase(struct device *dev,
0189                 const struct hisi_phase_clock *clks,
0190                 int nums, struct hisi_clock_data *data)
0191 {
0192     void __iomem *base = data->base;
0193     struct clk *clk;
0194     int i;
0195 
0196     for (i = 0; i < nums; i++) {
0197         clk = clk_register_hisi_phase(dev, &clks[i], base,
0198                           &hisi_clk_lock);
0199         if (IS_ERR(clk)) {
0200             pr_err("%s: failed to register clock %s\n", __func__,
0201                    clks[i].name);
0202             return PTR_ERR(clk);
0203         }
0204 
0205         data->clk_data.clks[clks[i].id] = clk;
0206     }
0207 
0208     return 0;
0209 }
0210 EXPORT_SYMBOL_GPL(hisi_clk_register_phase);
0211 
0212 int hisi_clk_register_divider(const struct hisi_divider_clock *clks,
0213                       int nums, struct hisi_clock_data *data)
0214 {
0215     struct clk *clk;
0216     void __iomem *base = data->base;
0217     int i;
0218 
0219     for (i = 0; i < nums; i++) {
0220         clk = clk_register_divider_table(NULL, clks[i].name,
0221                          clks[i].parent_name,
0222                          clks[i].flags,
0223                          base + clks[i].offset,
0224                          clks[i].shift, clks[i].width,
0225                          clks[i].div_flags,
0226                          clks[i].table,
0227                          &hisi_clk_lock);
0228         if (IS_ERR(clk)) {
0229             pr_err("%s: failed to register clock %s\n",
0230                    __func__, clks[i].name);
0231             goto err;
0232         }
0233 
0234         if (clks[i].alias)
0235             clk_register_clkdev(clk, clks[i].alias, NULL);
0236 
0237         data->clk_data.clks[clks[i].id] = clk;
0238     }
0239 
0240     return 0;
0241 
0242 err:
0243     while (i--)
0244         clk_unregister_divider(data->clk_data.clks[clks[i].id]);
0245 
0246     return PTR_ERR(clk);
0247 }
0248 EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
0249 
0250 int hisi_clk_register_gate(const struct hisi_gate_clock *clks,
0251                        int nums, struct hisi_clock_data *data)
0252 {
0253     struct clk *clk;
0254     void __iomem *base = data->base;
0255     int i;
0256 
0257     for (i = 0; i < nums; i++) {
0258         clk = clk_register_gate(NULL, clks[i].name,
0259                         clks[i].parent_name,
0260                         clks[i].flags,
0261                         base + clks[i].offset,
0262                         clks[i].bit_idx,
0263                         clks[i].gate_flags,
0264                         &hisi_clk_lock);
0265         if (IS_ERR(clk)) {
0266             pr_err("%s: failed to register clock %s\n",
0267                    __func__, clks[i].name);
0268             goto err;
0269         }
0270 
0271         if (clks[i].alias)
0272             clk_register_clkdev(clk, clks[i].alias, NULL);
0273 
0274         data->clk_data.clks[clks[i].id] = clk;
0275     }
0276 
0277     return 0;
0278 
0279 err:
0280     while (i--)
0281         clk_unregister_gate(data->clk_data.clks[clks[i].id]);
0282 
0283     return PTR_ERR(clk);
0284 }
0285 EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
0286 
0287 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks,
0288                        int nums, struct hisi_clock_data *data)
0289 {
0290     struct clk *clk;
0291     void __iomem *base = data->base;
0292     int i;
0293 
0294     for (i = 0; i < nums; i++) {
0295         clk = hisi_register_clkgate_sep(NULL, clks[i].name,
0296                         clks[i].parent_name,
0297                         clks[i].flags,
0298                         base + clks[i].offset,
0299                         clks[i].bit_idx,
0300                         clks[i].gate_flags,
0301                         &hisi_clk_lock);
0302         if (IS_ERR(clk)) {
0303             pr_err("%s: failed to register clock %s\n",
0304                    __func__, clks[i].name);
0305             continue;
0306         }
0307 
0308         if (clks[i].alias)
0309             clk_register_clkdev(clk, clks[i].alias, NULL);
0310 
0311         data->clk_data.clks[clks[i].id] = clk;
0312     }
0313 }
0314 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);
0315 
0316 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks,
0317                     int nums, struct hisi_clock_data *data)
0318 {
0319     struct clk *clk;
0320     void __iomem *base = data->base;
0321     int i;
0322 
0323     for (i = 0; i < nums; i++) {
0324         clk = hi6220_register_clkdiv(NULL, clks[i].name,
0325                         clks[i].parent_name,
0326                         clks[i].flags,
0327                         base + clks[i].offset,
0328                         clks[i].shift,
0329                         clks[i].width,
0330                         clks[i].mask_bit,
0331                         &hisi_clk_lock);
0332         if (IS_ERR(clk)) {
0333             pr_err("%s: failed to register clock %s\n",
0334                    __func__, clks[i].name);
0335             continue;
0336         }
0337 
0338         if (clks[i].alias)
0339             clk_register_clkdev(clk, clks[i].alias, NULL);
0340 
0341         data->clk_data.clks[clks[i].id] = clk;
0342     }
0343 }