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