Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 Socionext Inc.
0004  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
0005  */
0006 
0007 #include <linux/clk-provider.h>
0008 #include <linux/init.h>
0009 #include <linux/mfd/syscon.h>
0010 #include <linux/of.h>
0011 #include <linux/of_device.h>
0012 #include <linux/platform_device.h>
0013 
0014 #include "clk-uniphier.h"
0015 
0016 static struct clk_hw *uniphier_clk_register(struct device *dev,
0017                         struct regmap *regmap,
0018                     const struct uniphier_clk_data *data)
0019 {
0020     switch (data->type) {
0021     case UNIPHIER_CLK_TYPE_CPUGEAR:
0022         return uniphier_clk_register_cpugear(dev, regmap, data->name,
0023                              &data->data.cpugear);
0024     case UNIPHIER_CLK_TYPE_FIXED_FACTOR:
0025         return uniphier_clk_register_fixed_factor(dev, data->name,
0026                               &data->data.factor);
0027     case UNIPHIER_CLK_TYPE_FIXED_RATE:
0028         return uniphier_clk_register_fixed_rate(dev, data->name,
0029                             &data->data.rate);
0030     case UNIPHIER_CLK_TYPE_GATE:
0031         return uniphier_clk_register_gate(dev, regmap, data->name,
0032                           &data->data.gate);
0033     case UNIPHIER_CLK_TYPE_MUX:
0034         return uniphier_clk_register_mux(dev, regmap, data->name,
0035                          &data->data.mux);
0036     default:
0037         dev_err(dev, "unsupported clock type\n");
0038         return ERR_PTR(-EINVAL);
0039     }
0040 }
0041 
0042 static int uniphier_clk_probe(struct platform_device *pdev)
0043 {
0044     struct device *dev = &pdev->dev;
0045     struct clk_hw_onecell_data *hw_data;
0046     const struct uniphier_clk_data *p, *data;
0047     struct regmap *regmap;
0048     struct device_node *parent;
0049     int clk_num = 0;
0050 
0051     data = of_device_get_match_data(dev);
0052     if (WARN_ON(!data))
0053         return -EINVAL;
0054 
0055     parent = of_get_parent(dev->of_node); /* parent should be syscon node */
0056     regmap = syscon_node_to_regmap(parent);
0057     of_node_put(parent);
0058     if (IS_ERR(regmap)) {
0059         dev_err(dev, "failed to get regmap (error %ld)\n",
0060             PTR_ERR(regmap));
0061         return PTR_ERR(regmap);
0062     }
0063 
0064     for (p = data; p->name; p++)
0065         clk_num = max(clk_num, p->idx + 1);
0066 
0067     hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, clk_num),
0068             GFP_KERNEL);
0069     if (!hw_data)
0070         return -ENOMEM;
0071 
0072     hw_data->num = clk_num;
0073 
0074     /* avoid returning NULL for unused idx */
0075     while (--clk_num >= 0)
0076         hw_data->hws[clk_num] = ERR_PTR(-EINVAL);
0077 
0078     for (p = data; p->name; p++) {
0079         struct clk_hw *hw;
0080 
0081         dev_dbg(dev, "register %s (index=%d)\n", p->name, p->idx);
0082         hw = uniphier_clk_register(dev, regmap, p);
0083         if (WARN(IS_ERR(hw), "failed to register %s", p->name))
0084             continue;
0085 
0086         if (p->idx >= 0)
0087             hw_data->hws[p->idx] = hw;
0088     }
0089 
0090     return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
0091                       hw_data);
0092 }
0093 
0094 static int uniphier_clk_remove(struct platform_device *pdev)
0095 {
0096     of_clk_del_provider(pdev->dev.of_node);
0097 
0098     return 0;
0099 }
0100 
0101 static const struct of_device_id uniphier_clk_match[] = {
0102     /* System clock */
0103     {
0104         .compatible = "socionext,uniphier-ld4-clock",
0105         .data = uniphier_ld4_sys_clk_data,
0106     },
0107     {
0108         .compatible = "socionext,uniphier-pro4-clock",
0109         .data = uniphier_pro4_sys_clk_data,
0110     },
0111     {
0112         .compatible = "socionext,uniphier-sld8-clock",
0113         .data = uniphier_sld8_sys_clk_data,
0114     },
0115     {
0116         .compatible = "socionext,uniphier-pro5-clock",
0117         .data = uniphier_pro5_sys_clk_data,
0118     },
0119     {
0120         .compatible = "socionext,uniphier-pxs2-clock",
0121         .data = uniphier_pxs2_sys_clk_data,
0122     },
0123     {
0124         .compatible = "socionext,uniphier-ld11-clock",
0125         .data = uniphier_ld11_sys_clk_data,
0126     },
0127     {
0128         .compatible = "socionext,uniphier-ld20-clock",
0129         .data = uniphier_ld20_sys_clk_data,
0130     },
0131     {
0132         .compatible = "socionext,uniphier-pxs3-clock",
0133         .data = uniphier_pxs3_sys_clk_data,
0134     },
0135     {
0136         .compatible = "socionext,uniphier-nx1-clock",
0137         .data = uniphier_nx1_sys_clk_data,
0138     },
0139     /* Media I/O clock, SD clock */
0140     {
0141         .compatible = "socionext,uniphier-ld4-mio-clock",
0142         .data = uniphier_ld4_mio_clk_data,
0143     },
0144     {
0145         .compatible = "socionext,uniphier-pro4-mio-clock",
0146         .data = uniphier_ld4_mio_clk_data,
0147     },
0148     {
0149         .compatible = "socionext,uniphier-sld8-mio-clock",
0150         .data = uniphier_ld4_mio_clk_data,
0151     },
0152     {
0153         .compatible = "socionext,uniphier-pro5-sd-clock",
0154         .data = uniphier_pro5_sd_clk_data,
0155     },
0156     {
0157         .compatible = "socionext,uniphier-pxs2-sd-clock",
0158         .data = uniphier_pro5_sd_clk_data,
0159     },
0160     {
0161         .compatible = "socionext,uniphier-ld11-mio-clock",
0162         .data = uniphier_ld4_mio_clk_data,
0163     },
0164     {
0165         .compatible = "socionext,uniphier-ld20-sd-clock",
0166         .data = uniphier_pro5_sd_clk_data,
0167     },
0168     {
0169         .compatible = "socionext,uniphier-pxs3-sd-clock",
0170         .data = uniphier_pro5_sd_clk_data,
0171     },
0172     {
0173         .compatible = "socionext,uniphier-nx1-sd-clock",
0174         .data = uniphier_pro5_sd_clk_data,
0175     },
0176     /* Peripheral clock */
0177     {
0178         .compatible = "socionext,uniphier-ld4-peri-clock",
0179         .data = uniphier_ld4_peri_clk_data,
0180     },
0181     {
0182         .compatible = "socionext,uniphier-pro4-peri-clock",
0183         .data = uniphier_pro4_peri_clk_data,
0184     },
0185     {
0186         .compatible = "socionext,uniphier-sld8-peri-clock",
0187         .data = uniphier_ld4_peri_clk_data,
0188     },
0189     {
0190         .compatible = "socionext,uniphier-pro5-peri-clock",
0191         .data = uniphier_pro4_peri_clk_data,
0192     },
0193     {
0194         .compatible = "socionext,uniphier-pxs2-peri-clock",
0195         .data = uniphier_pro4_peri_clk_data,
0196     },
0197     {
0198         .compatible = "socionext,uniphier-ld11-peri-clock",
0199         .data = uniphier_pro4_peri_clk_data,
0200     },
0201     {
0202         .compatible = "socionext,uniphier-ld20-peri-clock",
0203         .data = uniphier_pro4_peri_clk_data,
0204     },
0205     {
0206         .compatible = "socionext,uniphier-pxs3-peri-clock",
0207         .data = uniphier_pro4_peri_clk_data,
0208     },
0209     {
0210         .compatible = "socionext,uniphier-nx1-peri-clock",
0211         .data = uniphier_pro4_peri_clk_data,
0212     },
0213     /* SoC-glue clock */
0214     {
0215         .compatible = "socionext,uniphier-pro4-sg-clock",
0216         .data = uniphier_pro4_sg_clk_data,
0217     },
0218     { /* sentinel */ }
0219 };
0220 
0221 static struct platform_driver uniphier_clk_driver = {
0222     .probe = uniphier_clk_probe,
0223     .remove = uniphier_clk_remove,
0224     .driver = {
0225         .name = "uniphier-clk",
0226         .of_match_table = uniphier_clk_match,
0227     },
0228 };
0229 builtin_platform_driver(uniphier_clk_driver);