Commit 88e0abcd7a8171ca7af3402373e7bd81fe9b6754

Authored by Pawel Moll
1 parent 3ecbf05be1

mfd: Versatile Express system registers driver

This is a platform driver for Versatile Express' "system
register" block. It's a random collection of registers providing
the following functionality:

- low level platform functions like board ID access; in order to
  use those, the driver must be initialized early, either statically
  or based on the DT

- config bus bridge via "system control" interface; as the response
  from the controller does not generate interrupt (yet), the status
  register is periodically polled using a timer

- pseudo GPIO lines providing MMC card status and Flash WP#
  signal control

- LED interface for a set of 8 LEDs on the motherboard, with
  "heartbeat", "mmc0" and "cpu0" to "cpu5" as default triggers

Signed-off-by: Pawel Moll <pawel.moll@arm.com>

Showing 4 changed files with 628 additions and 1 deletions Side-by-side Diff

Documentation/devicetree/bindings/arm/vexpress-sysreg.txt
  1 +ARM Versatile Express system registers
  2 +--------------------------------------
  3 +
  4 +This is a system control registers block, providing multiple low level
  5 +platform functions like board detection and identification, software
  6 +interrupt generation, MMC and NOR Flash control etc.
  7 +
  8 +Required node properties:
  9 +- compatible value : = "arm,vexpress,sysreg";
  10 +- reg : physical base address and the size of the registers window
  11 +- gpio-controller : specifies that the node is a GPIO controller
  12 +- #gpio-cells : size of the GPIO specifier, should be 2:
  13 + - first cell is the pseudo-GPIO line number:
  14 + 0 - MMC CARDIN
  15 + 1 - MMC WPROT
  16 + 2 - NOR FLASH WPn
  17 + - second cell can take standard GPIO flags (currently ignored).
  18 +
  19 +Example:
  20 + v2m_sysreg: sysreg@10000000 {
  21 + compatible = "arm,vexpress-sysreg";
  22 + reg = <0x10000000 0x1000>;
  23 + gpio-controller;
  24 + #gpio-cells = <2>;
  25 + };
  26 +
  27 +This block also can also act a bridge to the platform's configuration
  28 +bus via "system control" interface, addressing devices with site number,
  29 +position in the board stack, config controller, function and device
  30 +numbers - see motherboard's TRM for more details.
  31 +
  32 +The node describing a config device must refer to the sysreg node via
  33 +"arm,vexpress,config-bridge" phandle (can be also defined in the node's
  34 +parent) and relies on the board topology properties - see main vexpress
  35 +node documentation for more details. It must must also define the
  36 +following property:
  37 +- arm,vexpress-sysreg,func : must contain two cells:
  38 + - first cell defines function number (eg. 1 for clock generator,
  39 + 2 for voltage regulators etc.)
  40 + - device number (eg. osc 0, osc 1 etc.)
  41 +
  42 +Example:
  43 + mcc {
  44 + arm,vexpress,config-bridge = <&v2m_sysreg>;
  45 +
  46 + osc@0 {
  47 + compatible = "arm,vexpress-osc";
  48 + arm,vexpress-sysreg,func = <1 0>;
  49 + };
  50 + };
drivers/mfd/Makefile
... ... @@ -138,5 +138,5 @@
138 138 obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
139 139 obj-$(CONFIG_MFD_SYSCON) += syscon.o
140 140 obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
141   -obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
  141 +obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o
