51e02b02e6
The current in-kernel Alchemy GPIO support is far too inflexible for all my use cases. To address this, the following changes are made: * create generic functions which deal with manipulating the on-chip GPIO1/2 blocks. Such functions are universally useful. * Macros for GPIO2 shared interrupt management and block control. * support for both built-in CONFIG_GPIOLIB and fast, inlined GPIO macros. If CONFIG_GPIOLIB is not enabled, provide linux gpio framework compatibility by directly inlining the GPIO1/2 functions. GPIO access is limited to on-chip ones and they can be accessed as documented in the datasheets (GPIO0-31 and 200-215). If CONFIG_GPIOLIB is selected, two (2) gpio_chip-s, one for GPIO1 and one for GPIO2, are registered. GPIOs can still be accessed by using the numberspace established in the databooks. However this is not yet flexible enough for my uses: My Alchemy systems have a documented "external" gpio interface (fixed, different numberspace) and can support a variety of baseboards, some of which are equipped with I2C gpio expanders. I want to be able to provide the default 16 GPIOs of the CPU board numbered as 0..15 and also support gpio expanders, if present, starting as gpio16. To achieve this, a new Kconfig symbol for Alchemy is introduced, CONFIG_ALCHEMY_GPIO_INDIRECT, which boards can enable to signal that they don't want the Alchemy numberspace exposed to the outside world, but instead want to provide their own. Boards are now respon- sible for providing the linux gpio interface glue code (either in a custom gpio.h header (in board include directory) or with gpio_chips). To make the board-specific inlined gpio functions work, the MIPS Makefile must be changed so that the mach-au1x00/gpio.h header is included _after_ the board headers, by moving the inclusion of the mach-au1x00/ to the end of the header list. See arch/mips/include/asm/mach-au1x00/gpio.h for more info. Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com> Acked-by: Florian Fainelli <florian@openwrt.org> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
130 lines
4.1 KiB
C
130 lines
4.1 KiB
C
/*
|
|
* Copyright (C) 2007-2009, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
|
|
* GPIOLIB support for Au1000, Au1500, Au1100, Au1550 and Au12x0.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
|
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* Notes :
|
|
* au1000 SoC have only one GPIO block : GPIO1
|
|
* Au1100, Au15x0, Au12x0 have a second one : GPIO2
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/gpio.h>
|
|
|
|
#include <asm/mach-au1x00/au1000.h>
|
|
#include <asm/mach-au1x00/gpio.h>
|
|
|
|
#if !defined(CONFIG_SOC_AU1000)
|
|
static int gpio2_get(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
return alchemy_gpio2_get_value(offset + ALCHEMY_GPIO2_BASE);
|
|
}
|
|
|
|
static void gpio2_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
{
|
|
alchemy_gpio2_set_value(offset + ALCHEMY_GPIO2_BASE, value);
|
|
}
|
|
|
|
static int gpio2_direction_input(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
return alchemy_gpio2_direction_input(offset + ALCHEMY_GPIO2_BASE);
|
|
}
|
|
|
|
static int gpio2_direction_output(struct gpio_chip *chip, unsigned offset,
|
|
int value)
|
|
{
|
|
return alchemy_gpio2_direction_output(offset + ALCHEMY_GPIO2_BASE,
|
|
value);
|
|
}
|
|
|
|
static int gpio2_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
return alchemy_gpio2_to_irq(offset + ALCHEMY_GPIO2_BASE);
|
|
}
|
|
#endif /* !defined(CONFIG_SOC_AU1000) */
|
|
|
|
static int gpio1_get(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
return alchemy_gpio1_get_value(offset + ALCHEMY_GPIO1_BASE);
|
|
}
|
|
|
|
static void gpio1_set(struct gpio_chip *chip,
|
|
unsigned offset, int value)
|
|
{
|
|
alchemy_gpio1_set_value(offset + ALCHEMY_GPIO1_BASE, value);
|
|
}
|
|
|
|
static int gpio1_direction_input(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
return alchemy_gpio1_direction_input(offset + ALCHEMY_GPIO1_BASE);
|
|
}
|
|
|
|
static int gpio1_direction_output(struct gpio_chip *chip,
|
|
unsigned offset, int value)
|
|
{
|
|
return alchemy_gpio1_direction_output(offset + ALCHEMY_GPIO1_BASE,
|
|
value);
|
|
}
|
|
|
|
static int gpio1_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
return alchemy_gpio1_to_irq(offset + ALCHEMY_GPIO1_BASE);
|
|
}
|
|
|
|
struct gpio_chip alchemy_gpio_chip[] = {
|
|
[0] = {
|
|
.label = "alchemy-gpio1",
|
|
.direction_input = gpio1_direction_input,
|
|
.direction_output = gpio1_direction_output,
|
|
.get = gpio1_get,
|
|
.set = gpio1_set,
|
|
.to_irq = gpio1_to_irq,
|
|
.base = ALCHEMY_GPIO1_BASE,
|
|
.ngpio = ALCHEMY_GPIO1_NUM,
|
|
},
|
|
#if !defined(CONFIG_SOC_AU1000)
|
|
[1] = {
|
|
.label = "alchemy-gpio2",
|
|
.direction_input = gpio2_direction_input,
|
|
.direction_output = gpio2_direction_output,
|
|
.get = gpio2_get,
|
|
.set = gpio2_set,
|
|
.to_irq = gpio2_to_irq,
|
|
.base = ALCHEMY_GPIO2_BASE,
|
|
.ngpio = ALCHEMY_GPIO2_NUM,
|
|
},
|
|
#endif
|
|
};
|
|
|
|
static int __init alchemy_gpiolib_init(void)
|
|
{
|
|
gpiochip_add(&alchemy_gpio_chip[0]);
|
|
#if !defined(CONFIG_SOC_AU1000)
|
|
gpiochip_add(&alchemy_gpio_chip[1]);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
arch_initcall(alchemy_gpiolib_init);
|