0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define pr_fmt(fmt) "ap806-system-controller: " fmt
0012
0013 #include "armada_ap_cp_helper.h"
0014 #include <linux/clk-provider.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/init.h>
0017 #include <linux/of.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/regmap.h>
0020
0021 #define AP806_SAR_REG 0x400
0022 #define AP806_SAR_CLKFREQ_MODE_MASK 0x1f
0023
0024 #define AP806_CLK_NUM 6
0025
0026 static struct clk *ap806_clks[AP806_CLK_NUM];
0027
0028 static struct clk_onecell_data ap806_clk_data = {
0029 .clks = ap806_clks,
0030 .clk_num = AP806_CLK_NUM,
0031 };
0032
0033 static int ap806_get_sar_clocks(unsigned int freq_mode,
0034 unsigned int *cpuclk_freq,
0035 unsigned int *dclk_freq)
0036 {
0037 switch (freq_mode) {
0038 case 0x0:
0039 *cpuclk_freq = 2000;
0040 *dclk_freq = 600;
0041 break;
0042 case 0x1:
0043 *cpuclk_freq = 2000;
0044 *dclk_freq = 525;
0045 break;
0046 case 0x6:
0047 *cpuclk_freq = 1800;
0048 *dclk_freq = 600;
0049 break;
0050 case 0x7:
0051 *cpuclk_freq = 1800;
0052 *dclk_freq = 525;
0053 break;
0054 case 0x4:
0055 *cpuclk_freq = 1600;
0056 *dclk_freq = 400;
0057 break;
0058 case 0xB:
0059 *cpuclk_freq = 1600;
0060 *dclk_freq = 450;
0061 break;
0062 case 0xD:
0063 *cpuclk_freq = 1600;
0064 *dclk_freq = 525;
0065 break;
0066 case 0x1a:
0067 *cpuclk_freq = 1400;
0068 *dclk_freq = 400;
0069 break;
0070 case 0x14:
0071 *cpuclk_freq = 1300;
0072 *dclk_freq = 400;
0073 break;
0074 case 0x17:
0075 *cpuclk_freq = 1300;
0076 *dclk_freq = 325;
0077 break;
0078 case 0x19:
0079 *cpuclk_freq = 1200;
0080 *dclk_freq = 400;
0081 break;
0082 case 0x13:
0083 *cpuclk_freq = 1000;
0084 *dclk_freq = 325;
0085 break;
0086 case 0x1d:
0087 *cpuclk_freq = 1000;
0088 *dclk_freq = 400;
0089 break;
0090 case 0x1c:
0091 *cpuclk_freq = 800;
0092 *dclk_freq = 400;
0093 break;
0094 case 0x1b:
0095 *cpuclk_freq = 600;
0096 *dclk_freq = 400;
0097 break;
0098 default:
0099 return -EINVAL;
0100 }
0101
0102 return 0;
0103 }
0104
0105 static int ap807_get_sar_clocks(unsigned int freq_mode,
0106 unsigned int *cpuclk_freq,
0107 unsigned int *dclk_freq)
0108 {
0109 switch (freq_mode) {
0110 case 0x0:
0111 *cpuclk_freq = 2000;
0112 *dclk_freq = 1200;
0113 break;
0114 case 0x6:
0115 *cpuclk_freq = 2200;
0116 *dclk_freq = 1200;
0117 break;
0118 case 0xD:
0119 *cpuclk_freq = 1600;
0120 *dclk_freq = 1200;
0121 break;
0122 default:
0123 return -EINVAL;
0124 }
0125
0126 return 0;
0127 }
0128
0129 static int ap806_syscon_common_probe(struct platform_device *pdev,
0130 struct device_node *syscon_node)
0131 {
0132 unsigned int freq_mode, cpuclk_freq, dclk_freq;
0133 const char *name, *fixedclk_name;
0134 struct device *dev = &pdev->dev;
0135 struct device_node *np = dev->of_node;
0136 struct regmap *regmap;
0137 u32 reg;
0138 int ret;
0139
0140 regmap = syscon_node_to_regmap(syscon_node);
0141 if (IS_ERR(regmap)) {
0142 dev_err(dev, "cannot get regmap\n");
0143 return PTR_ERR(regmap);
0144 }
0145
0146 ret = regmap_read(regmap, AP806_SAR_REG, ®);
0147 if (ret) {
0148 dev_err(dev, "cannot read from regmap\n");
0149 return ret;
0150 }
0151
0152 freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK;
0153
0154 if (of_device_is_compatible(pdev->dev.of_node,
0155 "marvell,ap806-clock")) {
0156 ret = ap806_get_sar_clocks(freq_mode, &cpuclk_freq, &dclk_freq);
0157 } else if (of_device_is_compatible(pdev->dev.of_node,
0158 "marvell,ap807-clock")) {
0159 ret = ap807_get_sar_clocks(freq_mode, &cpuclk_freq, &dclk_freq);
0160 } else {
0161 dev_err(dev, "compatible not supported\n");
0162 return -EINVAL;
0163 }
0164
0165 if (ret) {
0166 dev_err(dev, "invalid Sample at Reset value\n");
0167 return ret;
0168 }
0169
0170
0171 cpuclk_freq *= 1000 * 1000;
0172 dclk_freq *= 1000 * 1000;
0173
0174
0175 name = ap_cp_unique_name(dev, syscon_node, "pll-cluster-0");
0176 ap806_clks[0] = clk_register_fixed_rate(dev, name, NULL,
0177 0, cpuclk_freq);
0178 if (IS_ERR(ap806_clks[0])) {
0179 ret = PTR_ERR(ap806_clks[0]);
0180 goto fail0;
0181 }
0182
0183 name = ap_cp_unique_name(dev, syscon_node, "pll-cluster-1");
0184 ap806_clks[1] = clk_register_fixed_rate(dev, name, NULL, 0,
0185 cpuclk_freq);
0186 if (IS_ERR(ap806_clks[1])) {
0187 ret = PTR_ERR(ap806_clks[1]);
0188 goto fail1;
0189 }
0190
0191
0192 fixedclk_name = ap_cp_unique_name(dev, syscon_node, "fixed");
0193 ap806_clks[2] = clk_register_fixed_rate(dev, fixedclk_name, NULL,
0194 0, 1200 * 1000 * 1000);
0195 if (IS_ERR(ap806_clks[2])) {
0196 ret = PTR_ERR(ap806_clks[2]);
0197 goto fail2;
0198 }
0199
0200
0201 name = ap_cp_unique_name(dev, syscon_node, "mss");
0202 ap806_clks[3] = clk_register_fixed_factor(NULL, name, fixedclk_name,
0203 0, 1, 6);
0204 if (IS_ERR(ap806_clks[3])) {
0205 ret = PTR_ERR(ap806_clks[3]);
0206 goto fail3;
0207 }
0208
0209
0210 name = ap_cp_unique_name(dev, syscon_node, "sdio");
0211 ap806_clks[4] = clk_register_fixed_factor(NULL, name,
0212 fixedclk_name,
0213 0, 1, 3);
0214 if (IS_ERR(ap806_clks[4])) {
0215 ret = PTR_ERR(ap806_clks[4]);
0216 goto fail4;
0217 }
0218
0219
0220 name = ap_cp_unique_name(dev, syscon_node, "ap-dclk");
0221 ap806_clks[5] = clk_register_fixed_rate(dev, name, NULL, 0, dclk_freq);
0222 if (IS_ERR(ap806_clks[5])) {
0223 ret = PTR_ERR(ap806_clks[5]);
0224 goto fail5;
0225 }
0226
0227 ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
0228 if (ret)
0229 goto fail_clk_add;
0230
0231 return 0;
0232
0233 fail_clk_add:
0234 clk_unregister_fixed_factor(ap806_clks[5]);
0235 fail5:
0236 clk_unregister_fixed_factor(ap806_clks[4]);
0237 fail4:
0238 clk_unregister_fixed_factor(ap806_clks[3]);
0239 fail3:
0240 clk_unregister_fixed_rate(ap806_clks[2]);
0241 fail2:
0242 clk_unregister_fixed_rate(ap806_clks[1]);
0243 fail1:
0244 clk_unregister_fixed_rate(ap806_clks[0]);
0245 fail0:
0246 return ret;
0247 }
0248
0249 static int ap806_syscon_legacy_probe(struct platform_device *pdev)
0250 {
0251 dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n");
0252 dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n");
0253 dev_warn(&pdev->dev, FW_WARN
0254 "This binding won't be supported in future kernel\n");
0255
0256 return ap806_syscon_common_probe(pdev, pdev->dev.of_node);
0257
0258 }
0259
0260 static int ap806_clock_probe(struct platform_device *pdev)
0261 {
0262 return ap806_syscon_common_probe(pdev, pdev->dev.of_node->parent);
0263 }
0264
0265 static const struct of_device_id ap806_syscon_legacy_of_match[] = {
0266 { .compatible = "marvell,ap806-system-controller", },
0267 { }
0268 };
0269
0270 static struct platform_driver ap806_syscon_legacy_driver = {
0271 .probe = ap806_syscon_legacy_probe,
0272 .driver = {
0273 .name = "marvell-ap806-system-controller",
0274 .of_match_table = ap806_syscon_legacy_of_match,
0275 .suppress_bind_attrs = true,
0276 },
0277 };
0278 builtin_platform_driver(ap806_syscon_legacy_driver);
0279
0280 static const struct of_device_id ap806_clock_of_match[] = {
0281 { .compatible = "marvell,ap806-clock", },
0282 { .compatible = "marvell,ap807-clock", },
0283 { }
0284 };
0285
0286 static struct platform_driver ap806_clock_driver = {
0287 .probe = ap806_clock_probe,
0288 .driver = {
0289 .name = "marvell-ap806-clock",
0290 .of_match_table = ap806_clock_of_match,
0291 .suppress_bind_attrs = true,
0292 },
0293 };
0294 builtin_platform_driver(ap806_clock_driver);