drivers/mfd/vexpress-sysreg.c
  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) 2012 ARM Limited
  12 + */
  13 +
  14 +#include <linux/err.h>
  15 +#include <linux/gpio.h>
  16 +#include <linux/io.h>
  17 +#include <linux/leds.h>
  18 +#include <linux/of_address.h>
  19 +#include <linux/platform_device.h>
  20 +#include <linux/regulator/driver.h>
  21 +#include <linux/slab.h>
  22 +#include <linux/stat.h>
  23 +#include <linux/timer.h>
  24 +#include <linux/vexpress.h>
  25 +
  26 +#define SYS_ID 0x000
  27 +#define SYS_SW 0x004
  28 +#define SYS_LED 0x008
  29 +#define SYS_100HZ 0x024
  30 +#define SYS_FLAGS 0x030
  31 +#define SYS_FLAGSSET 0x030
  32 +#define SYS_FLAGSCLR 0x034
  33 +#define SYS_NVFLAGS 0x038
  34 +#define SYS_NVFLAGSSET 0x038
  35 +#define SYS_NVFLAGSCLR 0x03c
  36 +#define SYS_MCI 0x048
  37 +#define SYS_FLASH 0x04c
  38 +#define SYS_CFGSW 0x058
  39 +#define SYS_24MHZ 0x05c
  40 +#define SYS_MISC 0x060
  41 +#define SYS_DMA 0x064
  42 +#define SYS_PROCID0 0x084
  43 +#define SYS_PROCID1 0x088
  44 +#define SYS_CFGDATA 0x0a0
  45 +#define SYS_CFGCTRL 0x0a4
  46 +#define SYS_CFGSTAT 0x0a8
  47 +
  48 +#define SYS_HBI_MASK 0xfff
  49 +#define SYS_ID_HBI_SHIFT 16
  50 +#define SYS_PROCIDx_HBI_SHIFT 0
  51 +
  52 +#define SYS_MCI_CARDIN (1 << 0)
  53 +#define SYS_MCI_WPROT (1 << 1)
  54 +
  55 +#define SYS_FLASH_WPn (1 << 0)
  56 +
  57 +#define SYS_MISC_MASTERSITE (1 << 14)
  58 +
  59 +#define SYS_CFGCTRL_START (1 << 31)
  60 +#define SYS_CFGCTRL_WRITE (1 << 30)
  61 +#define SYS_CFGCTRL_DCC(n) (((n) & 0xf) << 26)
  62 +#define SYS_CFGCTRL_FUNC(n) (((n) & 0x3f) << 20)
  63 +#define SYS_CFGCTRL_SITE(n) (((n) & 0x3) << 16)
  64 +#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
  65 +#define SYS_CFGCTRL_DEVICE(n) (((n) & 0xfff) << 0)
  66 +
  67 +#define SYS_CFGSTAT_ERR (1 << 1)
  68 +#define SYS_CFGSTAT_COMPLETE (1 << 0)
  69 +
  70 +
  71 +static void __iomem *vexpress_sysreg_base;
  72 +static struct device *vexpress_sysreg_dev;
  73 +static int vexpress_master_site;
  74 +
  75 +
  76 +void vexpress_flags_set(u32 data)
  77 +{
  78 + writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR);
  79 + writel(data, vexpress_sysreg_base + SYS_FLAGSSET);
  80 +}
  81 +
  82 +u32 vexpress_get_procid(int site)
  83 +{
  84 + if (site == VEXPRESS_SITE_MASTER)
  85 + site = vexpress_master_site;
  86 +
  87 + return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ?
  88 + SYS_PROCID0 : SYS_PROCID1));
  89 +}
  90 +
  91 +u32 vexpress_get_hbi(int site)
  92 +{
  93 + u32 id;
  94 +
  95 + switch (site) {
  96 + case VEXPRESS_SITE_MB:
  97 + id = readl(vexpress_sysreg_base + SYS_ID);
  98 + return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK;
  99 + case VEXPRESS_SITE_MASTER:
  100 + case VEXPRESS_SITE_DB1:
  101 + case VEXPRESS_SITE_DB2:
  102 + id = vexpress_get_procid(site);
  103 + return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
  104 + }
  105 +
  106 + return ~0;
  107 +}
  108 +
  109 +void __iomem *vexpress_get_24mhz_clock_base(void)
  110 +{
  111 + return vexpress_sysreg_base + SYS_24MHZ;
  112 +}
  113 +
  114 +
  115 +static void vexpress_sysreg_find_prop(struct device_node *node,
  116 + const char *name, u32 *val)
  117 +{
  118 + of_node_get(node);
  119 + while (node) {
  120 + if (of_property_read_u32(node, name, val) == 0) {
  121 + of_node_put(node);
  122 + return;
  123 + }
  124 + node = of_get_next_parent(node);
  125 + }
  126 +}
  127 +
  128 +unsigned __vexpress_get_site(struct device *dev, struct device_node *node)
  129 +{
  130 + u32 site = 0;
  131 +
  132 + WARN_ON(dev && node && dev->of_node != node);
  133 + if (dev && !node)
  134 + node = dev->of_node;
  135 +
  136 + if (node) {
  137 + vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
  138 + } else if (dev && dev->bus == &platform_bus_type) {
  139 + struct platform_device *pdev = to_platform_device(dev);
  140 +
  141 + if (pdev->num_resources == 1 &&
  142 + pdev->resource[0].flags == IORESOURCE_BUS)
  143 + site = pdev->resource[0].start;
  144 + } else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) {
  145 + site = VEXPRESS_SITE_MASTER;
  146 + }
  147 +
  148 + if (site == VEXPRESS_SITE_MASTER)
  149 + site = vexpress_master_site;
  150 +
  151 + return site;
  152 +}
  153 +
  154 +
  155 +struct vexpress_sysreg_config_func {
  156 + u32 template;
  157 + u32 device;
  158 +};
  159 +
  160 +static struct vexpress_config_bridge *vexpress_sysreg_config_bridge;
  161 +static struct timer_list vexpress_sysreg_config_timer;
  162 +static u32 *vexpress_sysreg_config_data;
  163 +static int vexpress_sysreg_config_tries;
  164 +
  165 +static void *vexpress_sysreg_config_func_get(struct device *dev,
  166 + struct device_node *node)
  167 +{
  168 + struct vexpress_sysreg_config_func *config_func;
  169 + u32 site;
  170 + u32 position = 0;
  171 + u32 dcc = 0;
  172 + u32 func_device[2];
  173 + int err = -EFAULT;
  174 +
  175 + if (node) {
  176 + of_node_get(node);
  177 + vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
  178 + vexpress_sysreg_find_prop(node, "arm,vexpress,position",
  179 + &position);
  180 + vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc);
  181 + err = of_property_read_u32_array(node,
  182 + "arm,vexpress-sysreg,func", func_device,
  183 + ARRAY_SIZE(func_device));
  184 + of_node_put(node);
  185 + } else if (dev && dev->bus == &platform_bus_type) {
  186 + struct platform_device *pdev = to_platform_device(dev);
  187 +
  188 + if (pdev->num_resources == 1 &&
  189 + pdev->resource[0].flags == IORESOURCE_BUS) {
  190 + site = pdev->resource[0].start;
  191 + func_device[0] = pdev->resource[0].end;
  192 + func_device[1] = pdev->id;
  193 + err = 0;
  194 + }
  195 + }
  196 + if (err)
  197 + return NULL;
  198 +
  199 + config_func = kzalloc(sizeof(*config_func), GFP_KERNEL);
  200 + if (!config_func)
  201 + return NULL;
  202 +
  203 + config_func->template = SYS_CFGCTRL_DCC(dcc);
  204 + config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]);
  205 + config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ?
  206 + vexpress_master_site : site);
  207 + config_func->template |= SYS_CFGCTRL_POSITION(position);
  208 + config_func->device |= func_device[1];
  209 +
  210 + dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func,
  211 + config_func->template, config_func->device);
  212 +
  213 + return config_func;
  214 +}
  215 +
  216 +static void vexpress_sysreg_config_func_put(void *func)
  217 +{
  218 + kfree(func);
  219 +}
  220 +
  221 +static int vexpress_sysreg_config_func_exec(void *func, int offset,
  222 + bool write, u32 *data)
  223 +{
  224 + int status;
  225 + struct vexpress_sysreg_config_func *config_func = func;
  226 + u32 command;
  227 +
  228 + if (WARN_ON(!vexpress_sysreg_base))
  229 + return -ENOENT;
  230 +
  231 + command = readl(vexpress_sysreg_base + SYS_CFGCTRL);
  232 + if (WARN_ON(command & SYS_CFGCTRL_START))
  233 + return -EBUSY;
  234 +
  235 + command = SYS_CFGCTRL_START;
  236 + command |= write ? SYS_CFGCTRL_WRITE : 0;
  237 + command |= config_func->template;
  238 + command |= SYS_CFGCTRL_DEVICE(config_func->device + offset);
  239 +
  240 + /* Use a canary for reads */
  241 + if (!write)
  242 + *data = 0xdeadbeef;
  243 +
  244 + dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n",
  245 + command, *data);
  246 + writel(*data, vexpress_sysreg_base + SYS_CFGDATA);
  247 + writel(0, vexpress_sysreg_base + SYS_CFGSTAT);
  248 + writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
  249 + mb();
  250 +
  251 + if (vexpress_sysreg_dev) {
  252 + /* Schedule completion check */
  253 + if (!write)
  254 + vexpress_sysreg_config_data = data;
  255 + vexpress_sysreg_config_tries = 100;
  256 + mod_timer(&vexpress_sysreg_config_timer,
  257 + jiffies + usecs_to_jiffies(100));
  258 + status = VEXPRESS_CONFIG_STATUS_WAIT;
  259 + } else {
  260 + /* Early execution, no timer available, have to spin */
  261 + u32 cfgstat;
  262 +
  263 + do {
  264 + cpu_relax();
  265 + cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
  266 + } while (!cfgstat);
  267 +
  268 + if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE))
  269 + *data = readl(vexpress_sysreg_base + SYS_CFGDATA);
  270 + status = VEXPRESS_CONFIG_STATUS_DONE;
  271 +
  272 + if (cfgstat & SYS_CFGSTAT_ERR)
  273 + status = -EINVAL;
  274 + }
  275 +
  276 + return status;
  277 +}
  278 +
  279 +struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = {
  280 + .name = "vexpress-sysreg",
  281 + .func_get = vexpress_sysreg_config_func_get,
  282 + .func_put = vexpress_sysreg_config_func_put,
  283 + .func_exec = vexpress_sysreg_config_func_exec,
  284 +};
  285 +
  286 +static void vexpress_sysreg_config_complete(unsigned long data)
  287 +{
  288 + int status = VEXPRESS_CONFIG_STATUS_DONE;
  289 + u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
  290 +
  291 + if (cfgstat & SYS_CFGSTAT_ERR)
  292 + status = -EINVAL;
  293 + if (!vexpress_sysreg_config_tries--)
  294 + status = -ETIMEDOUT;
  295 +
  296 + if (status < 0) {
  297 + dev_err(vexpress_sysreg_dev, "error %d\n", status);
  298 + } else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) {
  299 + mod_timer(&vexpress_sysreg_config_timer,
  300 + jiffies + usecs_to_jiffies(50));
  301 + return;
  302 + }
  303 +
  304 + if (vexpress_sysreg_config_data) {
  305 + *vexpress_sysreg_config_data = readl(vexpress_sysreg_base +
  306 + SYS_CFGDATA);
  307 + dev_dbg(vexpress_sysreg_dev, "read data %x\n",
  308 + *vexpress_sysreg_config_data);
  309 + vexpress_sysreg_config_data = NULL;
  310 + }
  311 +
  312 + vexpress_config_complete(vexpress_sysreg_config_bridge, status);
  313 +}
  314 +
  315 +
  316 +void __init vexpress_sysreg_early_init(void __iomem *base)
  317 +{
  318 + struct device_node *node = of_find_compatible_node(NULL, NULL,
  319 + "arm,vexpress-sysreg");
  320 +
  321 + if (node)
  322 + base = of_iomap(node, 0);
  323 +
  324 + if (WARN_ON(!base))
  325 + return;
  326 +
  327 + vexpress_sysreg_base = base;
  328 +
  329 + if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
  330 + vexpress_master_site = VEXPRESS_SITE_DB2;
  331 + else
  332 + vexpress_master_site = VEXPRESS_SITE_DB1;
  333 +
  334 + vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
  335 + node, &vexpress_sysreg_config_bridge_info);
  336 + WARN_ON(!vexpress_sysreg_config_bridge);
  337 +}
  338 +
  339 +void __init vexpress_sysreg_of_early_init(void)
  340 +{
  341 + vexpress_sysreg_early_init(NULL);
  342 +}
  343 +
  344 +
  345 +static struct vexpress_sysreg_gpio {
  346 + unsigned long reg;
  347 + u32 value;
  348 +} vexpress_sysreg_gpios[] = {
  349 + [VEXPRESS_GPIO_MMC_CARDIN] = {
  350 + .reg = SYS_MCI,
  351 + .value = SYS_MCI_CARDIN,
  352 + },
  353 + [VEXPRESS_GPIO_MMC_WPROT] = {
  354 + .reg = SYS_MCI,
  355 + .value = SYS_MCI_WPROT,
  356 + },
  357 + [VEXPRESS_GPIO_FLASH_WPn] = {
  358 + .reg = SYS_FLASH,
  359 + .value = SYS_FLASH_WPn,
  360 + },
  361 +};
  362 +
  363 +static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
  364 + unsigned offset)
  365 +{
  366 + return 0;
  367 +}
  368 +
  369 +static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
  370 + unsigned offset, int value)
  371 +{
  372 + return 0;
  373 +}
  374 +
  375 +static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
  376 + unsigned offset)
  377 +{
  378 + struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
  379 + u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
  380 +
  381 + return !!(reg_value & gpio->value);
  382 +}
  383 +
  384 +static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
  385 + unsigned offset, int value)
  386 +{
  387 + struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
  388 + u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
  389 +
  390 + if (value)
  391 + reg_value |= gpio->value;
  392 + else
  393 + reg_value &= ~gpio->value;
  394 +
  395 + writel(reg_value, vexpress_sysreg_base + gpio->reg);
  396 +}
  397 +
  398 +static struct gpio_chip vexpress_sysreg_gpio_chip = {
  399 + .label = "vexpress-sysreg",
  400 + .direction_input = vexpress_sysreg_gpio_direction_input,
  401 + .direction_output = vexpress_sysreg_gpio_direction_output,
  402 + .get = vexpress_sysreg_gpio_get,
  403 + .set = vexpress_sysreg_gpio_set,
  404 + .ngpio = ARRAY_SIZE(vexpress_sysreg_gpios),
  405 + .base = 0,
  406 +};
  407 +
  408 +
  409 +static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
  410 + struct device_attribute *attr, char *buf)
  411 +{
  412 + return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID));
  413 +}
  414 +
  415 +DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL);
  416 +
  417 +static int __devinit vexpress_sysreg_probe(struct platform_device *pdev)
  418 +{
  419 + int err;
  420 + struct resource *res = platform_get_resource(pdev,
  421 + IORESOURCE_MEM, 0);
  422 +
  423 + if (!devm_request_mem_region(&pdev->dev, res->start,
  424 + resource_size(res), pdev->name)) {
  425 + dev_err(&pdev->dev, "Failed to request memory region!\n");
  426 + return -EBUSY;
  427 + }
  428 +
  429 + if (!vexpress_sysreg_base)
  430 + vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start,
  431 + resource_size(res));
  432 +
  433 + if (!vexpress_sysreg_base) {
  434 + dev_err(&pdev->dev, "Failed to obtain base address!\n");
  435 + return -EFAULT;
  436 + }
  437 +
  438 + setup_timer(&vexpress_sysreg_config_timer,
  439 + vexpress_sysreg_config_complete, 0);
  440 +
  441 + vexpress_sysreg_gpio_chip.dev = &pdev->dev;
  442 + err = gpiochip_add(&vexpress_sysreg_gpio_chip);
  443 + if (err) {
  444 + vexpress_config_bridge_unregister(
  445 + vexpress_sysreg_config_bridge);
  446 + dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n",
  447 + err);
  448 + return err;
  449 + }
  450 +
  451 + vexpress_sysreg_dev = &pdev->dev;
  452 +
  453 + device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
  454 +
  455 + return 0;
  456 +}
  457 +
  458 +static const struct of_device_id vexpress_sysreg_match[] = {
  459 + { .compatible = "arm,vexpress-sysreg", },
  460 + {},
  461 +};
  462 +
  463 +static struct platform_driver vexpress_sysreg_driver = {
  464 + .driver = {
  465 + .name = "vexpress-sysreg",
  466 + .of_match_table = vexpress_sysreg_match,
  467 + },
  468 + .probe = vexpress_sysreg_probe,
  469 +};
  470 +
  471 +static int __init vexpress_sysreg_init(void)
  472 +{
  473 + return platform_driver_register(&vexpress_sysreg_driver);
  474 +}
  475 +core_initcall(vexpress_sysreg_init);
  476 +
  477 +
  478 +#if defined(CONFIG_LEDS_CLASS)
  479 +
  480 +struct vexpress_sysreg_led {
  481 + u32 mask;
  482 + struct led_classdev cdev;
  483 +} vexpress_sysreg_leds[] = {
  484 + { .mask = 1 << 0, .cdev.name = "v2m:green:user1",
  485 + .cdev.default_trigger = "heartbeat", },
  486 + { .mask = 1 << 1, .cdev.name = "v2m:green:user2",
  487 + .cdev.default_trigger = "mmc0", },
  488 + { .mask = 1 << 2, .cdev.name = "v2m:green:user3",
  489 + .cdev.default_trigger = "cpu0", },
  490 + { .mask = 1 << 3, .cdev.name = "v2m:green:user4",
  491 + .cdev.default_trigger = "cpu1", },
  492 + { .mask = 1 << 4, .cdev.name = "v2m:green:user5",
  493 + .cdev.default_trigger = "cpu2", },
  494 + { .mask = 1 << 5, .cdev.name = "v2m:green:user6",
  495 + .cdev.default_trigger = "cpu3", },
  496 + { .mask = 1 << 6, .cdev.name = "v2m:green:user7",
  497 + .cdev.default_trigger = "cpu4", },
  498 + { .mask = 1 << 7, .cdev.name = "v2m:green:user8",
  499 + .cdev.default_trigger = "cpu5", },
  500 +};
  501 +
  502 +static DEFINE_SPINLOCK(vexpress_sysreg_leds_lock);
  503 +
  504 +static void vexpress_sysreg_led_brightness_set(struct led_classdev *cdev,
  505 + enum led_brightness brightness)
  506 +{
  507 + struct vexpress_sysreg_led *led = container_of(cdev,
  508 + struct vexpress_sysreg_led, cdev);
  509 + unsigned long flags;
  510 + u32 val;
  511 +
  512 + spin_lock_irqsave(&vexpress_sysreg_leds_lock, flags);
  513 +
  514 + val = readl(vexpress_sysreg_base + SYS_LED);
  515 + if (brightness == LED_OFF)
  516 + val &= ~led->mask;
  517 + else
  518 + val |= led->mask;
  519 + writel(val, vexpress_sysreg_base + SYS_LED);
  520 +
  521 + spin_unlock_irqrestore(&vexpress_sysreg_leds_lock, flags);
  522 +}
  523 +
  524 +static int __init vexpress_sysreg_init_leds(void)
  525 +{
  526 + struct vexpress_sysreg_led *led;
  527 + int i;
  528 +
  529 + /* Clear all user LEDs */
  530 + writel(0, vexpress_sysreg_base + SYS_LED);
  531 +
  532 + for (i = 0, led = vexpress_sysreg_leds;
  533 + i < ARRAY_SIZE(vexpress_sysreg_leds); i++, led++) {
  534 + int err;
  535 +
  536 + led->cdev.brightness_set = vexpress_sysreg_led_brightness_set;
  537 + err = led_classdev_register(vexpress_sysreg_dev, &led->cdev);
  538 + if (err) {
  539 + dev_err(vexpress_sysreg_dev,
  540 + "Failed to register LED %d! (%d)\n",
  541 + i, err);
  542 + while (led--, i--)
  543 + led_classdev_unregister(&led->cdev);
  544 + return err;
  545 + }
  546 + }
  547 +
  548 + return 0;
  549 +}
  550 +device_initcall(vexpress_sysreg_init_leds);
  551 +
  552 +#endif
