aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPawel Moll <pawel.moll@arm.com>2014-04-23 05:49:31 -0400
committerPawel Moll <pawel.moll@arm.com>2014-05-15 12:02:19 -0400
commit974cc7b93441a0e78f030495436d1be7eb7c208d (patch)
treebc59d8bdfbb3c8bc25282495a40247eef810a415 /drivers
parent29f9b6cf7bff6a118130163c848811e14f8022da (diff)
mfd: vexpress: Define the device as MFD cells
This patch - finally, after over 6 months! :-( - addresses Samuel's request to split the vexpress-sysreg driver into smaller portions and define the device in a form of MFD cells: * LEDs code has been completely removed and replaced with "gpio-leds" nodes in the tree (referencing dedicated GPIO subnodes in sysreg - bindings documentation updated); this also better fits the reality as some variants of the motherboard don't have all the LEDs populated * syscfg bridge code has been extracted into a separate driver (placed in drivers/misc for no better place) * all the ID & MISC registers are defined as sysconf making them available for other drivers should they need to use them (and also to the user via /sys/kernel/debug/regmap which can be helpful in platform debugging) Signed-off-by: Pawel Moll <pawel.moll@arm.com> Acked-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/Kconfig15
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/vexpress-sysreg.c533
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/vexpress-syscfg.c324
6 files changed, 479 insertions, 405 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 33834120d057..490fd48a9541 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1227,12 +1227,17 @@ config MCP_UCB1200_TS
1227 1227
1228endmenu 1228endmenu
1229 1229
1230config VEXPRESS_CONFIG 1230config MFD_VEXPRESS_SYSREG
1231 bool "ARM Versatile Express platform infrastructure" 1231 bool "Versatile Express System Registers"
1232 depends on ARM || ARM64 1232 depends on VEXPRESS_CONFIG
1233 default y
1234 select CLKSRC_MMIO
1235 select GPIO_GENERIC_PLATFORM
1236 select MFD_CORE
1237 select MFD_SYSCON
1233 help 1238 help
1234 Platform configuration infrastructure for the ARM Ltd. 1239 System Registers are the platform configuration block
1235 Versatile Express. 1240 on the ARM Ltd. Versatile Express board.
1236 1241
1237endmenu 1242endmenu
1238endif 1243endif
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9ba838eb5131..cec3487b539e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -161,7 +161,7 @@ obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
161obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o 161obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
162obj-$(CONFIG_MFD_SYSCON) += syscon.o 162obj-$(CONFIG_MFD_SYSCON) += syscon.o
163obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o 163obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
164obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-sysreg.o 164obj-$(CONFIG_MFD_VEXPRESS_SYSREG) += vexpress-sysreg.o
165obj-$(CONFIG_MFD_RETU) += retu-mfd.o 165obj-$(CONFIG_MFD_RETU) += retu-mfd.o
166obj-$(CONFIG_MFD_AS3711) += as3711.o 166obj-$(CONFIG_MFD_AS3711) += as3711.o
167obj-$(CONFIG_MFD_AS3722) += as3722.o 167obj-$(CONFIG_MFD_AS3722) += as3722.o
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index b4138a7168db..952df843b6be 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -11,25 +11,22 @@
11 * Copyright (C) 2012 ARM Limited 11 * Copyright (C) 2012 ARM Limited
12 */ 12 */
13 13
14#include <linux/basic_mmio_gpio.h>
14#include <linux/err.h> 15#include <linux/err.h>
15#include <linux/gpio.h>
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/leds.h> 17#include <linux/mfd/core.h>
18#include <linux/of_address.h> 18#include <linux/of_address.h>
19#include <linux/of_platform.h> 19#include <linux/of_platform.h>
20#include <linux/platform_data/syscon.h>
20#include <linux/platform_device.h> 21#include <linux/platform_device.h>
21#include <linux/regulator/driver.h>
22#include <linux/sched.h>
23#include <linux/slab.h> 22#include <linux/slab.h>
24#include <linux/stat.h> 23#include <linux/stat.h>
25#include <linux/timer.h>
26#include <linux/vexpress.h> 24#include <linux/vexpress.h>
27 25
28#define SYS_ID 0x000 26#define SYS_ID 0x000
29#define SYS_SW 0x004 27#define SYS_SW 0x004
30#define SYS_LED 0x008 28#define SYS_LED 0x008
31#define SYS_100HZ 0x024 29#define SYS_100HZ 0x024
32#define SYS_FLAGS 0x030
33#define SYS_FLAGSSET 0x030 30#define SYS_FLAGSSET 0x030
34#define SYS_FLAGSCLR 0x034 31#define SYS_FLAGSCLR 0x034
35#define SYS_NVFLAGS 0x038 32#define SYS_NVFLAGS 0x038
@@ -51,36 +48,32 @@
51#define SYS_ID_HBI_SHIFT 16 48#define SYS_ID_HBI_SHIFT 16
52#define SYS_PROCIDx_HBI_SHIFT 0 49#define SYS_PROCIDx_HBI_SHIFT 0
53 50
54#define SYS_LED_LED(n) (1 << (n))
55
56#define SYS_MCI_CARDIN (1 << 0) 51#define SYS_MCI_CARDIN (1 << 0)
57#define SYS_MCI_WPROT (1 << 1) 52#define SYS_MCI_WPROT (1 << 1)
58 53
59#define SYS_FLASH_WPn (1 << 0)
60
61#define SYS_MISC_MASTERSITE (1 << 14) 54#define SYS_MISC_MASTERSITE (1 << 14)
62 55
63#define SYS_CFGCTRL_START (1 << 31)
64#define SYS_CFGCTRL_WRITE (1 << 30)
65#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26)
66#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20)
67#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16)
68#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
69#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0)
70 56
71#define SYS_CFGSTAT_ERR (1 << 1) 57static void __iomem *__vexpress_sysreg_base;
72#define SYS_CFGSTAT_COMPLETE (1 << 0)
73 58
59static void __iomem *vexpress_sysreg_base(void)
60{
61 if (!__vexpress_sysreg_base) {
62 struct device_node *node = of_find_compatible_node(NULL, NULL,
63 "arm,vexpress-sysreg");
74 64
75static void __iomem *vexpress_sysreg_base; 65 __vexpress_sysreg_base = of_iomap(node, 0);
76static struct device *vexpress_sysreg_dev; 66 }
77static LIST_HEAD(vexpress_sysreg_config_funcs); 67
78static struct device *vexpress_sysreg_config_bridge; 68 WARN_ON(!__vexpress_sysreg_base);
69
70 return __vexpress_sysreg_base;
71}
79 72
80 73
81static int vexpress_sysreg_get_master(void) 74static int vexpress_sysreg_get_master(void)
82{ 75{
83 if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE) 76 if (readl(vexpress_sysreg_base() + SYS_MISC) & SYS_MISC_MASTERSITE)
84 return VEXPRESS_SITE_DB2; 77 return VEXPRESS_SITE_DB2;
85 78
86 return VEXPRESS_SITE_DB1; 79 return VEXPRESS_SITE_DB1;
@@ -88,8 +81,13 @@ static int vexpress_sysreg_get_master(void)
88 81
89void vexpress_flags_set(u32 data) 82void vexpress_flags_set(u32 data)
90{ 83{
91 writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR); 84 writel(~0, vexpress_sysreg_base() + SYS_FLAGSCLR);
92 writel(data, vexpress_sysreg_base + SYS_FLAGSSET); 85 writel(data, vexpress_sysreg_base() + SYS_FLAGSSET);
86}
87
88unsigned int vexpress_get_mci_cardin(struct device *dev)
89{
90 return readl(vexpress_sysreg_base() + SYS_MCI) & SYS_MCI_CARDIN;
93} 91}
94 92
95u32 vexpress_get_procid(int site) 93u32 vexpress_get_procid(int site)
@@ -97,7 +95,7 @@ u32 vexpress_get_procid(int site)
97 if (site == VEXPRESS_SITE_MASTER) 95 if (site == VEXPRESS_SITE_MASTER)
98 site = vexpress_sysreg_get_master(); 96 site = vexpress_sysreg_get_master();
99 97
100 return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ? 98 return readl(vexpress_sysreg_base() + (site == VEXPRESS_SITE_DB1 ?
101 SYS_PROCID0 : SYS_PROCID1)); 99 SYS_PROCID0 : SYS_PROCID1));
102} 100}
103 101
@@ -107,7 +105,7 @@ u32 vexpress_get_hbi(int site)
107 105
108 switch (site) { 106 switch (site) {
109 case VEXPRESS_SITE_MB: 107 case VEXPRESS_SITE_MB:
110 id = readl(vexpress_sysreg_base + SYS_ID); 108 id = readl(vexpress_sysreg_base() + SYS_ID);
111 return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK; 109 return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK;
112 case VEXPRESS_SITE_MASTER: 110 case VEXPRESS_SITE_MASTER:
113 case VEXPRESS_SITE_DB1: 111 case VEXPRESS_SITE_DB1:
@@ -121,406 +119,143 @@ u32 vexpress_get_hbi(int site)
121 119
122void __iomem *vexpress_get_24mhz_clock_base(void) 120void __iomem *vexpress_get_24mhz_clock_base(void)
123{ 121{
124 return vexpress_sysreg_base + SYS_24MHZ; 122 return vexpress_sysreg_base() + SYS_24MHZ;
125}
126
127
128struct vexpress_sysreg_config_func {
129 struct list_head list;
130 struct regmap *regmap;
131 int num_templates;
132 u32 template[0]; /* Keep this last */
133};
134
135static int vexpress_sysreg_config_exec(struct vexpress_sysreg_config_func *func,
136 int index, bool write, u32 *data)
137{
138 u32 command, status;
139 int tries;
140 long timeout;
141
142 if (WARN_ON(!vexpress_sysreg_base))
143 return -ENOENT;
144
145 if (WARN_ON(index > func->num_templates))
146 return -EINVAL;
147
148 command = readl(vexpress_sysreg_base + SYS_CFGCTRL);
149 if (WARN_ON(command & SYS_CFGCTRL_START))
150 return -EBUSY;
151
152 command = func->template[index];
153 command |= SYS_CFGCTRL_START;
154 command |= write ? SYS_CFGCTRL_WRITE : 0;
155
156 /* Use a canary for reads */
157 if (!write)
158 *data = 0xdeadbeef;
159
160 dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n",
161 command, *data);
162 writel(*data, vexpress_sysreg_base + SYS_CFGDATA);
163 writel(0, vexpress_sysreg_base + SYS_CFGSTAT);
164 writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
165 mb();
166
167 /* The operation can take ages... Go to sleep, 100us initially */
168 tries = 100;
169 timeout = 100;
170 do {
171 set_current_state(TASK_INTERRUPTIBLE);
172 schedule_timeout(usecs_to_jiffies(timeout));
173 if (signal_pending(current))
174 return -EINTR;
175
176 status = readl(vexpress_sysreg_base + SYS_CFGSTAT);
177 if (status & SYS_CFGSTAT_ERR)
178 return -EFAULT;
179
180 if (timeout > 20)
181 timeout -= 20;
182 } while (--tries && !(status & SYS_CFGSTAT_COMPLETE));
183 if (WARN_ON_ONCE(!tries))
184 return -ETIMEDOUT;
185
186 if (!write) {
187 *data = readl(vexpress_sysreg_base + SYS_CFGDATA);
188 dev_dbg(vexpress_sysreg_dev, "func %p, read data %x\n",
189 func, *data);
190 }
191
192 return 0;
193}
194
195static int vexpress_sysreg_config_read(void *context, unsigned int index,
196 unsigned int *val)
197{
198 struct vexpress_sysreg_config_func *func = context;
199
200 return vexpress_sysreg_config_exec(func, index, false, val);
201}
202
203static int vexpress_sysreg_config_write(void *context, unsigned int index,
204 unsigned int val)
205{
206 struct vexpress_sysreg_config_func *func = context;
207
208 return vexpress_sysreg_config_exec(func, index, true, &val);
209}
210
211struct regmap_config vexpress_sysreg_regmap_config = {
212 .lock = vexpress_config_lock,
213 .unlock = vexpress_config_unlock,
214 .reg_bits = 32,
215 .val_bits = 32,
216 .reg_read = vexpress_sysreg_config_read,
217 .reg_write = vexpress_sysreg_config_write,
218 .reg_format_endian = REGMAP_ENDIAN_LITTLE,
219 .val_format_endian = REGMAP_ENDIAN_LITTLE,
220};
221
222static struct regmap *vexpress_sysreg_config_regmap_init(struct device *dev,
223 void *context)
224{
225 struct platform_device *pdev = to_platform_device(dev);
226 struct vexpress_sysreg_config_func *func;
227 struct property *prop;
228 const __be32 *val = NULL;
229 __be32 energy_quirk[4];
230 int num;
231 u32 site, position, dcc;
232 int err;
233 int i;
234
235 if (dev->of_node) {
236 err = vexpress_config_get_topo(dev->of_node, &site, &position,
237 &dcc);
238 if (err)
239 return ERR_PTR(err);
240
241 prop = of_find_property(dev->of_node,
242 "arm,vexpress-sysreg,func", NULL);
243 if (!prop)
244 return ERR_PTR(-EINVAL);
245
246 num = prop->length / sizeof(u32) / 2;
247 val = prop->value;
248 } else {
249 if (pdev->num_resources != 1 ||
250 pdev->resource[0].flags != IORESOURCE_BUS)
251 return ERR_PTR(-EFAULT);
252
253 site = pdev->resource[0].start;
254 if (site == VEXPRESS_SITE_MASTER)
255 site = vexpress_sysreg_get_master();
256 position = 0;
257 dcc = 0;
258 num = 1;
259 }
260
261 /*
262 * "arm,vexpress-energy" function used to be described
263 * by its first device only, now it requires both
264 */
265 if (num == 1 && of_device_is_compatible(dev->of_node,
266 "arm,vexpress-energy")) {
267 num = 2;
268 energy_quirk[0] = *val;
269 energy_quirk[2] = *val++;
270 energy_quirk[1] = *val;
271 energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1);
272 val = energy_quirk;
273 }
274
275 func = kzalloc(sizeof(*func) + sizeof(*func->template) * num,
276 GFP_KERNEL);
277 if (!func)
278 return NULL;
279
280 func->num_templates = num;
281
282 for (i = 0; i < num; i++) {
283 u32 function, device;
284
285 if (dev->of_node) {
286 function = be32_to_cpup(val++);
287 device = be32_to_cpup(val++);
288 } else {
289 function = pdev->resource[0].end;
290 device = pdev->id;
291 }
292
293 dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n",
294 func, site, position, dcc,
295 function, device);
296
297 func->template[i] = SYS_CFGCTRL_DCC(dcc);
298 func->template[i] |= SYS_CFGCTRL_SITE(site);
299 func->template[i] |= SYS_CFGCTRL_POSITION(position);
300 func->template[i] |= SYS_CFGCTRL_FUNC(function);
301 func->template[i] |= SYS_CFGCTRL_DEVICE(device);
302 }
303
304 vexpress_sysreg_regmap_config.max_register = num - 1;
305
306 func->regmap = regmap_init(dev, NULL, func,
307 &vexpress_sysreg_regmap_config);
308
309 if (IS_ERR(func->regmap))
310 kfree(func);
311 else
312 list_add(&func->list, &vexpress_sysreg_config_funcs);
313
314 return func->regmap;
315}
316
317static void vexpress_sysreg_config_regmap_exit(struct regmap *regmap,
318 void *context)
319{
320 struct vexpress_sysreg_config_func *func, *tmp;
321
322 regmap_exit(regmap);
323
324 list_for_each_entry_safe(func, tmp, &vexpress_sysreg_config_funcs,
325 list) {
326 if (func->regmap == regmap) {
327 list_del(&vexpress_sysreg_config_funcs);
328 kfree(func);
329 break;
330 }
331 }
332}
333
334static struct vexpress_config_bridge_ops vexpress_sysreg_config_bridge_ops = {
335 .regmap_init = vexpress_sysreg_config_regmap_init,
336 .regmap_exit = vexpress_sysreg_config_regmap_exit,
337};
338
339int vexpress_sysreg_config_device_register(struct platform_device *pdev)
340{
341 pdev->dev.parent = vexpress_sysreg_config_bridge;
342
343 return platform_device_register(pdev);
344} 123}
345 124
346 125
347void __init vexpress_sysreg_early_init(void __iomem *base) 126void __init vexpress_sysreg_early_init(void __iomem *base)
348{ 127{
349 vexpress_sysreg_base = base; 128 __vexpress_sysreg_base = base;
350 vexpress_config_set_master(vexpress_sysreg_get_master());
351}
352
353void __init vexpress_sysreg_of_early_init(void)
354{
355 struct device_node *node;
356
357 if (vexpress_sysreg_base)
358 return;
359
360 node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
361 if (WARN_ON(!node))
362 return;
363
364 vexpress_sysreg_base = of_iomap(node, 0);
365 if (WARN_ON(!vexpress_sysreg_base))
366 return;
367 129
368 vexpress_config_set_master(vexpress_sysreg_get_master()); 130 vexpress_config_set_master(vexpress_sysreg_get_master());
369} 131}
370 132
371 133
372#ifdef CONFIG_GPIOLIB 134/* The sysreg block is just a random collection of various functions... */
373
374#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
375 [VEXPRESS_GPIO_##_name] = { \
376 .reg = _reg, \
377 .value = _reg##_##_value, \
378 }
379 135
380static struct vexpress_sysreg_gpio { 136static struct syscon_platform_data vexpress_sysreg_sys_id_pdata = {
381 unsigned long reg; 137 .label = "sys_id",
382 u32 value;
383} vexpress_sysreg_gpios[] = {
384 VEXPRESS_SYSREG_GPIO(MMC_CARDIN, SYS_MCI, CARDIN),
385 VEXPRESS_SYSREG_GPIO(MMC_WPROT, SYS_MCI, WPROT),
386 VEXPRESS_SYSREG_GPIO(FLASH_WPn, SYS_FLASH, WPn),
387 VEXPRESS_SYSREG_GPIO(LED0, SYS_LED, LED(0)),
388 VEXPRESS_SYSREG_GPIO(LED1, SYS_LED, LED(1)),
389 VEXPRESS_SYSREG_GPIO(LED2, SYS_LED, LED(2)),
390 VEXPRESS_SYSREG_GPIO(LED3, SYS_LED, LED(3)),
391 VEXPRESS_SYSREG_GPIO(LED4, SYS_LED, LED(4)),
392 VEXPRESS_SYSREG_GPIO(LED5, SYS_LED, LED(5)),
393 VEXPRESS_SYSREG_GPIO(LED6, SYS_LED, LED(6)),
394 VEXPRESS_SYSREG_GPIO(LED7, SYS_LED, LED(7)),
395}; 138};
396 139
397static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip, 140static struct bgpio_pdata vexpress_sysreg_sys_led_pdata = {
398 unsigned offset) 141 .label = "sys_led",
399{ 142 .base = -1,
400 return 0; 143 .ngpio = 8,
401}
402
403static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
404 unsigned offset)
405{
406 struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
407 u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
408
409 return !!(reg_value & gpio->value);
410}
411
412static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
413 unsigned offset, int value)
414{
415 struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
416 u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
417
418 if (value)
419 reg_value |= gpio->value;
420 else
421 reg_value &= ~gpio->value;
422
423 writel(reg_value, vexpress_sysreg_base + gpio->reg);
424}
425
426static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
427 unsigned offset, int value)
428{
429 vexpress_sysreg_gpio_set(chip, offset, value);
430
431 return 0;
432}
433
434static struct gpio_chip vexpress_sysreg_gpio_chip = {
435 .label = "vexpress-sysreg",
436 .direction_input = vexpress_sysreg_gpio_direction_input,
437 .direction_output = vexpress_sysreg_gpio_direction_output,
438 .get = vexpress_sysreg_gpio_get,
439 .set = vexpress_sysreg_gpio_set,
440 .ngpio = ARRAY_SIZE(vexpress_sysreg_gpios),
441 .base = 0,
442}; 144};
443 145
444 146static struct bgpio_pdata vexpress_sysreg_sys_mci_pdata = {
445#define VEXPRESS_SYSREG_GREEN_LED(_name, _default_trigger, _gpio) \ 147 .label = "sys_mci",
446 { \ 148 .base = -1,
447 .name = "v2m:green:"_name, \ 149 .ngpio = 2,
448 .default_trigger = _default_trigger, \
449 .gpio = VEXPRESS_GPIO_##_gpio, \
450 }
451
452struct gpio_led vexpress_sysreg_leds[] = {
453 VEXPRESS_SYSREG_GREEN_LED("user1", "heartbeat", LED0),
454 VEXPRESS_SYSREG_GREEN_LED("user2", "mmc0", LED1),
455 VEXPRESS_SYSREG_GREEN_LED("user3", "cpu0", LED2),
456 VEXPRESS_SYSREG_GREEN_LED("user4", "cpu1", LED3),
457 VEXPRESS_SYSREG_GREEN_LED("user5", "cpu2", LED4),
458 VEXPRESS_SYSREG_GREEN_LED("user6", "cpu3", LED5),
459 VEXPRESS_SYSREG_GREEN_LED("user7", "cpu4", LED6),
460 VEXPRESS_SYSREG_GREEN_LED("user8", "cpu5", LED7),
461}; 150};
462 151
463struct gpio_led_platform_data vexpress_sysreg_leds_pdata = { 152static struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = {
464 .num_leds = ARRAY_SIZE(vexpress_sysreg_leds), 153 .label = "sys_flash",
465 .leds = vexpress_sysreg_leds, 154 .base = -1,
155 .ngpio = 1,
466}; 156};
467 157
468#endif 158static struct syscon_platform_data vexpress_sysreg_sys_misc_pdata = {
469 159 .label = "sys_misc",
160};
470 161
471static ssize_t vexpress_sysreg_sys_id_show(struct device *dev, 162static struct syscon_platform_data vexpress_sysreg_sys_procid_pdata = {
472 struct device_attribute *attr, char *buf) 163 .label = "sys_procid",
473{ 164};
474 return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID));
475}
476 165
477DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL); 166static struct mfd_cell vexpress_sysreg_cells[] = {
167 {
168 .name = "syscon",
169 .num_resources = 1,
170 .resources = (struct resource []) {
171 DEFINE_RES_MEM(SYS_ID, 0x4),
172 },
173 .platform_data = &vexpress_sysreg_sys_id_pdata,
174 .pdata_size = sizeof(vexpress_sysreg_sys_id_pdata),
175 }, {
176 .name = "basic-mmio-gpio",
177 .of_compatible = "arm,vexpress-sysreg,sys_led",
178 .num_resources = 1,
179 .resources = (struct resource []) {
180 DEFINE_RES_MEM_NAMED(SYS_LED, 0x4, "dat"),
181 },
182 .platform_data = &vexpress_sysreg_sys_led_pdata,
183 .pdata_size = sizeof(vexpress_sysreg_sys_led_pdata),
184 }, {
185 .name = "basic-mmio-gpio",
186 .of_compatible = "arm,vexpress-sysreg,sys_mci",
187 .num_resources = 1,
188 .resources = (struct resource []) {
189 DEFINE_RES_MEM_NAMED(SYS_MCI, 0x4, "dat"),
190 },
191 .platform_data = &vexpress_sysreg_sys_mci_pdata,
192 .pdata_size = sizeof(vexpress_sysreg_sys_mci_pdata),
193 }, {
194 .name = "basic-mmio-gpio",
195 .of_compatible = "arm,vexpress-sysreg,sys_flash",
196 .num_resources = 1,
197 .resources = (struct resource []) {
198 DEFINE_RES_MEM_NAMED(SYS_FLASH, 0x4, "dat"),
199 },
200 .platform_data = &vexpress_sysreg_sys_flash_pdata,
201 .pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata),
202 }, {
203 .name = "syscon",
204 .num_resources = 1,
205 .resources = (struct resource []) {
206 DEFINE_RES_MEM(SYS_MISC, 0x4),
207 },
208 .platform_data = &vexpress_sysreg_sys_misc_pdata,
209 .pdata_size = sizeof(vexpress_sysreg_sys_misc_pdata),
210 }, {
211 .name = "syscon",
212 .num_resources = 1,
213 .resources = (struct resource []) {
214 DEFINE_RES_MEM(SYS_PROCID0, 0x8),
215 },
216 .platform_data = &vexpress_sysreg_sys_procid_pdata,
217 .pdata_size = sizeof(vexpress_sysreg_sys_procid_pdata),
218 }, {
219 .name = "vexpress-syscfg",
220 .num_resources = 1,
221 .resources = (struct resource []) {
222 DEFINE_RES_MEM(SYS_CFGDATA, 0xc),
223 },
224 }
225};
478 226
479static int vexpress_sysreg_probe(struct platform_device *pdev) 227static int vexpress_sysreg_probe(struct platform_device *pdev)
480{ 228{
481 int err; 229 struct resource *mem;
482 struct resource *res = platform_get_resource(pdev, 230 void __iomem *base;
483 IORESOURCE_MEM, 0); 231 struct bgpio_chip *mmc_gpio_chip;
484
485 if (!devm_request_mem_region(&pdev->dev, res->start,
486 resource_size(res), pdev->name)) {
487 dev_err(&pdev->dev, "Failed to request memory region!\n");
488 return -EBUSY;
489 }
490 232
491 if (!vexpress_sysreg_base) 233 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
492 vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start, 234 if (!mem)
493 resource_size(res)); 235 return -EINVAL;
494 236
495 if (!vexpress_sysreg_base) { 237 base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
496 dev_err(&pdev->dev, "Failed to obtain base address!\n"); 238 if (!base)
497 return -EFAULT; 239 return -ENOMEM;
498 }
499 240
500 vexpress_config_set_master(vexpress_sysreg_get_master()); 241 vexpress_config_set_master(vexpress_sysreg_get_master());
501 vexpress_sysreg_dev = &pdev->dev;
502
503#ifdef CONFIG_GPIOLIB
504 vexpress_sysreg_gpio_chip.dev = &pdev->dev;
505 err = gpiochip_add(&vexpress_sysreg_gpio_chip);
506 if (err) {
507 dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n",
508 err);
509 return err;
510 }
511 242
512 platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", 243 /*
513 PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, 244 * Duplicated SYS_MCI pseudo-GPIO controller for compatibility with
514 sizeof(vexpress_sysreg_leds_pdata)); 245 * older trees using sysreg node for MMC control lines.
515#endif 246 */
516 247 mmc_gpio_chip = devm_kzalloc(&pdev->dev, sizeof(*mmc_gpio_chip),
517 vexpress_sysreg_config_bridge = vexpress_config_bridge_register( 248 GFP_KERNEL);
518 &pdev->dev, &vexpress_sysreg_config_bridge_ops, NULL); 249 if (!mmc_gpio_chip)
519 WARN_ON(!vexpress_sysreg_config_bridge); 250 return -ENOMEM;
520 251 bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
521 device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); 252 NULL, NULL, NULL, NULL, 0);
522 253 mmc_gpio_chip->gc.ngpio = 2;
523 return 0; 254 gpiochip_add(&mmc_gpio_chip->gc);
255
256 return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
257 vexpress_sysreg_cells,
258 ARRAY_SIZE(vexpress_sysreg_cells), mem, 0, NULL);
524} 259}
525 260
526static const struct of_device_id vexpress_sysreg_match[] = { 261static const struct of_device_id vexpress_sysreg_match[] = {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 8baff0effc7d..d9663ef90ce8 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -515,6 +515,15 @@ config SRAM
515 the genalloc API. It is supposed to be used for small on-chip SRAM 515 the genalloc API. It is supposed to be used for small on-chip SRAM
516 areas found on many SoCs. 516 areas found on many SoCs.
517 517
518config VEXPRESS_SYSCFG
519 bool "Versatile Express System Configuration driver"
520 depends on VEXPRESS_CONFIG
521 default y
522 help
523 ARM Ltd. Versatile Express uses specialised platform configuration
524 bus. System Configuration interface is one of the possible means
525 of generating transactions on this bus.
526
518source "drivers/misc/c2port/Kconfig" 527source "drivers/misc/c2port/Kconfig"
519source "drivers/misc/eeprom/Kconfig" 528source "drivers/misc/eeprom/Kconfig"
520source "drivers/misc/cb710/Kconfig" 529source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7eb4b69580c0..d59ce1261b38 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_SRAM) += sram.o
55obj-y += mic/ 55obj-y += mic/
56obj-$(CONFIG_GENWQE) += genwqe/ 56obj-$(CONFIG_GENWQE) += genwqe/
57obj-$(CONFIG_ECHO) += echo/ 57obj-$(CONFIG_ECHO) += echo/
58obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c
new file mode 100644
index 000000000000..73068e50e56d
--- /dev/null
+++ b/drivers/misc/vexpress-syscfg.c
@@ -0,0 +1,324 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * Copyright (C) 2014 ARM Limited
12 */
13
14#include <linux/delay.h>
15#include <linux/err.h>
16#include <linux/io.h>
17#include <linux/of.h>
18#include <linux/platform_device.h>
19#include <linux/sched.h>
20#include <linux/slab.h>
21#include <linux/syscore_ops.h>
22#include <linux/vexpress.h>
23
24
25#define SYS_CFGDATA 0x0
26
27#define SYS_CFGCTRL 0x4
28#define SYS_CFGCTRL_START (1 << 31)
29#define SYS_CFGCTRL_WRITE (1 << 30)
30#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26)
31#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20)
32#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16)
33#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
34#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0)
35
36#define SYS_CFGSTAT 0x8
37#define SYS_CFGSTAT_ERR (1 << 1)
38#define SYS_CFGSTAT_COMPLETE (1 << 0)
39
40
41struct vexpress_syscfg {
42 struct device *dev;
43 void __iomem *base;
44 struct list_head funcs;
45};
46
47struct vexpress_syscfg_func {
48 struct list_head list;
49 struct vexpress_syscfg *syscfg;
50 struct regmap *regmap;
51 int num_templates;
52 u32 template[0]; /* Keep it last! */
53};
54
55
56static int vexpress_syscfg_exec(struct vexpress_syscfg_func *func,
57 int index, bool write, u32 *data)
58{
59 struct vexpress_syscfg *syscfg = func->syscfg;
60 u32 command, status;
61 int tries;
62 long timeout;
63
64 if (WARN_ON(index > func->num_templates))
65 return -EINVAL;
66
67 command = readl(syscfg->base + SYS_CFGCTRL);
68 if (WARN_ON(command & SYS_CFGCTRL_START))
69 return -EBUSY;
70
71 command = func->template[index];
72 command |= SYS_CFGCTRL_START;
73 command |= write ? SYS_CFGCTRL_WRITE : 0;
74
75 /* Use a canary for reads */
76 if (!write)
77 *data = 0xdeadbeef;
78
79 dev_dbg(syscfg->dev, "func %p, command %x, data %x\n",
80 func, command, *data);
81 writel(*data, syscfg->base + SYS_CFGDATA);
82 writel(0, syscfg->base + SYS_CFGSTAT);
83 writel(command, syscfg->base + SYS_CFGCTRL);
84 mb();
85
86 /* The operation can take ages... Go to sleep, 100us initially */
87 tries = 100;
88 timeout = 100;
89 do {
90 if (!irqs_disabled()) {
91 set_current_state(TASK_INTERRUPTIBLE);
92 schedule_timeout(usecs_to_jiffies(timeout));
93 if (signal_pending(current))
94 return -EINTR;
95 } else {
96 udelay(timeout);
97 }
98
99 status = readl(syscfg->base + SYS_CFGSTAT);
100 if (status & SYS_CFGSTAT_ERR)
101 return -EFAULT;
102
103 if (timeout > 20)
104 timeout -= 20;
105 } while (--tries && !(status & SYS_CFGSTAT_COMPLETE));
106 if (WARN_ON_ONCE(!tries))
107 return -ETIMEDOUT;
108
109 if (!write) {
110 *data = readl(syscfg->base + SYS_CFGDATA);
111 dev_dbg(syscfg->dev, "func %p, read data %x\n", func, *data);
112 }
113
114 return 0;
115}
116
117static int vexpress_syscfg_read(void *context, unsigned int index,
118 unsigned int *val)
119{
120 struct vexpress_syscfg_func *func = context;
121
122 return vexpress_syscfg_exec(func, index, false, val);
123}
124
125static int vexpress_syscfg_write(void *context, unsigned int index,
126 unsigned int val)
127{
128 struct vexpress_syscfg_func *func = context;
129
130 return vexpress_syscfg_exec(func, index, true, &val);
131}
132
133struct regmap_config vexpress_syscfg_regmap_config = {
134 .lock = vexpress_config_lock,
135 .unlock = vexpress_config_unlock,
136 .reg_bits = 32,
137 .val_bits = 32,
138 .reg_read = vexpress_syscfg_read,
139 .reg_write = vexpress_syscfg_write,
140 .reg_format_endian = REGMAP_ENDIAN_LITTLE,
141 .val_format_endian = REGMAP_ENDIAN_LITTLE,
142};
143
144
145static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,
146 void *context)
147{
148 struct platform_device *pdev = to_platform_device(dev);
149 struct vexpress_syscfg *syscfg = context;
150 struct vexpress_syscfg_func *func;
151 struct property *prop;
152 const __be32 *val = NULL;
153 __be32 energy_quirk[4];
154 int num;
155 u32 site, position, dcc;
156 int i;
157
158 if (dev->of_node) {
159 int err = vexpress_config_get_topo(dev->of_node, &site,
160 &position, &dcc);
161
162 if (err)
163 return ERR_PTR(err);
164
165 prop = of_find_property(dev->of_node,
166 "arm,vexpress-sysreg,func", NULL);
167 if (!prop)
168 return ERR_PTR(-EINVAL);
169
170 num = prop->length / sizeof(u32) / 2;
171 val = prop->value;
172 } else {
173 if (pdev->num_resources != 1 ||
174 pdev->resource[0].flags != IORESOURCE_BUS)
175 return ERR_PTR(-EFAULT);
176
177 site = pdev->resource[0].start;
178 if (site == VEXPRESS_SITE_MASTER)
179 site = vexpress_config_get_master();
180 position = 0;
181 dcc = 0;
182 num = 1;
183 }
184
185 /*
186 * "arm,vexpress-energy" function used to be described
187 * by its first device only, now it requires both
188 */
189 if (num == 1 && of_device_is_compatible(dev->of_node,
190 "arm,vexpress-energy")) {
191 num = 2;
192 energy_quirk[0] = *val;
193 energy_quirk[2] = *val++;
194 energy_quirk[1] = *val;
195 energy_quirk[3] = cpu_to_be32(be32_to_cpup(val) + 1);
196 val = energy_quirk;
197 }
198
199 func = kzalloc(sizeof(*func) + sizeof(*func->template) * num,
200 GFP_KERNEL);
201 if (!func)
202 return NULL;
203
204 func->syscfg = syscfg;
205 func->num_templates = num;
206
207 for (i = 0; i < num; i++) {
208 u32 function, device;
209
210 if (dev->of_node) {
211 function = be32_to_cpup(val++);
212 device = be32_to_cpup(val++);
213 } else {
214 function = pdev->resource[0].end;
215 device = pdev->id;
216 }
217
218 dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n",
219 func, site, position, dcc,
220 function, device);
221
222 func->template[i] = SYS_CFGCTRL_DCC(dcc);
223 func->template[i] |= SYS_CFGCTRL_SITE(site);
224 func->template[i] |= SYS_CFGCTRL_POSITION(position);
225 func->template[i] |= SYS_CFGCTRL_FUNC(function);
226 func->template[i] |= SYS_CFGCTRL_DEVICE(device);
227 }
228
229 vexpress_syscfg_regmap_config.max_register = num - 1;
230
231 func->regmap = regmap_init(dev, NULL, func,
232 &vexpress_syscfg_regmap_config);
233
234 if (IS_ERR(func->regmap))
235 kfree(func);
236 else
237 list_add(&func->list, &syscfg->funcs);
238
239 return func->regmap;
240}
241
242static void vexpress_syscfg_regmap_exit(struct regmap *regmap, void *context)
243{
244 struct vexpress_syscfg *syscfg = context;
245 struct vexpress_syscfg_func *func, *tmp;
246
247 regmap_exit(regmap);
248
249 list_for_each_entry_safe(func, tmp, &syscfg->funcs, list) {
250 if (func->regmap == regmap) {
251 list_del(&syscfg->funcs);
252 kfree(func);
253 break;
254 }
255 }
256}
257
258static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = {
259 .regmap_init = vexpress_syscfg_regmap_init,
260 .regmap_exit = vexpress_syscfg_regmap_exit,
261};
262
263
264/* Non-DT hack, to be gone... */
265static struct device *vexpress_syscfg_bridge;
266
267int vexpress_syscfg_device_register(struct platform_device *pdev)
268{
269 pdev->dev.parent = vexpress_syscfg_bridge;
270
271 return platform_device_register(pdev);
272}
273
274
275int vexpress_syscfg_probe(struct platform_device *pdev)
276{
277 struct vexpress_syscfg *syscfg;
278 struct resource *res;
279 struct device *bridge;
280
281 syscfg = devm_kzalloc(&pdev->dev, sizeof(*syscfg), GFP_KERNEL);
282 if (!syscfg)
283 return -ENOMEM;
284 syscfg->dev = &pdev->dev;
285 INIT_LIST_HEAD(&syscfg->funcs);
286
287 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
288 if (!devm_request_mem_region(&pdev->dev, res->start,
289 resource_size(res), pdev->name))
290 return -EBUSY;
291
292 syscfg->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
293 if (!syscfg->base)
294 return -EFAULT;
295
296 /* Must use dev.parent (MFD), as that's where DT phandle points at... */
297 bridge = vexpress_config_bridge_register(pdev->dev.parent,
298 &vexpress_syscfg_bridge_ops, syscfg);
299 if (IS_ERR(bridge))
300 return PTR_ERR(bridge);
301
302 /* Non-DT case */
303 if (!pdev->dev.of_node)
304 vexpress_syscfg_bridge = bridge;
305
306 return 0;
307}
308
309static const struct platform_device_id vexpress_syscfg_id_table[] = {
310 { "vexpress-syscfg", },
311 {},
312};
313
314static struct platform_driver vexpress_syscfg_driver = {
315 .driver.name = "vexpress-syscfg",
316 .id_table = vexpress_syscfg_id_table,
317 .probe = vexpress_syscfg_probe,
318};
319
320static int __init vexpress_syscfg_init(void)
321{
322 return platform_driver_register(&vexpress_syscfg_driver);
323}
324core_initcall(vexpress_syscfg_init);