Commit aeec56e331c6d2750de02ef34b305338305ca690

Authored by Anton Vorontsov
Committed by Linus Torvalds
1 parent d0f744c8cb

gpio: add driver for basic memory-mapped GPIO controllers

The basic GPIO controllers may be found in various on-board FPGA and ASIC
solutions that are used to control board's switches, LEDs, chip-selects,
Ethernet/USB PHY power, etc.

These controllers may not provide any means of pin setup
(in/out/open drain).

The driver supports:
- 8/16/32/64 bits registers;
- GPIO controllers with clear/set registers;
- GPIO controllers with a single "data" register;
- Big endian bits/GPIOs ordering (mostly used on PowerPC).

Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Samuel Ortiz <sameo@linux.intel.com>,
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 4 changed files with 323 additions and 0 deletions Side-by-side Diff

drivers/gpio/Kconfig
... ... @@ -70,6 +70,11 @@
70 70  
71 71 comment "Memory mapped GPIO expanders:"
72 72  
  73 +config GPIO_BASIC_MMIO
  74 + tristate "Basic memory-mapped GPIO controllers support"
  75 + help
  76 + Say yes here to support basic memory-mapped GPIO controllers.
  77 +
73 78 config GPIO_IT8761E
74 79 tristate "IT8761E GPIO support"
75 80 depends on GPIOLIB
drivers/gpio/Makefile
... ... @@ -10,6 +10,7 @@
10 10  
11 11 obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o
12 12 obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o
  13 +obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o
