Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Microchip LAN966x SoC Clock driver.
0004  *
0005  * Copyright (C) 2021 Microchip Technology, Inc. and its subsidiaries
0006  *
0007  * Author: Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>
0008  */
0009 
0010 #include <linux/bitfield.h>
0011 #include <linux/clk-provider.h>
0012 #include <linux/io.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/slab.h>
0018 
0019 #include <dt-bindings/clock/microchip,lan966x.h>
0020 
0021 #define GCK_ENA         BIT(0)
0022 #define GCK_SRC_SEL     GENMASK(9, 8)
0023 #define GCK_PRESCALER   GENMASK(23, 16)
0024 
0025 #define DIV_MAX     255
0026 
0027 static const char *clk_names[N_CLOCKS] = {
0028     "qspi0", "qspi1", "qspi2", "sdmmc0",
0029     "pi", "mcan0", "mcan1", "flexcom0",
0030     "flexcom1", "flexcom2", "flexcom3",
0031     "flexcom4", "timer1", "usb_refclk",
0032 };
0033 
0034 struct lan966x_gck {
0035     struct clk_hw hw;
0036     void __iomem *reg;
0037 };
0038 #define to_lan966x_gck(hw) container_of(hw, struct lan966x_gck, hw)
0039 
0040 static const struct clk_parent_data lan966x_gck_pdata[] = {
0041     { .fw_name = "cpu", },
0042     { .fw_name = "ddr", },
0043     { .fw_name = "sys", },
0044 };
0045 
0046 static struct clk_init_data init = {
0047     .parent_data = lan966x_gck_pdata,
0048     .num_parents = ARRAY_SIZE(lan966x_gck_pdata),
0049 };
0050 
0051 struct clk_gate_soc_desc {
0052     const char *name;
0053     int bit_idx;
0054 };
0055 
0056 static const struct clk_gate_soc_desc clk_gate_desc[] = {
0057     { "uhphs", 11 },
0058     { "udphs", 10 },
0059     { "mcramc", 9 },
0060     { "hmatrix", 8 },
0061     { }
0062 };
0063 
0064 static DEFINE_SPINLOCK(clk_gate_lock);
0065 static void __iomem *base;
0066 
0067 static int lan966x_gck_enable(struct clk_hw *hw)
0068 {
0069     struct lan966x_gck *gck = to_lan966x_gck(hw);
0070     u32 val = readl(gck->reg);
0071 
0072     val |= GCK_ENA;
0073     writel(val, gck->reg);
0074 
0075     return 0;
0076 }
0077 
0078 static void lan966x_gck_disable(struct clk_hw *hw)
0079 {
0080     struct lan966x_gck *gck = to_lan966x_gck(hw);
0081     u32 val = readl(gck->reg);
0082 
0083     val &= ~GCK_ENA;
0084     writel(val, gck->reg);
0085 }
0086 
0087 static int lan966x_gck_set_rate(struct clk_hw *hw,
0088                 unsigned long rate,
0089                 unsigned long parent_rate)
0090 {
0091     struct lan966x_gck *gck = to_lan966x_gck(hw);
0092     u32 div, val = readl(gck->reg);
0093 
0094     if (rate == 0 || parent_rate == 0)
0095         return -EINVAL;
0096 
0097     /* Set Prescalar */
0098     div = parent_rate / rate;
0099     val &= ~GCK_PRESCALER;
0100     val |= FIELD_PREP(GCK_PRESCALER, (div - 1));
0101     writel(val, gck->reg);
0102 
0103     return 0;
0104 }
0105 
0106 static long lan966x_gck_round_rate(struct clk_hw *hw, unsigned long rate,
0107                    unsigned long *parent_rate)
0108 {
0109     unsigned int div;
0110 
0111     if (rate == 0 || *parent_rate == 0)
0112         return -EINVAL;
0113 
0114     if (rate >= *parent_rate)
0115         return *parent_rate;
0116 
0117     div = DIV_ROUND_CLOSEST(*parent_rate, rate);
0118 
0119     return *parent_rate / div;
0120 }
0121 
0122 static unsigned long lan966x_gck_recalc_rate(struct clk_hw *hw,
0123                          unsigned long parent_rate)
0124 {
0125     struct lan966x_gck *gck = to_lan966x_gck(hw);
0126     u32 div, val = readl(gck->reg);
0127 
0128     div = FIELD_GET(GCK_PRESCALER, val);
0129 
0130     return parent_rate / (div + 1);
0131 }
0132 
0133 static int lan966x_gck_determine_rate(struct clk_hw *hw,
0134                       struct clk_rate_request *req)
0135 {
0136     struct clk_hw *parent;
0137     int i;
0138 
0139     for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
0140         parent = clk_hw_get_parent_by_index(hw, i);
0141         if (!parent)
0142             continue;
0143 
0144         /* Allowed prescaler divider range is 0-255 */
0145         if (clk_hw_get_rate(parent) / req->rate <= DIV_MAX) {
0146             req->best_parent_hw = parent;
0147             req->best_parent_rate = clk_hw_get_rate(parent);
0148 
0149             return 0;
0150         }
0151     }
0152 
0153     return -EINVAL;
0154 }
0155 
0156 static u8 lan966x_gck_get_parent(struct clk_hw *hw)
0157 {
0158     struct lan966x_gck *gck = to_lan966x_gck(hw);
0159     u32 val = readl(gck->reg);
0160 
0161     return FIELD_GET(GCK_SRC_SEL, val);
0162 }
0163 
0164 static int lan966x_gck_set_parent(struct clk_hw *hw, u8 index)
0165 {
0166     struct lan966x_gck *gck = to_lan966x_gck(hw);
0167     u32 val = readl(gck->reg);
0168 
0169     val &= ~GCK_SRC_SEL;
0170     val |= FIELD_PREP(GCK_SRC_SEL, index);
0171     writel(val, gck->reg);
0172 
0173     return 0;
0174 }
0175 
0176 static const struct clk_ops lan966x_gck_ops = {
0177     .enable         = lan966x_gck_enable,
0178     .disable        = lan966x_gck_disable,
0179     .set_rate       = lan966x_gck_set_rate,
0180     .round_rate     = lan966x_gck_round_rate,
0181     .recalc_rate    = lan966x_gck_recalc_rate,
0182     .determine_rate = lan966x_gck_determine_rate,
0183     .set_parent     = lan966x_gck_set_parent,
0184     .get_parent     = lan966x_gck_get_parent,
0185 };
0186 
0187 static struct clk_hw *lan966x_gck_clk_register(struct device *dev, int i)
0188 {
0189     struct lan966x_gck *priv;
0190     int ret;
0191 
0192     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0193     if (!priv)
0194         return ERR_PTR(-ENOMEM);
0195 
0196     priv->reg = base + (i * 4);
0197     priv->hw.init = &init;
0198     ret = devm_clk_hw_register(dev, &priv->hw);
0199     if (ret)
0200         return ERR_PTR(ret);
0201 
0202     return &priv->hw;
0203 };
0204 
0205 static int lan966x_gate_clk_register(struct device *dev,
0206                      struct clk_hw_onecell_data *hw_data,
0207                      void __iomem *gate_base)
0208 {
0209     int i;
0210 
0211     for (i = GCK_GATE_UHPHS; i < N_CLOCKS; ++i) {
0212         int idx = i - GCK_GATE_UHPHS;
0213 
0214         hw_data->hws[i] =
0215             devm_clk_hw_register_gate(dev, clk_gate_desc[idx].name,
0216                           "lan966x", 0, gate_base,
0217                           clk_gate_desc[idx].bit_idx,
0218                           0, &clk_gate_lock);
0219 
0220         if (IS_ERR(hw_data->hws[i]))
0221             return dev_err_probe(dev, PTR_ERR(hw_data->hws[i]),
0222                          "failed to register %s clock\n",
0223                          clk_gate_desc[idx].name);
0224     }
0225 
0226     return 0;
0227 }
0228 
0229 static int lan966x_clk_probe(struct platform_device *pdev)
0230 {
0231     struct clk_hw_onecell_data *hw_data;
0232     struct device *dev = &pdev->dev;
0233     void __iomem *gate_base;
0234     struct resource *res;
0235     int i, ret;
0236 
0237     hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, N_CLOCKS),
0238                    GFP_KERNEL);
0239     if (!hw_data)
0240         return -ENOMEM;
0241 
0242     base = devm_platform_ioremap_resource(pdev, 0);
0243     if (IS_ERR(base))
0244         return PTR_ERR(base);
0245 
0246     init.ops = &lan966x_gck_ops;
0247 
0248     hw_data->num = GCK_GATE_UHPHS;
0249 
0250     for (i = 0; i < GCK_GATE_UHPHS; i++) {
0251         init.name = clk_names[i];
0252         hw_data->hws[i] = lan966x_gck_clk_register(dev, i);
0253         if (IS_ERR(hw_data->hws[i])) {
0254             dev_err(dev, "failed to register %s clock\n",
0255                 init.name);
0256             return PTR_ERR(hw_data->hws[i]);
0257         }
0258     }
0259 
0260     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0261     if (res) {
0262         gate_base = devm_ioremap_resource(&pdev->dev, res);
0263         if (IS_ERR(gate_base))
0264             return PTR_ERR(gate_base);
0265 
0266         hw_data->num = N_CLOCKS;
0267 
0268         ret = lan966x_gate_clk_register(dev, hw_data, gate_base);
0269         if (ret)
0270             return ret;
0271     }
0272 
0273     return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, hw_data);
0274 }
0275 
0276 static const struct of_device_id lan966x_clk_dt_ids[] = {
0277     { .compatible = "microchip,lan966x-gck", },
0278     { }
0279 };
0280 MODULE_DEVICE_TABLE(of, lan966x_clk_dt_ids);
0281 
0282 static struct platform_driver lan966x_clk_driver = {
0283     .probe  = lan966x_clk_probe,
0284     .driver = {
0285         .name = "lan966x-clk",
0286         .of_match_table = lan966x_clk_dt_ids,
0287     },
0288 };
0289 builtin_platform_driver(lan966x_clk_driver);
0290 
0291 MODULE_AUTHOR("Kavyasree Kotagiri <kavyasree.kotagiri@microchip.com>");
0292 MODULE_DESCRIPTION("LAN966X clock driver");
0293 MODULE_LICENSE("GPL v2");