Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * PRCMU clock implementation for ux500 platform.
0004  *
0005  * Copyright (C) 2012 ST-Ericsson SA
0006  * Author: Ulf Hansson <ulf.hansson@linaro.org>
0007  */
0008 
0009 #include <linux/clk-provider.h>
0010 #include <linux/mfd/dbx500-prcmu.h>
0011 #include <linux/slab.h>
0012 #include <linux/io.h>
0013 #include <linux/err.h>
0014 #include "clk.h"
0015 
0016 #define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw)
0017 #define to_clk_prcmu_clkout(_hw) container_of(_hw, struct clk_prcmu_clkout, hw)
0018 
0019 struct clk_prcmu {
0020     struct clk_hw hw;
0021     u8 cg_sel;
0022     int opp_requested;
0023 };
0024 
0025 struct clk_prcmu_clkout {
0026     struct clk_hw hw;
0027     u8 clkout_id;
0028     u8 source;
0029     u8 divider;
0030 };
0031 
0032 /* PRCMU clock operations. */
0033 
0034 static int clk_prcmu_prepare(struct clk_hw *hw)
0035 {
0036     struct clk_prcmu *clk = to_clk_prcmu(hw);
0037 
0038     return prcmu_request_clock(clk->cg_sel, true);
0039 }
0040 
0041 static void clk_prcmu_unprepare(struct clk_hw *hw)
0042 {
0043     struct clk_prcmu *clk = to_clk_prcmu(hw);
0044     if (prcmu_request_clock(clk->cg_sel, false))
0045         pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
0046                clk_hw_get_name(hw));
0047 }
0048 
0049 static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw,
0050                        unsigned long parent_rate)
0051 {
0052     struct clk_prcmu *clk = to_clk_prcmu(hw);
0053     return prcmu_clock_rate(clk->cg_sel);
0054 }
0055 
0056 static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate,
0057                  unsigned long *parent_rate)
0058 {
0059     struct clk_prcmu *clk = to_clk_prcmu(hw);
0060     return prcmu_round_clock_rate(clk->cg_sel, rate);
0061 }
0062 
0063 static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
0064                   unsigned long parent_rate)
0065 {
0066     struct clk_prcmu *clk = to_clk_prcmu(hw);
0067     return prcmu_set_clock_rate(clk->cg_sel, rate);
0068 }
0069 
0070 static int clk_prcmu_opp_prepare(struct clk_hw *hw)
0071 {
0072     int err;
0073     struct clk_prcmu *clk = to_clk_prcmu(hw);
0074 
0075     if (!clk->opp_requested) {
0076         err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
0077                         (char *)clk_hw_get_name(hw),
0078                         100);
0079         if (err) {
0080             pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
0081                 __func__, clk_hw_get_name(hw));
0082             return err;
0083         }
0084         clk->opp_requested = 1;
0085     }
0086 
0087     err = prcmu_request_clock(clk->cg_sel, true);
0088     if (err) {
0089         prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
0090                     (char *)clk_hw_get_name(hw));
0091         clk->opp_requested = 0;
0092         return err;
0093     }
0094 
0095     return 0;
0096 }
0097 
0098 static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
0099 {
0100     struct clk_prcmu *clk = to_clk_prcmu(hw);
0101 
0102     if (prcmu_request_clock(clk->cg_sel, false)) {
0103         pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
0104             clk_hw_get_name(hw));
0105         return;
0106     }
0107 
0108     if (clk->opp_requested) {
0109         prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
0110                     (char *)clk_hw_get_name(hw));
0111         clk->opp_requested = 0;
0112     }
0113 }
0114 
0115 static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
0116 {
0117     int err;
0118     struct clk_prcmu *clk = to_clk_prcmu(hw);
0119 
0120     if (!clk->opp_requested) {
0121         err = prcmu_request_ape_opp_100_voltage(true);
0122         if (err) {
0123             pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
0124                 __func__, clk_hw_get_name(hw));
0125             return err;
0126         }
0127         clk->opp_requested = 1;
0128     }
0129 
0130     err = prcmu_request_clock(clk->cg_sel, true);
0131     if (err) {
0132         prcmu_request_ape_opp_100_voltage(false);
0133         clk->opp_requested = 0;
0134         return err;
0135     }
0136 
0137     return 0;
0138 }
0139 
0140 static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
0141 {
0142     struct clk_prcmu *clk = to_clk_prcmu(hw);
0143 
0144     if (prcmu_request_clock(clk->cg_sel, false)) {
0145         pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
0146             clk_hw_get_name(hw));
0147         return;
0148     }
0149 
0150     if (clk->opp_requested) {
0151         prcmu_request_ape_opp_100_voltage(false);
0152         clk->opp_requested = 0;
0153     }
0154 }
0155 
0156 static const struct clk_ops clk_prcmu_scalable_ops = {
0157     .prepare = clk_prcmu_prepare,
0158     .unprepare = clk_prcmu_unprepare,
0159     .recalc_rate = clk_prcmu_recalc_rate,
0160     .round_rate = clk_prcmu_round_rate,
0161     .set_rate = clk_prcmu_set_rate,
0162 };
0163 
0164 static const struct clk_ops clk_prcmu_gate_ops = {
0165     .prepare = clk_prcmu_prepare,
0166     .unprepare = clk_prcmu_unprepare,
0167     .recalc_rate = clk_prcmu_recalc_rate,
0168 };
0169 
0170 static const struct clk_ops clk_prcmu_scalable_rate_ops = {
0171     .recalc_rate = clk_prcmu_recalc_rate,
0172     .round_rate = clk_prcmu_round_rate,
0173     .set_rate = clk_prcmu_set_rate,
0174 };
0175 
0176 static const struct clk_ops clk_prcmu_rate_ops = {
0177     .recalc_rate = clk_prcmu_recalc_rate,
0178 };
0179 
0180 static const struct clk_ops clk_prcmu_opp_gate_ops = {
0181     .prepare = clk_prcmu_opp_prepare,
0182     .unprepare = clk_prcmu_opp_unprepare,
0183     .recalc_rate = clk_prcmu_recalc_rate,
0184 };
0185 
0186 static const struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
0187     .prepare = clk_prcmu_opp_volt_prepare,
0188     .unprepare = clk_prcmu_opp_volt_unprepare,
0189     .recalc_rate = clk_prcmu_recalc_rate,
0190     .round_rate = clk_prcmu_round_rate,
0191     .set_rate = clk_prcmu_set_rate,
0192 };
0193 
0194 static struct clk_hw *clk_reg_prcmu(const char *name,
0195                     const char *parent_name,
0196                     u8 cg_sel,
0197                     unsigned long rate,
0198                     unsigned long flags,
0199                     const struct clk_ops *clk_prcmu_ops)
0200 {
0201     struct clk_prcmu *clk;
0202     struct clk_init_data clk_prcmu_init;
0203     int ret;
0204 
0205     if (!name) {
0206         pr_err("clk_prcmu: %s invalid arguments passed\n", __func__);
0207         return ERR_PTR(-EINVAL);
0208     }
0209 
0210     clk = kzalloc(sizeof(*clk), GFP_KERNEL);
0211     if (!clk)
0212         return ERR_PTR(-ENOMEM);
0213 
0214     clk->cg_sel = cg_sel;
0215     clk->opp_requested = 0;
0216     /* "rate" can be used for changing the initial frequency */
0217     if (rate)
0218         prcmu_set_clock_rate(cg_sel, rate);
0219 
0220     clk_prcmu_init.name = name;
0221     clk_prcmu_init.ops = clk_prcmu_ops;
0222     clk_prcmu_init.flags = flags;
0223     clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL);
0224     clk_prcmu_init.num_parents = (parent_name ? 1 : 0);
0225     clk->hw.init = &clk_prcmu_init;
0226 
0227     ret = clk_hw_register(NULL, &clk->hw);
0228     if (ret)
0229         goto free_clk;
0230 
0231     return &clk->hw;
0232 
0233 free_clk:
0234     kfree(clk);
0235     pr_err("clk_prcmu: %s failed to register clk\n", __func__);
0236     return ERR_PTR(-ENOMEM);
0237 }
0238 
0239 struct clk_hw *clk_reg_prcmu_scalable(const char *name,
0240                       const char *parent_name,
0241                       u8 cg_sel,
0242                       unsigned long rate,
0243                       unsigned long flags)
0244 {
0245     return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
0246             &clk_prcmu_scalable_ops);
0247 }
0248 
0249 struct clk_hw *clk_reg_prcmu_gate(const char *name,
0250                   const char *parent_name,
0251                   u8 cg_sel,
0252                   unsigned long flags)
0253 {
0254     return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
0255             &clk_prcmu_gate_ops);
0256 }
0257 
0258 struct clk_hw *clk_reg_prcmu_scalable_rate(const char *name,
0259                        const char *parent_name,
0260                        u8 cg_sel,
0261                        unsigned long rate,
0262                        unsigned long flags)
0263 {
0264     return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
0265             &clk_prcmu_scalable_rate_ops);
0266 }
0267 
0268 struct clk_hw *clk_reg_prcmu_rate(const char *name,
0269                   const char *parent_name,
0270                   u8 cg_sel,
0271                   unsigned long flags)
0272 {
0273     return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
0274             &clk_prcmu_rate_ops);
0275 }
0276 
0277 struct clk_hw *clk_reg_prcmu_opp_gate(const char *name,
0278                       const char *parent_name,
0279                       u8 cg_sel,
0280                       unsigned long flags)
0281 {
0282     return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
0283             &clk_prcmu_opp_gate_ops);
0284 }
0285 
0286 struct clk_hw *clk_reg_prcmu_opp_volt_scalable(const char *name,
0287                            const char *parent_name,
0288                            u8 cg_sel,
0289                            unsigned long rate,
0290                            unsigned long flags)
0291 {
0292     return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
0293             &clk_prcmu_opp_volt_scalable_ops);
0294 }
0295 
0296 /* The clkout (external) clock is special and need special ops */
0297 
0298 static int clk_prcmu_clkout_prepare(struct clk_hw *hw)
0299 {
0300     struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
0301 
0302     return prcmu_config_clkout(clk->clkout_id, clk->source, clk->divider);
0303 }
0304 
0305 static void clk_prcmu_clkout_unprepare(struct clk_hw *hw)
0306 {
0307     struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
0308     int ret;
0309 
0310     /* The clkout clock is disabled by dividing by 0 */
0311     ret = prcmu_config_clkout(clk->clkout_id, clk->source, 0);
0312     if (ret)
0313         pr_err("clk_prcmu: %s failed to disable %s\n", __func__,
0314                clk_hw_get_name(hw));
0315 }
0316 
0317 static unsigned long clk_prcmu_clkout_recalc_rate(struct clk_hw *hw,
0318                           unsigned long parent_rate)
0319 {
0320     struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
0321 
0322     return (parent_rate / clk->divider);
0323 }
0324 
0325 static u8 clk_prcmu_clkout_get_parent(struct clk_hw *hw)
0326 {
0327     struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
0328 
0329     return clk->source;
0330 }
0331 
0332 static int clk_prcmu_clkout_set_parent(struct clk_hw *hw, u8 index)
0333 {
0334     struct clk_prcmu_clkout *clk = to_clk_prcmu_clkout(hw);
0335 
0336     clk->source = index;
0337     /* Make sure the change reaches the hardware immediately */
0338     if (clk_hw_is_prepared(hw))
0339         return clk_prcmu_clkout_prepare(hw);
0340     return 0;
0341 }
0342 
0343 static const struct clk_ops clk_prcmu_clkout_ops = {
0344     .prepare = clk_prcmu_clkout_prepare,
0345     .unprepare = clk_prcmu_clkout_unprepare,
0346     .recalc_rate = clk_prcmu_clkout_recalc_rate,
0347     .get_parent = clk_prcmu_clkout_get_parent,
0348     .set_parent = clk_prcmu_clkout_set_parent,
0349 };
0350 
0351 struct clk_hw *clk_reg_prcmu_clkout(const char *name,
0352                     const char * const *parent_names,
0353                     int num_parents,
0354                     u8 source, u8 divider)
0355 
0356 {
0357     struct clk_prcmu_clkout *clk;
0358     struct clk_init_data clk_prcmu_clkout_init;
0359     u8 clkout_id;
0360     int ret;
0361 
0362     if (!name) {
0363         pr_err("clk_prcmu_clkout: %s invalid arguments passed\n", __func__);
0364         return ERR_PTR(-EINVAL);
0365     }
0366 
0367     if (!strcmp(name, "clkout1"))
0368         clkout_id = 0;
0369     else if (!strcmp(name, "clkout2"))
0370         clkout_id = 1;
0371     else {
0372         pr_err("clk_prcmu_clkout: %s bad clock name\n", __func__);
0373         return ERR_PTR(-EINVAL);
0374     }
0375 
0376     clk = kzalloc(sizeof(*clk), GFP_KERNEL);
0377     if (!clk)
0378         return ERR_PTR(-ENOMEM);
0379 
0380     clk->clkout_id = clkout_id;
0381     clk->source = source;
0382     clk->divider = divider;
0383 
0384     clk_prcmu_clkout_init.name = name;
0385     clk_prcmu_clkout_init.ops = &clk_prcmu_clkout_ops;
0386     clk_prcmu_clkout_init.flags = CLK_GET_RATE_NOCACHE;
0387     clk_prcmu_clkout_init.parent_names = parent_names;
0388     clk_prcmu_clkout_init.num_parents = num_parents;
0389     clk->hw.init = &clk_prcmu_clkout_init;
0390 
0391     ret = clk_hw_register(NULL, &clk->hw);
0392     if (ret)
0393         goto free_clkout;
0394 
0395     return &clk->hw;
0396 free_clkout:
0397     kfree(clk);
0398     pr_err("clk_prcmu_clkout: %s failed to register clk\n", __func__);
0399     return ERR_PTR(-ENOMEM);
0400 }