root/drivers/clk/mvebu/ap806-system-controller.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ap806_get_sar_clocks
  2. ap807_get_sar_clocks
  3. ap806_syscon_common_probe
  4. ap806_syscon_legacy_probe
  5. ap806_clock_probe

   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 "armada_ap_cp_helper.h"
  14 #include <linux/clk-provider.h>
  15 #include <linux/mfd/syscon.h>
  16 #include <linux/init.h>
  17 #include <linux/of.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                   6
  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 int ap806_get_sar_clocks(unsigned int freq_mode,
  34                                 unsigned int *cpuclk_freq,
  35                                 unsigned int *dclk_freq)
  36 {
  37         switch (freq_mode) {
  38         case 0x0:
  39                 *cpuclk_freq = 2000;
  40                 *dclk_freq = 600;
  41                 break;
  42         case 0x1:
  43                 *cpuclk_freq = 2000;
  44                 *dclk_freq = 525;
  45                 break;
  46         case 0x6:
  47                 *cpuclk_freq = 1800;
  48                 *dclk_freq = 600;
  49                 break;
  50         case 0x7:
  51                 *cpuclk_freq = 1800;
  52                 *dclk_freq = 525;
  53                 break;
  54         case 0x4:
  55                 *cpuclk_freq = 1600;
  56                 *dclk_freq = 400;
  57                 break;
  58         case 0xB:
  59                 *cpuclk_freq = 1600;
  60                 *dclk_freq = 450;
  61                 break;
  62         case 0xD:
  63                 *cpuclk_freq = 1600;
  64                 *dclk_freq = 525;
  65                 break;
  66         case 0x1a:
  67                 *cpuclk_freq = 1400;
  68                 *dclk_freq = 400;
  69                 break;
  70         case 0x14:
  71                 *cpuclk_freq = 1300;
  72                 *dclk_freq = 400;
  73                 break;
  74         case 0x17:
  75                 *cpuclk_freq = 1300;
  76                 *dclk_freq = 325;
  77                 break;
  78         case 0x19:
  79                 *cpuclk_freq = 1200;
  80                 *dclk_freq = 400;
  81                 break;
  82         case 0x13:
  83                 *cpuclk_freq = 1000;
  84                 *dclk_freq = 325;
  85                 break;
  86         case 0x1d:
  87                 *cpuclk_freq = 1000;
  88                 *dclk_freq = 400;
  89                 break;
  90         case 0x1c:
  91                 *cpuclk_freq = 800;
  92                 *dclk_freq = 400;
  93                 break;
  94         case 0x1b:
  95                 *cpuclk_freq = 600;
  96                 *dclk_freq = 400;
  97                 break;
  98         default:
  99                 return -EINVAL;
 100         }
 101 
 102         return 0;
 103 }
 104 
 105 static int ap807_get_sar_clocks(unsigned int freq_mode,
 106                                 unsigned int *cpuclk_freq,
 107                                 unsigned int *dclk_freq)
 108 {
 109         switch (freq_mode) {
 110         case 0x0:
 111                 *cpuclk_freq = 2000;
 112                 *dclk_freq = 1200;
 113                 break;
 114         case 0x6:
 115                 *cpuclk_freq = 2200;
 116                 *dclk_freq = 1200;
 117                 break;
 118         case 0xD:
 119                 *cpuclk_freq = 1600;
 120                 *dclk_freq = 1200;
 121                 break;
 122         default:
 123                 return -EINVAL;
 124         }
 125 
 126         return 0;
 127 }
 128 
 129 static int ap806_syscon_common_probe(struct platform_device *pdev,
 130                                      struct device_node *syscon_node)
 131 {
 132         unsigned int freq_mode, cpuclk_freq, dclk_freq;
 133         const char *name, *fixedclk_name;
 134         struct device *dev = &pdev->dev;
 135         struct device_node *np = dev->of_node;
 136         struct regmap *regmap;
 137         u32 reg;
 138         int ret;
 139 
 140         regmap = syscon_node_to_regmap(syscon_node);
 141         if (IS_ERR(regmap)) {
 142                 dev_err(dev, "cannot get regmap\n");
 143                 return PTR_ERR(regmap);
 144         }
 145 
 146         ret = regmap_read(regmap, AP806_SAR_REG, &reg);
 147         if (ret) {
 148                 dev_err(dev, "cannot read from regmap\n");
 149                 return ret;
 150         }
 151 
 152         freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK;
 153 
 154         if (of_device_is_compatible(pdev->dev.of_node,
 155                                     "marvell,ap806-clock")) {
 156                 ret = ap806_get_sar_clocks(freq_mode, &cpuclk_freq, &dclk_freq);
 157         } else if (of_device_is_compatible(pdev->dev.of_node,
 158                                            "marvell,ap807-clock")) {
 159                 ret = ap807_get_sar_clocks(freq_mode, &cpuclk_freq, &dclk_freq);
 160         } else {
 161                 dev_err(dev, "compatible not supported\n");
 162                 return -EINVAL;
 163         }
 164 
 165         if (ret) {
 166                 dev_err(dev, "invalid Sample at Reset value\n");
 167                 return ret;
 168         }
 169 
 170         /* Convert to hertz */
 171         cpuclk_freq *= 1000 * 1000;
 172         dclk_freq *= 1000 * 1000;
 173 
 174         /* CPU clocks depend on the Sample At Reset configuration */
 175         name = ap_cp_unique_name(dev, syscon_node, "pll-cluster-0");
 176         ap806_clks[0] = clk_register_fixed_rate(dev, name, NULL,
 177                                                 0, cpuclk_freq);
 178         if (IS_ERR(ap806_clks[0])) {
 179                 ret = PTR_ERR(ap806_clks[0]);
 180                 goto fail0;
 181         }
 182 
 183         name = ap_cp_unique_name(dev, syscon_node, "pll-cluster-1");
 184         ap806_clks[1] = clk_register_fixed_rate(dev, name, NULL, 0,
 185                                                 cpuclk_freq);
 186         if (IS_ERR(ap806_clks[1])) {
 187                 ret = PTR_ERR(ap806_clks[1]);
 188                 goto fail1;
 189         }
 190 
 191         /* Fixed clock is always 1200 Mhz */
 192         fixedclk_name = ap_cp_unique_name(dev, syscon_node, "fixed");
 193         ap806_clks[2] = clk_register_fixed_rate(dev, fixedclk_name, NULL,
 194                                                 0, 1200 * 1000 * 1000);
 195         if (IS_ERR(ap806_clks[2])) {
 196                 ret = PTR_ERR(ap806_clks[2]);
 197                 goto fail2;
 198         }
 199 
 200         /* MSS Clock is fixed clock divided by 6 */
 201         name = ap_cp_unique_name(dev, syscon_node, "mss");
 202         ap806_clks[3] = clk_register_fixed_factor(NULL, name, fixedclk_name,
 203                                                   0, 1, 6);
 204         if (IS_ERR(ap806_clks[3])) {
 205                 ret = PTR_ERR(ap806_clks[3]);
 206                 goto fail3;
 207         }
 208 
 209         /* SDIO(/eMMC) Clock is fixed clock divided by 3 */
 210         name = ap_cp_unique_name(dev, syscon_node, "sdio");
 211         ap806_clks[4] = clk_register_fixed_factor(NULL, name,
 212                                                   fixedclk_name,
 213                                                   0, 1, 3);
 214         if (IS_ERR(ap806_clks[4])) {
 215                 ret = PTR_ERR(ap806_clks[4]);
 216                 goto fail4;
 217         }
 218 
 219         /* AP-DCLK(HCLK) Clock is DDR clock divided by 2 */
 220         name = ap_cp_unique_name(dev, syscon_node, "ap-dclk");
 221         ap806_clks[5] = clk_register_fixed_rate(dev, name, NULL, 0, dclk_freq);
 222         if (IS_ERR(ap806_clks[5])) {
 223                 ret = PTR_ERR(ap806_clks[5]);
 224                 goto fail5;
 225         }
 226 
 227         ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
 228         if (ret)
 229                 goto fail_clk_add;
 230 
 231         return 0;
 232 
 233 fail_clk_add:
 234         clk_unregister_fixed_factor(ap806_clks[5]);
 235 fail5:
 236         clk_unregister_fixed_factor(ap806_clks[4]);
 237 fail4:
 238         clk_unregister_fixed_factor(ap806_clks[3]);
 239 fail3:
 240         clk_unregister_fixed_rate(ap806_clks[2]);
 241 fail2:
 242         clk_unregister_fixed_rate(ap806_clks[1]);
 243 fail1:
 244         clk_unregister_fixed_rate(ap806_clks[0]);
 245 fail0:
 246         return ret;
 247 }
 248 
 249 static int ap806_syscon_legacy_probe(struct platform_device *pdev)
 250 {
 251         dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n");
 252         dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n");
 253         dev_warn(&pdev->dev, FW_WARN
 254                  "This binding won't be supported in future kernel\n");
 255 
 256         return ap806_syscon_common_probe(pdev, pdev->dev.of_node);
 257 
 258 }
 259 
 260 static int ap806_clock_probe(struct platform_device *pdev)
 261 {
 262         return ap806_syscon_common_probe(pdev, pdev->dev.of_node->parent);
 263 }
 264 
 265 static const struct of_device_id ap806_syscon_legacy_of_match[] = {
 266         { .compatible = "marvell,ap806-system-controller", },
 267         { }
 268 };
 269 
 270 static struct platform_driver ap806_syscon_legacy_driver = {
 271         .probe = ap806_syscon_legacy_probe,
 272         .driver         = {
 273                 .name   = "marvell-ap806-system-controller",
 274                 .of_match_table = ap806_syscon_legacy_of_match,
 275                 .suppress_bind_attrs = true,
 276         },
 277 };
 278 builtin_platform_driver(ap806_syscon_legacy_driver);
 279 
 280 static const struct of_device_id ap806_clock_of_match[] = {
 281         { .compatible = "marvell,ap806-clock", },
 282         { .compatible = "marvell,ap807-clock", },
 283         { }
 284 };
 285 
 286 static struct platform_driver ap806_clock_driver = {
 287         .probe = ap806_clock_probe,
 288         .driver         = {
 289                 .name   = "marvell-ap806-clock",
 290                 .of_match_table = ap806_clock_of_match,
 291                 .suppress_bind_attrs = true,
 292         },
 293 };
 294 builtin_platform_driver(ap806_clock_driver);

/* [<][>][^][v][top][bottom][index][help] */