13 14 obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o
14 15 obj-$(CONFIG_GPIO_MAX730X) += max730x.o
15 16 obj-$(CONFIG_GPIO_MAX7300) += max7300.o
drivers/gpio/basic_mmio_gpio.c
  1 +/*
  2 + * Driver for basic memory-mapped GPIO controllers.
  3 + *
  4 + * Copyright 2008 MontaVista Software, Inc.
  5 + * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify it
  8 + * under the terms of the GNU General Public License as published by the
  9 + * Free Software Foundation; either version 2 of the License, or (at your
  10 + * option) any later version.
  11 + *
  12 + * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
  13 + * ...`` ```````..
  14 + * ..The simplest form of a GPIO controller that the driver supports is``
  15 + * `.just a single "data" register, where GPIO state can be read and/or `
  16 + * `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.```````
  17 + * `````````
  18 + ___
  19 +_/~~|___/~| . ```~~~~~~ ___/___\___ ,~.`.`.`.`````.~~...,,,,...
  20 +__________|~$@~~~ %~ /o*o*o*o*o*o\ .. Implementing such a GPIO .
  21 +o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
  22 + `....trivial..'~`.```.```
  23 + * ```````
  24 + * .```````~~~~`..`.``.``.
  25 + * . The driver supports `... ,..```.`~~~```````````````....````.``,,
  26 + * . big-endian notation, just`. .. A bit more sophisticated controllers ,
  27 + * . register the device with -be`. .with a pair of set/clear-bit registers ,
  28 + * `.. suffix. ```~~`````....`.` . affecting the data register and the .`
  29 + * ``.`.``...``` ```.. output pins are also supported.`
  30 + * ^^ `````.`````````.,``~``~``~~``````
  31 + * . ^^
  32 + * ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`..
  33 + * .. The expectation is that in at least some cases . ,-~~~-,
  34 + * .this will be used with roll-your-own ASIC/FPGA .` \ /
  35 + * .logic in Verilog or VHDL. ~~~`````````..`````~~` \ /
  36 + * ..````````......``````````` \o_
  37 + * |
  38 + * ^^ / \
  39 + *
  40 + * ...`````~~`.....``.`..........``````.`.``.```........``.
  41 + * ` 8, 16, 32 and 64 bits registers are supported, and``.
  42 + * . the number of GPIOs is determined by the width of ~
  43 + * .. the registers. ,............```.`.`..`.`.~~~.`.`.`~
  44 + * `.......````.```
  45 + */
  46 +
  47 +#include <linux/init.h>
  48 +#include <linux/bug.h>
  49 +#include <linux/kernel.h>
  50 +#include <linux/module.h>
  51 +#include <linux/spinlock.h>
  52 +#include <linux/compiler.h>
  53 +#include <linux/types.h>
  54 +#include <linux/errno.h>
  55 +#include <linux/log2.h>
  56 +#include <linux/ioport.h>
  57 +#include <linux/io.h>
  58 +#include <linux/gpio.h>
  59 +#include <linux/slab.h>
  60 +#include <linux/platform_device.h>
  61 +#include <linux/mod_devicetable.h>
  62 +#include <linux/basic_mmio_gpio.h>
  63 +
  64 +struct bgpio_chip {
  65 + struct gpio_chip gc;
  66 + void __iomem *reg_dat;
  67 + void __iomem *reg_set;
  68 + void __iomem *reg_clr;
  69 +
  70 + /* Number of bits (GPIOs): <register width> * 8. */
  71 + int bits;
  72 +
  73 + /*
  74 + * Some GPIO controllers work with the big-endian bits notation,
  75 + * e.g. in a 8-bits register, GPIO7 is the least significant bit.
  76 + */
  77 + int big_endian_bits;
  78 +
  79 + /*
  80 + * Used to lock bgpio_chip->data. Also, this is needed to keep
  81 + * shadowed and real data registers writes together.
  82 + */
  83 + spinlock_t lock;
  84 +
  85 + /* Shadowed data register to clear/set bits safely. */
  86 + unsigned long data;
  87 +};
  88 +
  89 +static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
  90 +{
  91 + return container_of(gc, struct bgpio_chip, gc);
  92 +}
  93 +
  94 +static unsigned long bgpio_in(struct bgpio_chip *bgc)
  95 +{
  96 + switch (bgc->bits) {
  97 + case 8:
  98 + return __raw_readb(bgc->reg_dat);
  99 + case 16:
  100 + return __raw_readw(bgc->reg_dat);
  101 + case 32:
  102 + return __raw_readl(bgc->reg_dat);
  103 +#if BITS_PER_LONG >= 64
  104 + case 64:
  105 + return __raw_readq(bgc->reg_dat);
  106 +#endif
  107 + }
  108 + return -EINVAL;
  109 +}
  110 +
  111 +static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg,
  112 + unsigned long data)
  113 +{
  114 + switch (bgc->bits) {
  115 + case 8:
  116 + __raw_writeb(data, reg);
  117 + return;
  118 + case 16:
  119 + __raw_writew(data, reg);
  120 + return;
  121 + case 32:
  122 + __raw_writel(data, reg);
  123 + return;
  124 +#if BITS_PER_LONG >= 64
  125 + case 64:
  126 + __raw_writeq(data, reg);
  127 + return;
  128 +#endif
  129 + }
  130 +}
  131 +
  132 +static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
  133 +{
  134 + if (bgc->big_endian_bits)
  135 + return 1 << (bgc->bits - 1 - pin);
  136 + else
  137 + return 1 << pin;
  138 +}
  139 +
  140 +static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
  141 +{
  142 + struct bgpio_chip *bgc = to_bgpio_chip(gc);
  143 +
  144 + return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio);
  145 +}
  146 +
  147 +static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
  148 +{
  149 + struct bgpio_chip *bgc = to_bgpio_chip(gc);
  150 + unsigned long mask = bgpio_pin2mask(bgc, gpio);
  151 + unsigned long flags;
  152 +
  153 + if (bgc->reg_set) {
  154 + if (val)
  155 + bgpio_out(bgc, bgc->reg_set, mask);
  156 + else
  157 + bgpio_out(bgc, bgc->reg_clr, mask);
  158 + return;
  159 + }
  160 +
  161 + spin_lock_irqsave(&bgc->lock, flags);
  162 +
  163 + if (val)
  164 + bgc->data |= mask;
  165 + else
  166 + bgc->data &= ~mask;
  167 +
  168 + bgpio_out(bgc, bgc->reg_dat, bgc->data);
  169 +
  170 + spin_unlock_irqrestore(&bgc->lock, flags);
  171 +}
  172 +
  173 +static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
  174 +{
  175 + return 0;
  176 +}
  177 +
  178 +static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
  179 +{
  180 + bgpio_set(gc, gpio, val);
  181 + return 0;
  182 +}
  183 +
  184 +static int __devinit bgpio_probe(struct platform_device *pdev)
  185 +{
  186 + const struct platform_device_id *platid = platform_get_device_id(pdev);
  187 + struct device *dev = &pdev->dev;
  188 + struct bgpio_pdata *pdata = dev_get_platdata(dev);
  189 + struct bgpio_chip *bgc;
  190 + struct resource *res_dat;
  191 + struct resource *res_set;
  192 + struct resource *res_clr;
  193 + resource_size_t dat_sz;
  194 + int bits;
  195 + int ret;
  196 +
  197 + res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
  198 + if (!res_dat)
  199 + return -EINVAL;
  200 +
  201 + dat_sz = resource_size(res_dat);
  202 + if (!is_power_of_2(dat_sz))
  203 + return -EINVAL;
  204 +
  205 + bits = dat_sz * 8;
  206 + if (bits > BITS_PER_LONG)
  207 + return -EINVAL;
  208 +
  209 + bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
  210 + if (!bgc)
  211 + return -ENOMEM;
  212 +
  213 + bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz);
  214 + if (!bgc->reg_dat)
  215 + return -ENOMEM;
  216 +
  217 + res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
  218 + res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
  219 + if (res_set && res_clr) {
  220 + if (resource_size(res_set) != resource_size(res_clr) ||
  221 + resource_size(res_set) != dat_sz)
  222 + return -EINVAL;
  223 +
  224 + bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz);
  225 + bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz);
  226 + if (!bgc->reg_set || !bgc->reg_clr)
  227 + return -ENOMEM;
  228 + } else if (res_set || res_clr) {
  229 + return -EINVAL;
  230 + }
  231 +
  232 + spin_lock_init(&bgc->lock);
  233 +
  234 + bgc->bits = bits;
  235 + bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be");
  236 + bgc->data = bgpio_in(bgc);
  237 +
  238 + bgc->gc.ngpio = bits;
  239 + bgc->gc.direction_input = bgpio_dir_in;
  240 + bgc->gc.direction_output = bgpio_dir_out;
  241 + bgc->gc.get = bgpio_get;
  242 + bgc->gc.set = bgpio_set;
  243 + bgc->gc.dev = dev;
  244 + bgc->gc.label = dev_name(dev);
  245 +
  246 + if (pdata)
  247 + bgc->gc.base = pdata->base;
  248 + else
  249 + bgc->gc.base = -1;
  250 +
  251 + dev_set_drvdata(dev, bgc);
  252 +
  253 + ret = gpiochip_add(&bgc->gc);
  254 + if (ret)
  255 + dev_err(dev, "gpiochip_add() failed: %d\n", ret);
  256 +
  257 + return ret;
  258 +}
  259 +
  260 +static int __devexit bgpio_remove(struct platform_device *pdev)
  261 +{
  262 + struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev);
  263 +
  264 + return gpiochip_remove(&bgc->gc);
  265 +}
  266 +
  267 +static const struct platform_device_id bgpio_id_table[] = {
  268 + { "basic-mmio-gpio", },
  269 + { "basic-mmio-gpio-be", },
  270 + {},
  271 +};
  272 +MODULE_DEVICE_TABLE(platform, bgpio_id_table);
  273 +
  274 +static struct platform_driver bgpio_driver = {
  275 + .driver = {
  276 + .name = "basic-mmio-gpio",
  277 + },
  278 + .id_table = bgpio_id_table,
  279 + .probe = bgpio_probe,
  280 + .remove = __devexit_p(bgpio_remove),
  281 +};
  282 +
  283 +static int __init bgpio_init(void)
  284 +{
  285 + return platform_driver_register(&bgpio_driver);
  286 +}
  287 +module_init(bgpio_init);
  288 +
  289 +static void __exit bgpio_exit(void)
  290 +{
  291 + platform_driver_unregister(&bgpio_driver);
  292 +}
  293 +module_exit(bgpio_exit);
  294 +
  295 +MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
  296 +MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
  297 +MODULE_LICENSE("GPL");
include/linux/basic_mmio_gpio.h
  1 +/*
  2 + * Basic memory-mapped GPIO controllers.
  3 + *
  4 + * Copyright 2008 MontaVista Software, Inc.
  5 + * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
  6 + *
  7 + * This program is free software; you can redistribute it and/or modify it
  8 + * under the terms of the GNU General Public License as published by the
  9 + * Free Software Foundation; either version 2 of the License, or (at your
  10 + * option) any later version.
  11 + */
  12 +
  13 +#ifndef __BASIC_MMIO_GPIO_H
  14 +#define __BASIC_MMIO_GPIO_H
  15 +
  16 +struct bgpio_pdata {
  17 + int base;
  18 +};
  19 +
  20 +#endif /* __BASIC_MMIO_GPIO_H */