Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Intel Atom platform clocks driver for BayTrail and CherryTrail SoCs
0004  *
0005  * Copyright (C) 2016, Intel Corporation
0006  * Author: Irina Tirdea <irina.tirdea@intel.com>
0007  */
0008 
0009 #include <linux/clk-provider.h>
0010 #include <linux/clkdev.h>
0011 #include <linux/err.h>
0012 #include <linux/io.h>
0013 #include <linux/platform_data/x86/clk-pmc-atom.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/slab.h>
0016 
0017 #define PLT_CLK_NAME_BASE   "pmc_plt_clk"
0018 
0019 #define PMC_CLK_CTL_OFFSET      0x60
0020 #define PMC_CLK_CTL_SIZE        4
0021 #define PMC_CLK_NUM         6
0022 #define PMC_CLK_CTL_GATED_ON_D3     0x0
0023 #define PMC_CLK_CTL_FORCE_ON        0x1
0024 #define PMC_CLK_CTL_FORCE_OFF       0x2
0025 #define PMC_CLK_CTL_RESERVED        0x3
0026 #define PMC_MASK_CLK_CTL        GENMASK(1, 0)
0027 #define PMC_MASK_CLK_FREQ       BIT(2)
0028 #define PMC_CLK_FREQ_XTAL       (0 << 2)    /* 25 MHz */
0029 #define PMC_CLK_FREQ_PLL        (1 << 2)    /* 19.2 MHz */
0030 
0031 struct clk_plt_fixed {
0032     struct clk_hw *clk;
0033     struct clk_lookup *lookup;
0034 };
0035 
0036 struct clk_plt {
0037     struct clk_hw hw;
0038     void __iomem *reg;
0039     struct clk_lookup *lookup;
0040     /* protect access to PMC registers */
0041     spinlock_t lock;
0042 };
0043 
0044 #define to_clk_plt(_hw) container_of(_hw, struct clk_plt, hw)
0045 
0046 struct clk_plt_data {
0047     struct clk_plt_fixed **parents;
0048     u8 nparents;
0049     struct clk_plt *clks[PMC_CLK_NUM];
0050     struct clk_lookup *mclk_lookup;
0051     struct clk_lookup *ether_clk_lookup;
0052 };
0053 
0054 /* Return an index in parent table */
0055 static inline int plt_reg_to_parent(int reg)
0056 {
0057     switch (reg & PMC_MASK_CLK_FREQ) {
0058     default:
0059     case PMC_CLK_FREQ_XTAL:
0060         return 0;
0061     case PMC_CLK_FREQ_PLL:
0062         return 1;
0063     }
0064 }
0065 
0066 /* Return clk index of parent */
0067 static inline int plt_parent_to_reg(int index)
0068 {
0069     switch (index) {
0070     default:
0071     case 0:
0072         return PMC_CLK_FREQ_XTAL;
0073     case 1:
0074         return PMC_CLK_FREQ_PLL;
0075     }
0076 }
0077 
0078 /* Abstract status in simpler enabled/disabled value */
0079 static inline int plt_reg_to_enabled(int reg)
0080 {
0081     switch (reg & PMC_MASK_CLK_CTL) {
0082     case PMC_CLK_CTL_GATED_ON_D3:
0083     case PMC_CLK_CTL_FORCE_ON:
0084         return 1;   /* enabled */
0085     case PMC_CLK_CTL_FORCE_OFF:
0086     case PMC_CLK_CTL_RESERVED:
0087     default:
0088         return 0;   /* disabled */
0089     }
0090 }
0091 
0092 static void plt_clk_reg_update(struct clk_plt *clk, u32 mask, u32 val)
0093 {
0094     u32 tmp;
0095     unsigned long flags;
0096 
0097     spin_lock_irqsave(&clk->lock, flags);
0098 
0099     tmp = readl(clk->reg);
0100     tmp = (tmp & ~mask) | (val & mask);
0101     writel(tmp, clk->reg);
0102 
0103     spin_unlock_irqrestore(&clk->lock, flags);
0104 }
0105 
0106 static int plt_clk_set_parent(struct clk_hw *hw, u8 index)
0107 {
0108     struct clk_plt *clk = to_clk_plt(hw);
0109 
0110     plt_clk_reg_update(clk, PMC_MASK_CLK_FREQ, plt_parent_to_reg(index));
0111 
0112     return 0;
0113 }
0114 
0115 static u8 plt_clk_get_parent(struct clk_hw *hw)
0116 {
0117     struct clk_plt *clk = to_clk_plt(hw);
0118     u32 value;
0119 
0120     value = readl(clk->reg);
0121 
0122     return plt_reg_to_parent(value);
0123 }
0124 
0125 static int plt_clk_enable(struct clk_hw *hw)
0126 {
0127     struct clk_plt *clk = to_clk_plt(hw);
0128 
0129     plt_clk_reg_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_ON);
0130 
0131     return 0;
0132 }
0133 
0134 static void plt_clk_disable(struct clk_hw *hw)
0135 {
0136     struct clk_plt *clk = to_clk_plt(hw);
0137 
0138     plt_clk_reg_update(clk, PMC_MASK_CLK_CTL, PMC_CLK_CTL_FORCE_OFF);
0139 }
0140 
0141 static int plt_clk_is_enabled(struct clk_hw *hw)
0142 {
0143     struct clk_plt *clk = to_clk_plt(hw);
0144     u32 value;
0145 
0146     value = readl(clk->reg);
0147 
0148     return plt_reg_to_enabled(value);
0149 }
0150 
0151 static const struct clk_ops plt_clk_ops = {
0152     .enable = plt_clk_enable,
0153     .disable = plt_clk_disable,
0154     .is_enabled = plt_clk_is_enabled,
0155     .get_parent = plt_clk_get_parent,
0156     .set_parent = plt_clk_set_parent,
0157     .determine_rate = __clk_mux_determine_rate,
0158 };
0159 
0160 static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id,
0161                     const struct pmc_clk_data *pmc_data,
0162                     const char **parent_names,
0163                     int num_parents)
0164 {
0165     struct clk_plt *pclk;
0166     struct clk_init_data init;
0167     int ret;
0168 
0169     pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL);
0170     if (!pclk)
0171         return ERR_PTR(-ENOMEM);
0172 
0173     init.name =  kasprintf(GFP_KERNEL, "%s_%d", PLT_CLK_NAME_BASE, id);
0174     init.ops = &plt_clk_ops;
0175     init.flags = 0;
0176     init.parent_names = parent_names;
0177     init.num_parents = num_parents;
0178 
0179     pclk->hw.init = &init;
0180     pclk->reg = pmc_data->base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE;
0181     spin_lock_init(&pclk->lock);
0182 
0183     /*
0184      * On some systems, the pmc_plt_clocks already enabled by the
0185      * firmware are being marked as critical to avoid them being
0186      * gated by the clock framework.
0187      */
0188     if (pmc_data->critical && plt_clk_is_enabled(&pclk->hw))
0189         init.flags |= CLK_IS_CRITICAL;
0190 
0191     ret = devm_clk_hw_register(&pdev->dev, &pclk->hw);
0192     if (ret) {
0193         pclk = ERR_PTR(ret);
0194         goto err_free_init;
0195     }
0196 
0197     pclk->lookup = clkdev_hw_create(&pclk->hw, init.name, NULL);
0198     if (!pclk->lookup) {
0199         pclk = ERR_PTR(-ENOMEM);
0200         goto err_free_init;
0201     }
0202 
0203 err_free_init:
0204     kfree(init.name);
0205     return pclk;
0206 }
0207 
0208 static void plt_clk_unregister(struct clk_plt *pclk)
0209 {
0210     clkdev_drop(pclk->lookup);
0211 }
0212 
0213 static struct clk_plt_fixed *plt_clk_register_fixed_rate(struct platform_device *pdev,
0214                          const char *name,
0215                          const char *parent_name,
0216                          unsigned long fixed_rate)
0217 {
0218     struct clk_plt_fixed *pclk;
0219 
0220     pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL);
0221     if (!pclk)
0222         return ERR_PTR(-ENOMEM);
0223 
0224     pclk->clk = clk_hw_register_fixed_rate(&pdev->dev, name, parent_name,
0225                            0, fixed_rate);
0226     if (IS_ERR(pclk->clk))
0227         return ERR_CAST(pclk->clk);
0228 
0229     pclk->lookup = clkdev_hw_create(pclk->clk, name, NULL);
0230     if (!pclk->lookup) {
0231         clk_hw_unregister_fixed_rate(pclk->clk);
0232         return ERR_PTR(-ENOMEM);
0233     }
0234 
0235     return pclk;
0236 }
0237 
0238 static void plt_clk_unregister_fixed_rate(struct clk_plt_fixed *pclk)
0239 {
0240     clkdev_drop(pclk->lookup);
0241     clk_hw_unregister_fixed_rate(pclk->clk);
0242 }
0243 
0244 static void plt_clk_unregister_fixed_rate_loop(struct clk_plt_data *data,
0245                            unsigned int i)
0246 {
0247     while (i--)
0248         plt_clk_unregister_fixed_rate(data->parents[i]);
0249 }
0250 
0251 static void plt_clk_free_parent_names_loop(const char **parent_names,
0252                        unsigned int i)
0253 {
0254     while (i--)
0255         kfree_const(parent_names[i]);
0256     kfree(parent_names);
0257 }
0258 
0259 static void plt_clk_unregister_loop(struct clk_plt_data *data,
0260                     unsigned int i)
0261 {
0262     while (i--)
0263         plt_clk_unregister(data->clks[i]);
0264 }
0265 
0266 static const char **plt_clk_register_parents(struct platform_device *pdev,
0267                          struct clk_plt_data *data,
0268                          const struct pmc_clk *clks)
0269 {
0270     const char **parent_names;
0271     unsigned int i;
0272     int err;
0273     int nparents = 0;
0274 
0275     data->nparents = 0;
0276     while (clks[nparents].name)
0277         nparents++;
0278 
0279     data->parents = devm_kcalloc(&pdev->dev, nparents,
0280                      sizeof(*data->parents), GFP_KERNEL);
0281     if (!data->parents)
0282         return ERR_PTR(-ENOMEM);
0283 
0284     parent_names = kcalloc(nparents, sizeof(*parent_names),
0285                    GFP_KERNEL);
0286     if (!parent_names)
0287         return ERR_PTR(-ENOMEM);
0288 
0289     for (i = 0; i < nparents; i++) {
0290         data->parents[i] =
0291             plt_clk_register_fixed_rate(pdev, clks[i].name,
0292                             clks[i].parent_name,
0293                             clks[i].freq);
0294         if (IS_ERR(data->parents[i])) {
0295             err = PTR_ERR(data->parents[i]);
0296             goto err_unreg;
0297         }
0298         parent_names[i] = kstrdup_const(clks[i].name, GFP_KERNEL);
0299     }
0300 
0301     data->nparents = nparents;
0302     return parent_names;
0303 
0304 err_unreg:
0305     plt_clk_unregister_fixed_rate_loop(data, i);
0306     plt_clk_free_parent_names_loop(parent_names, i);
0307     return ERR_PTR(err);
0308 }
0309 
0310 static void plt_clk_unregister_parents(struct clk_plt_data *data)
0311 {
0312     plt_clk_unregister_fixed_rate_loop(data, data->nparents);
0313 }
0314 
0315 static int plt_clk_probe(struct platform_device *pdev)
0316 {
0317     const struct pmc_clk_data *pmc_data;
0318     const char **parent_names;
0319     struct clk_plt_data *data;
0320     unsigned int i;
0321     int err;
0322 
0323     pmc_data = dev_get_platdata(&pdev->dev);
0324     if (!pmc_data || !pmc_data->clks)
0325         return -EINVAL;
0326 
0327     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0328     if (!data)
0329         return -ENOMEM;
0330 
0331     parent_names = plt_clk_register_parents(pdev, data, pmc_data->clks);
0332     if (IS_ERR(parent_names))
0333         return PTR_ERR(parent_names);
0334 
0335     for (i = 0; i < PMC_CLK_NUM; i++) {
0336         data->clks[i] = plt_clk_register(pdev, i, pmc_data,
0337                          parent_names, data->nparents);
0338         if (IS_ERR(data->clks[i])) {
0339             err = PTR_ERR(data->clks[i]);
0340             goto err_unreg_clk_plt;
0341         }
0342     }
0343     data->mclk_lookup = clkdev_hw_create(&data->clks[3]->hw, "mclk", NULL);
0344     if (!data->mclk_lookup) {
0345         err = -ENOMEM;
0346         goto err_unreg_clk_plt;
0347     }
0348 
0349     data->ether_clk_lookup = clkdev_hw_create(&data->clks[4]->hw,
0350                           "ether_clk", NULL);
0351     if (!data->ether_clk_lookup) {
0352         err = -ENOMEM;
0353         goto err_drop_mclk;
0354     }
0355 
0356     plt_clk_free_parent_names_loop(parent_names, data->nparents);
0357 
0358     platform_set_drvdata(pdev, data);
0359     return 0;
0360 
0361 err_drop_mclk:
0362     clkdev_drop(data->mclk_lookup);
0363 err_unreg_clk_plt:
0364     plt_clk_unregister_loop(data, i);
0365     plt_clk_unregister_parents(data);
0366     plt_clk_free_parent_names_loop(parent_names, data->nparents);
0367     return err;
0368 }
0369 
0370 static int plt_clk_remove(struct platform_device *pdev)
0371 {
0372     struct clk_plt_data *data;
0373 
0374     data = platform_get_drvdata(pdev);
0375 
0376     clkdev_drop(data->ether_clk_lookup);
0377     clkdev_drop(data->mclk_lookup);
0378     plt_clk_unregister_loop(data, PMC_CLK_NUM);
0379     plt_clk_unregister_parents(data);
0380     return 0;
0381 }
0382 
0383 static struct platform_driver plt_clk_driver = {
0384     .driver = {
0385         .name = "clk-pmc-atom",
0386     },
0387     .probe = plt_clk_probe,
0388     .remove = plt_clk_remove,
0389 };
0390 builtin_platform_driver(plt_clk_driver);