1 /* 2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 */ 10 11 #include <linux/clk-provider.h> 12 #include <linux/clkdev.h> 13 #include <linux/clk/at91_pmc.h> 14 #include <linux/of.h> 15 #include <linux/mfd/syscon.h> 16 #include <linux/regmap.h> 17 18 #include <asm/proc-fns.h> 19 20 #include "pmc.h" 21 22 struct at91_pmc_caps { 23 u32 available_irqs; 24 }; 25 26 struct at91_pmc { 27 struct regmap *regmap; 28 const struct at91_pmc_caps *caps; 29 }; 30 31 int of_at91_get_clk_range(struct device_node *np, const char *propname, 32 struct clk_range *range) 33 { 34 u32 min, max; 35 int ret; 36 37 ret = of_property_read_u32_index(np, propname, 0, &min); 38 if (ret) 39 return ret; 40 41 ret = of_property_read_u32_index(np, propname, 1, &max); 42 if (ret) 43 return ret; 44 45 if (range) { 46 range->min = min; 47 range->max = max; 48 } 49 50 return 0; 51 } 52 EXPORT_SYMBOL_GPL(of_at91_get_clk_range); 53 54 static const struct at91_pmc_caps at91rm9200_caps = { 55 .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | 56 AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | 57 AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | 58 AT91_PMC_PCK3RDY, 59 }; 60 61 static const struct at91_pmc_caps at91sam9260_caps = { 62 .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | 63 AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | 64 AT91_PMC_PCK1RDY, 65 }; 66 67 static const struct at91_pmc_caps at91sam9g45_caps = { 68 .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | 69 AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | 70 AT91_PMC_PCK1RDY, 71 }; 72 73 static const struct at91_pmc_caps at91sam9n12_caps = { 74 .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB | 75 AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY | 76 AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS | 77 AT91_PMC_MOSCRCS | AT91_PMC_CFDEV, 78 }; 79 80 static const struct at91_pmc_caps at91sam9x5_caps = { 81 .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | 82 AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | 83 AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS | 84 AT91_PMC_MOSCRCS | AT91_PMC_CFDEV, 85 }; 86 87 static const struct at91_pmc_caps sama5d2_caps = { 88 .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | 89 AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | 90 AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | 91 AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS | 92 AT91_PMC_CFDEV | AT91_PMC_GCKRDY, 93 }; 94 95 static const struct at91_pmc_caps sama5d3_caps = { 96 .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | 97 AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | 98 AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | 99 AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS | 100 AT91_PMC_CFDEV, 101 }; 102 103 static void __init of_at91_pmc_setup(struct device_node *np, 104 const struct at91_pmc_caps *caps) 105 { 106 struct at91_pmc *pmc; 107 struct regmap *regmap; 108 109 regmap = syscon_node_to_regmap(np); 110 if (IS_ERR(regmap)) 111 panic("Could not retrieve syscon regmap"); 112 113 pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); 114 if (!pmc) 115 return; 116 117 pmc->regmap = regmap; 118 pmc->caps = caps; 119 120 regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff); 121 122 } 123 124 static void __init of_at91rm9200_pmc_setup(struct device_node *np) 125 { 126 of_at91_pmc_setup(np, &at91rm9200_caps); 127 } 128 CLK_OF_DECLARE(at91rm9200_clk_pmc, "atmel,at91rm9200-pmc", 129 of_at91rm9200_pmc_setup); 130 131 static void __init of_at91sam9260_pmc_setup(struct device_node *np) 132 { 133 of_at91_pmc_setup(np, &at91sam9260_caps); 134 } 135 CLK_OF_DECLARE(at91sam9260_clk_pmc, "atmel,at91sam9260-pmc", 136 of_at91sam9260_pmc_setup); 137 138 static void __init of_at91sam9g45_pmc_setup(struct device_node *np) 139 { 140 of_at91_pmc_setup(np, &at91sam9g45_caps); 141 } 142 CLK_OF_DECLARE(at91sam9g45_clk_pmc, "atmel,at91sam9g45-pmc", 143 of_at91sam9g45_pmc_setup); 144 145 static void __init of_at91sam9n12_pmc_setup(struct device_node *np) 146 { 147 of_at91_pmc_setup(np, &at91sam9n12_caps); 148 } 149 CLK_OF_DECLARE(at91sam9n12_clk_pmc, "atmel,at91sam9n12-pmc", 150 of_at91sam9n12_pmc_setup); 151 152 static void __init of_at91sam9x5_pmc_setup(struct device_node *np) 153 { 154 of_at91_pmc_setup(np, &at91sam9x5_caps); 155 } 156 CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc", 157 of_at91sam9x5_pmc_setup); 158 159 static void __init of_sama5d2_pmc_setup(struct device_node *np) 160 { 161 of_at91_pmc_setup(np, &sama5d2_caps); 162 } 163 CLK_OF_DECLARE(sama5d2_clk_pmc, "atmel,sama5d2-pmc", 164 of_sama5d2_pmc_setup); 165 166 static void __init of_sama5d3_pmc_setup(struct device_node *np) 167 { 168 of_at91_pmc_setup(np, &sama5d3_caps); 169 } 170 CLK_OF_DECLARE(sama5d3_clk_pmc, "atmel,sama5d3-pmc", 171 of_sama5d3_pmc_setup); 172