1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Marvell Armada AP806 System Controller 4 * 5 * Copyright (C) 2016 Marvell 6 * 7 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 8 * 9 */ 10 11 #define pr_fmt(fmt) "ap806-system-controller: " fmt 12 13 #include <linux/clk-provider.h> 14 #include <linux/mfd/syscon.h> 15 #include <linux/init.h> 16 #include <linux/of.h> 17 #include <linux/of_address.h> 18 #include <linux/platform_device.h> 19 #include <linux/regmap.h> 20 21 #define AP806_SAR_REG 0x400 22 #define AP806_SAR_CLKFREQ_MODE_MASK 0x1f 23 24 #define AP806_CLK_NUM 5 25 26 static struct clk *ap806_clks[AP806_CLK_NUM]; 27 28 static struct clk_onecell_data ap806_clk_data = { 29 .clks = ap806_clks, 30 .clk_num = AP806_CLK_NUM, 31 }; 32 33 static char *ap806_unique_name(struct device *dev, struct device_node *np, 34 char *name) 35 { 36 const __be32 *reg; 37 u64 addr; 38 39 reg = of_get_property(np, "reg", NULL); 40 addr = of_translate_address(np, reg); 41 return devm_kasprintf(dev, GFP_KERNEL, "%llx-%s", 42 (unsigned long long)addr, name); 43 } 44 45 static int ap806_syscon_common_probe(struct platform_device *pdev, 46 struct device_node *syscon_node) 47 { 48 unsigned int freq_mode, cpuclk_freq; 49 const char *name, *fixedclk_name; 50 struct device *dev = &pdev->dev; 51 struct device_node *np = dev->of_node; 52 struct regmap *regmap; 53 u32 reg; 54 int ret; 55 56 regmap = syscon_node_to_regmap(syscon_node); 57 if (IS_ERR(regmap)) { 58 dev_err(dev, "cannot get regmap\n"); 59 return PTR_ERR(regmap); 60 } 61 62 ret = regmap_read(regmap, AP806_SAR_REG, ®); 63 if (ret) { 64 dev_err(dev, "cannot read from regmap\n"); 65 return ret; 66 } 67 68 freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK; 69 switch (freq_mode) { 70 case 0x0: 71 case 0x1: 72 cpuclk_freq = 2000; 73 break; 74 case 0x6: 75 case 0x7: 76 cpuclk_freq = 1800; 77 break; 78 case 0x4: 79 case 0xB: 80 case 0xD: 81 cpuclk_freq = 1600; 82 break; 83 case 0x1a: 84 cpuclk_freq = 1400; 85 break; 86 case 0x14: 87 case 0x17: 88 cpuclk_freq = 1300; 89 break; 90 case 0x19: 91 cpuclk_freq = 1200; 92 break; 93 case 0x13: 94 case 0x1d: 95 cpuclk_freq = 1000; 96 break; 97 case 0x1c: 98 cpuclk_freq = 800; 99 break; 100 case 0x1b: 101 cpuclk_freq = 600; 102 break; 103 default: 104 dev_err(dev, "invalid SAR value\n"); 105 return -EINVAL; 106 } 107 108 /* Convert to hertz */ 109 cpuclk_freq *= 1000 * 1000; 110 111 /* CPU clocks depend on the Sample At Reset configuration */ 112 name = ap806_unique_name(dev, syscon_node, "cpu-cluster-0"); 113 ap806_clks[0] = clk_register_fixed_rate(dev, name, NULL, 114 0, cpuclk_freq); 115 if (IS_ERR(ap806_clks[0])) { 116 ret = PTR_ERR(ap806_clks[0]); 117 goto fail0; 118 } 119 120 name = ap806_unique_name(dev, syscon_node, "cpu-cluster-1"); 121 ap806_clks[1] = clk_register_fixed_rate(dev, name, NULL, 0, 122 cpuclk_freq); 123 if (IS_ERR(ap806_clks[1])) { 124 ret = PTR_ERR(ap806_clks[1]); 125 goto fail1; 126 } 127 128 /* Fixed clock is always 1200 Mhz */ 129 fixedclk_name = ap806_unique_name(dev, syscon_node, "fixed"); 130 ap806_clks[2] = clk_register_fixed_rate(dev, fixedclk_name, NULL, 131 0, 1200 * 1000 * 1000); 132 if (IS_ERR(ap806_clks[2])) { 133 ret = PTR_ERR(ap806_clks[2]); 134 goto fail2; 135 } 136 137 /* MSS Clock is fixed clock divided by 6 */ 138 name = ap806_unique_name(dev, syscon_node, "mss"); 139 ap806_clks[3] = clk_register_fixed_factor(NULL, name, fixedclk_name, 140 0, 1, 6); 141 if (IS_ERR(ap806_clks[3])) { 142 ret = PTR_ERR(ap806_clks[3]); 143 goto fail3; 144 } 145 146 /* SDIO(/eMMC) Clock is fixed clock divided by 3 */ 147 name = ap806_unique_name(dev, syscon_node, "sdio"); 148 ap806_clks[4] = clk_register_fixed_factor(NULL, name, 149 fixedclk_name, 150 0, 1, 3); 151 if (IS_ERR(ap806_clks[4])) { 152 ret = PTR_ERR(ap806_clks[4]); 153 goto fail4; 154 } 155 156 ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data); 157 if (ret) 158 goto fail_clk_add; 159 160 return 0; 161 162 fail_clk_add: 163 clk_unregister_fixed_factor(ap806_clks[4]); 164 fail4: 165 clk_unregister_fixed_factor(ap806_clks[3]); 166 fail3: 167 clk_unregister_fixed_rate(ap806_clks[2]); 168 fail2: 169 clk_unregister_fixed_rate(ap806_clks[1]); 170 fail1: 171 clk_unregister_fixed_rate(ap806_clks[0]); 172 fail0: 173 return ret; 174 } 175 176 static int ap806_syscon_legacy_probe(struct platform_device *pdev) 177 { 178 dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n"); 179 dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n"); 180 dev_warn(&pdev->dev, FW_WARN 181 "This binding won't be supported in future kernel\n"); 182 183 return ap806_syscon_common_probe(pdev, pdev->dev.of_node); 184 185 } 186 187 static int ap806_clock_probe(struct platform_device *pdev) 188 { 189 return ap806_syscon_common_probe(pdev, pdev->dev.of_node->parent); 190 } 191 192 static const struct of_device_id ap806_syscon_legacy_of_match[] = { 193 { .compatible = "marvell,ap806-system-controller", }, 194 { } 195 }; 196 197 static struct platform_driver ap806_syscon_legacy_driver = { 198 .probe = ap806_syscon_legacy_probe, 199 .driver = { 200 .name = "marvell-ap806-system-controller", 201 .of_match_table = ap806_syscon_legacy_of_match, 202 .suppress_bind_attrs = true, 203 }, 204 }; 205 builtin_platform_driver(ap806_syscon_legacy_driver); 206 207 static const struct of_device_id ap806_clock_of_match[] = { 208 { .compatible = "marvell,ap806-clock", }, 209 { } 210 }; 211 212 static struct platform_driver ap806_clock_driver = { 213 .probe = ap806_clock_probe, 214 .driver = { 215 .name = "marvell-ap806-clock", 216 .of_match_table = ap806_clock_of_match, 217 .suppress_bind_attrs = true, 218 }, 219 }; 220 builtin_platform_driver(ap806_clock_driver); 221