include/linux/vexpress.h
... ... @@ -24,6 +24,17 @@
24 24 #define VEXPRESS_CONFIG_STATUS_DONE 0
25 25 #define VEXPRESS_CONFIG_STATUS_WAIT 1
26 26  
  27 +#define VEXPRESS_GPIO_MMC_CARDIN 0
  28 +#define VEXPRESS_GPIO_MMC_WPROT 1
  29 +#define VEXPRESS_GPIO_FLASH_WPn 2
  30 +
  31 +#define VEXPRESS_RES_FUNC(_site, _func) \
  32 +{ \
  33 + .start = (_site), \
  34 + .end = (_func), \
  35 + .flags = IORESOURCE_BUS, \
  36 +}
  37 +
27 38 /* Config bridge API */
28 39  
29 40 /**
... ... @@ -81,6 +92,20 @@
81 92 u32 *data);
82 93 int vexpress_config_write(struct vexpress_config_func *func, int offset,
83 94 u32 data);
  95 +
  96 +/* Platform control */
  97 +
  98 +u32 vexpress_get_procid(int site);
  99 +u32 vexpress_get_hbi(int site);
  100 +void *vexpress_get_24mhz_clock_base(void);
  101 +void vexpress_flags_set(u32 data);
  102 +
  103 +#define vexpress_get_site_by_node(node) __vexpress_get_site(NULL, node)
  104 +#define vexpress_get_site_by_dev(dev) __vexpress_get_site(dev, NULL)
  105 +unsigned __vexpress_get_site(struct device *dev, struct device_node *node);
  106 +
  107 +void vexpress_sysreg_early_init(void __iomem *base);
  108 +void vexpress_sysreg_of_early_init(void);
84 109  
85 110 #endif