0001
0002
0003
0004
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);
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
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
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
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
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
0214 {
0215 .compatible = "socionext,uniphier-pro4-sg-clock",
0216 .data = uniphier_pro4_sg_clk_data,
0217 },
0218 { }
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);