提交 b1bf7d4d 编写于 作者: L Linus Torvalds

Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux-2.6

Pull GPIO driver changes from Grant Likely:
 "Lots of gpio changes, both to core code and drivers.

  Changes do touch architecture code to remove the need for separate
  arm/gpio.h includes in most architectures.

  Some new drivers are added, and a number of gpio drivers are converted
  to use irq_domains for gpio inputs used as interrupts.  Device tree
  support has been amended to allow multiple gpio_chips to use the same
  device tree node.

  Remaining changes are primarily bug fixes."

* tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux-2.6: (33 commits)
  gpio/generic: initialize basic_mmio_gpio shadow variables properly
  gpiolib: Remove 'const' from data argument of gpiochip_find()
  gpio/rc5t583: add gpio driver for RICOH PMIC RC5T583
  gpiolib: quiet gpiochip_add boot message noise
  gpio: mpc8xxx: Prevent NULL pointer deref in demux handler
  gpio/lpc32xx: Add device tree support
  gpio: Adjust of_xlate API to support multiple GPIO chips
  gpiolib: Implement devm_gpio_request_one()
  gpio-mcp23s08: dbg_show: fix pullup configuration display
  Add support for TCA6424A
  gpio/omap: (re)fix wakeups on level-triggered GPIOs
  gpio/omap: fix broken context restore for non-OFF mode transitions
  gpio/omap: fix missing check in *_runtime_suspend()
  gpio/omap: remove cpu_is_omapxxxx() checks from *_runtime_resume()
  gpio/omap: remove suspend/resume callbacks
  gpio/omap: remove retrigger variable in gpio_irq_handler
  gpio/omap: remove saved_wakeup field from struct gpio_bank
  gpio/omap: remove suspend_wakeup field from struct gpio_bank
  gpio/omap: remove saved_fallingdetect, saved_risingdetect
  gpio/omap: remove virtual_irq_start variable
  ...

Conflicts:
	drivers/gpio/gpio-samsung.c
NXP LPC32xx SoC GPIO controller
Required properties:
- compatible: must be "nxp,lpc3220-gpio"
- reg: Physical base address and length of the controller's registers.
- gpio-controller: Marks the device node as a GPIO controller.
- #gpio-cells: Should be 3:
1) bank:
0: GPIO P0
1: GPIO P1
2: GPIO P2
3: GPIO P3
4: GPI P3
5: GPO P3
2) pin number
3) optional parameters:
- bit 0 specifies polarity (0 for normal, 1 for inverted)
- reg: Index of the GPIO group
Example:
gpio: gpio@40028000 {
compatible = "nxp,lpc3220-gpio";
reg = <0x40028000 0x1000>;
gpio-controller;
#gpio-cells = <3>; /* bank, pin, flags */
};
leds {
compatible = "gpio-leds";
led0 {
gpios = <&gpio 5 1 1>; /* GPO_P3 1, active low */
linux,default-trigger = "heartbeat";
default-state = "off";
};
led1 {
gpios = <&gpio 5 14 1>; /* GPO_P3 14, active low */
linux,default-trigger = "timer";
default-state = "off";
};
};
...@@ -322,6 +322,9 @@ where 'flags' is currently defined to specify the following properties: ...@@ -322,6 +322,9 @@ where 'flags' is currently defined to specify the following properties:
* GPIOF_OPEN_DRAIN - gpio pin is open drain type. * GPIOF_OPEN_DRAIN - gpio pin is open drain type.
* GPIOF_OPEN_SOURCE - gpio pin is open source type. * GPIOF_OPEN_SOURCE - gpio pin is open source type.
* GPIOF_EXPORT_DIR_FIXED - export gpio to sysfs, keep direction
* GPIOF_EXPORT_DIR_CHANGEABLE - also export, allow changing direction
since GPIOF_INIT_* are only valid when configured as output, so group valid since GPIOF_INIT_* are only valid when configured as output, so group valid
combinations as: combinations as:
......
/* #ifndef __LINUX_GPIO_H
* Generic GPIO API implementation for Alpha. #warning Include linux/gpio.h instead of asm/gpio.h
* #include <linux/gpio.h>
* A stright copy of that for PowerPC which was: #endif
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* 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.
*/
#ifndef _ASM_ALPHA_GPIO_H
#define _ASM_ALPHA_GPIO_H
#include <linux/errno.h>
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
/*
* We don't (yet) implement inlined/rapid versions for on-chip gpios.
* Just call gpiolib.
*/
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* _ASM_ALPHA_GPIO_H */
config ARM config ARM
bool bool
default y default y
select ARCH_HAVE_CUSTOM_GPIO_H
select HAVE_AOUT select HAVE_AOUT
select HAVE_DMA_API_DEBUG select HAVE_DMA_API_DEBUG
select HAVE_IDE if PCI || ISA || PCMCIA select HAVE_IDE if PCI || ISA || PCMCIA
......
...@@ -98,8 +98,7 @@ static struct i2c_board_info __initdata i2c_devices_3ds[] = { ...@@ -98,8 +98,7 @@ static struct i2c_board_info __initdata i2c_devices_3ds[] = {
static int lcd_power_gpio = -ENXIO; static int lcd_power_gpio = -ENXIO;
static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip, static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip, void *data)
const void *data)
{ {
return !strcmp(chip->label, data); return !strcmp(chip->label, data);
} }
......
/* empty */ #ifndef __MACH_GPIO_H
#define __MACH_GPIO_H
#include "gpio-lpc32xx.h"
#define ARCH_NR_GPIOS (LPC32XX_GPO_P3_GRP + LPC32XX_GPO_P3_MAX)
#endif /* __MACH_GPIO_H */
...@@ -46,7 +46,6 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = { ...@@ -46,7 +46,6 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {
}; };
static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = { static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
.virtual_irq_start = IH_MPUIO_BASE,
.is_mpuio = true, .is_mpuio = true,
.bank_width = 16, .bank_width = 16,
.bank_stride = 1, .bank_stride = 1,
...@@ -89,7 +88,6 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = { ...@@ -89,7 +88,6 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
}; };
static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = { static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
.virtual_irq_start = IH_GPIO_BASE,
.bank_width = 16, .bank_width = 16,
.regs = &omap15xx_gpio_regs, .regs = &omap15xx_gpio_regs,
}; };
......
...@@ -52,7 +52,6 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = { ...@@ -52,7 +52,6 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {
}; };
static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = { static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
.virtual_irq_start = IH_MPUIO_BASE,
.is_mpuio = true, .is_mpuio = true,
.bank_width = 16, .bank_width = 16,
.bank_stride = 1, .bank_stride = 1,
...@@ -99,7 +98,6 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = { ...@@ -99,7 +98,6 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
}; };
static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = { static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
.virtual_irq_start = IH_GPIO_BASE,
.bank_width = 16, .bank_width = 16,
.regs = &omap16xx_gpio_regs, .regs = &omap16xx_gpio_regs,
}; };
...@@ -128,7 +126,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = { ...@@ -128,7 +126,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = { static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
.virtual_irq_start = IH_GPIO_BASE + 16,
.bank_width = 16, .bank_width = 16,
.regs = &omap16xx_gpio_regs, .regs = &omap16xx_gpio_regs,
}; };
...@@ -157,7 +154,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = { ...@@ -157,7 +154,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = { static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
.virtual_irq_start = IH_GPIO_BASE + 32,
.bank_width = 16, .bank_width = 16,
.regs = &omap16xx_gpio_regs, .regs = &omap16xx_gpio_regs,
}; };
...@@ -186,7 +182,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = { ...@@ -186,7 +182,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = { static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
.virtual_irq_start = IH_GPIO_BASE + 48,
.bank_width = 16, .bank_width = 16,
.regs = &omap16xx_gpio_regs, .regs = &omap16xx_gpio_regs,
}; };
......
...@@ -51,7 +51,6 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = { ...@@ -51,7 +51,6 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {
}; };
static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = { static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
.virtual_irq_start = IH_MPUIO_BASE,
.is_mpuio = true, .is_mpuio = true,
.bank_width = 16, .bank_width = 16,
.bank_stride = 2, .bank_stride = 2,
...@@ -93,7 +92,6 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = { ...@@ -93,7 +92,6 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = {
}; };
static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = { static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
.virtual_irq_start = IH_GPIO_BASE,
.bank_width = 32, .bank_width = 32,
.regs = &omap7xx_gpio_regs, .regs = &omap7xx_gpio_regs,
}; };
...@@ -122,7 +120,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = { ...@@ -122,7 +120,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = { static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
.virtual_irq_start = IH_GPIO_BASE + 32,
.bank_width = 32, .bank_width = 32,
.regs = &omap7xx_gpio_regs, .regs = &omap7xx_gpio_regs,
}; };
...@@ -151,7 +148,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = { ...@@ -151,7 +148,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = { static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
.virtual_irq_start = IH_GPIO_BASE + 64,
.bank_width = 32, .bank_width = 32,
.regs = &omap7xx_gpio_regs, .regs = &omap7xx_gpio_regs,
}; };
...@@ -180,7 +176,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = { ...@@ -180,7 +176,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = { static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
.virtual_irq_start = IH_GPIO_BASE + 96,
.bank_width = 32, .bank_width = 32,
.regs = &omap7xx_gpio_regs, .regs = &omap7xx_gpio_regs,
}; };
...@@ -209,7 +204,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = { ...@@ -209,7 +204,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = { static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
.virtual_irq_start = IH_GPIO_BASE + 128,
.bank_width = 32, .bank_width = 32,
.regs = &omap7xx_gpio_regs, .regs = &omap7xx_gpio_regs,
}; };
...@@ -238,7 +232,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = { ...@@ -238,7 +232,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = {
}; };
static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = { static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
.virtual_irq_start = IH_GPIO_BASE + 160,
.bank_width = 32, .bank_width = 32,
.regs = &omap7xx_gpio_regs, .regs = &omap7xx_gpio_regs,
}; };
......
...@@ -56,7 +56,6 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) ...@@ -56,7 +56,6 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
dev_attr = (struct omap_gpio_dev_attr *)oh->dev_attr; dev_attr = (struct omap_gpio_dev_attr *)oh->dev_attr;
pdata->bank_width = dev_attr->bank_width; pdata->bank_width = dev_attr->bank_width;
pdata->dbck_flag = dev_attr->dbck_flag; pdata->dbck_flag = dev_attr->dbck_flag;
pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);
pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL); pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
if (!pdata->regs) { if (!pdata->regs) {
...@@ -103,6 +102,8 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) ...@@ -103,6 +102,8 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
pdata->regs->dataout = OMAP4_GPIO_DATAOUT; pdata->regs->dataout = OMAP4_GPIO_DATAOUT;
pdata->regs->set_dataout = OMAP4_GPIO_SETDATAOUT; pdata->regs->set_dataout = OMAP4_GPIO_SETDATAOUT;
pdata->regs->clr_dataout = OMAP4_GPIO_CLEARDATAOUT; pdata->regs->clr_dataout = OMAP4_GPIO_CLEARDATAOUT;
pdata->regs->irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0;
pdata->regs->irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1;
pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0; pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;
pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1; pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;
pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0; pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0;
......
...@@ -172,6 +172,8 @@ struct omap_gpio_reg_offs { ...@@ -172,6 +172,8 @@ struct omap_gpio_reg_offs {
u16 clr_dataout; u16 clr_dataout;
u16 irqstatus; u16 irqstatus;
u16 irqstatus2; u16 irqstatus2;
u16 irqstatus_raw0;
u16 irqstatus_raw1;
u16 irqenable; u16 irqenable;
u16 irqenable2; u16 irqenable2;
u16 set_irqenable; u16 set_irqenable;
...@@ -193,7 +195,6 @@ struct omap_gpio_reg_offs { ...@@ -193,7 +195,6 @@ struct omap_gpio_reg_offs {
}; };
struct omap_gpio_platform_data { struct omap_gpio_platform_data {
u16 virtual_irq_start;
int bank_type; int bank_type;
int bank_width; /* GPIO bank width */ int bank_width; /* GPIO bank width */
int bank_stride; /* Only needed for omap1 MPUIO */ int bank_stride; /* Only needed for omap1 MPUIO */
......
...@@ -11,6 +11,7 @@ config AVR32 ...@@ -11,6 +11,7 @@ config AVR32
select GENERIC_ATOMIC64 select GENERIC_ATOMIC64
select HARDIRQS_SW_RESEND select HARDIRQS_SW_RESEND
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
help help
......
...@@ -31,6 +31,7 @@ config BLACKFIN ...@@ -31,6 +31,7 @@ config BLACKFIN
select HAVE_KERNEL_LZO if RAMKERNEL select HAVE_KERNEL_LZO if RAMKERNEL
select HAVE_OPROFILE select HAVE_OPROFILE
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_WANT_OPTIONAL_GPIOLIB select ARCH_WANT_OPTIONAL_GPIOLIB
select HAVE_GENERIC_HARDIRQS select HAVE_GENERIC_HARDIRQS
select GENERIC_ATOMIC64 select GENERIC_ATOMIC64
......
/* #ifndef __LINUX_GPIO_H
* Generic GPIO API implementation for IA-64. #warning Include linux/gpio.h instead of asm/gpio.h
* #include <linux/gpio.h>
* A stright copy of that for PowerPC which was: #endif
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* 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.
*/
#ifndef _ASM_IA64_GPIO_H
#define _ASM_IA64_GPIO_H
#include <linux/errno.h>
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
/*
* We don't (yet) implement inlined/rapid versions for on-chip gpios.
* Just call gpiolib.
*/
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* _ASM_IA64_GPIO_H */
...@@ -24,6 +24,7 @@ config COLDFIRE ...@@ -24,6 +24,7 @@ config COLDFIRE
bool "Coldfire CPU family support" bool "Coldfire CPU family support"
select GENERIC_GPIO select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select ARCH_HAVE_CUSTOM_GPIO_H
select CPU_HAS_NO_BITFIELDS select CPU_HAS_NO_BITFIELDS
select CPU_HAS_NO_MULDIV64 select CPU_HAS_NO_MULDIV64
select GENERIC_CSUM select GENERIC_CSUM
......
/* #ifndef __LINUX_GPIO_H
* Generic GPIO API implementation for PowerPC. #warning Include linux/gpio.h instead of asm/gpio.h
* #include <linux/gpio.h>
* Copyright (c) 2007-2008 MontaVista Software, Inc. #endif
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* 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.
*/
#ifndef _ASM_MICROBLAZE_GPIO_H
#define _ASM_MICROBLAZE_GPIO_H
#include <linux/errno.h>
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
/*
* We don't (yet) implement inlined/rapid versions for on-chip gpios.
* Just call gpiolib.
*/
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* _ASM_MICROBLAZE_GPIO_H */
...@@ -8,6 +8,7 @@ config MIPS ...@@ -8,6 +8,7 @@ config MIPS
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC select PERF_USE_VMALLOC
select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB
select ARCH_HAVE_CUSTOM_GPIO_H
select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
......
/* #ifndef __LINUX_GPIO_H
* OpenRISC Linux #warning Include linux/gpio.h instead of asm/gpio.h
* #include <linux/gpio.h>
* Linux architectural port borrowing liberally from similar works of #endif
* others. All original copyrights apply as per the original source
* declaration.
*
* OpenRISC implementation:
* Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
* Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
* et al.
*
* 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.
*/
#ifndef __ASM_OPENRISC_GPIO_H
#define __ASM_OPENRISC_GPIO_H
#include <linux/errno.h>
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
/*
* OpenRISC (or1k) does not have on-chip GPIO's so there is not really
* any standardized implementation that makes sense here. If passing
* through gpiolib becomes a bottleneck then it may make sense, on a
* case-by-case basis, to implement these inlined/rapid versions.
*
* Just call gpiolib.
*/
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
/*
* Not implemented, yet.
*/
static inline int gpio_to_irq(unsigned int gpio)
{
return -ENOSYS;
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* __ASM_OPENRISC_GPIO_H */
/* #ifndef __LINUX_GPIO_H
* Generic GPIO API implementation for PowerPC. #warning Include linux/gpio.h instead of asm/gpio.h
* #include <linux/gpio.h>
* Copyright (c) 2007-2008 MontaVista Software, Inc. #endif
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* 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.
*/
#ifndef __ASM_POWERPC_GPIO_H
#define __ASM_POWERPC_GPIO_H
#include <linux/errno.h>
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
/*
* We don't (yet) implement inlined/rapid versions for on-chip gpios.
* Just call gpiolib.
*/
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* __ASM_POWERPC_GPIO_H */
...@@ -13,6 +13,7 @@ config SUPERH ...@@ -13,6 +13,7 @@ config SUPERH
select HAVE_DMA_ATTRS select HAVE_DMA_ATTRS
select HAVE_IRQ_WORK select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS select HAVE_PERF_EVENTS
select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A) select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A)
select PERF_USE_VMALLOC select PERF_USE_VMALLOC
select HAVE_KERNEL_GZIP select HAVE_KERNEL_GZIP
......
#ifndef __ASM_SPARC_GPIO_H #ifndef __LINUX_GPIO_H
#define __ASM_SPARC_GPIO_H #warning Include linux/gpio.h instead of asm/gpio.h
#include <linux/gpio.h>
#include <linux/errno.h> #endif
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return -ENOSYS;
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* __ASM_SPARC_GPIO_H */
...@@ -8,6 +8,7 @@ config UNICORE32 ...@@ -8,6 +8,7 @@ config UNICORE32
select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZO select HAVE_KERNEL_LZO
select HAVE_KERNEL_LZMA select HAVE_KERNEL_LZMA
select ARCH_HAVE_CUSTOM_GPIO_H
select GENERIC_FIND_FIRST_BIT select GENERIC_FIND_FIRST_BIT
select GENERIC_IRQ_PROBE select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW
......
/* #ifndef __LINUX_GPIO_H
* Generic GPIO API implementation for x86. #warning Include linux/gpio.h instead of asm/gpio.h
* #include <linux/gpio.h>
* Derived from the generic GPIO API for powerpc: #endif
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* 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.
*/
#ifndef _ASM_X86_GPIO_H
#define _ASM_X86_GPIO_H
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
/*
* Just call gpiolib.
*/
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* _ASM_X86_GPIO_H */
/* #ifndef __LINUX_GPIO_H
* Generic GPIO API implementation for xtensa. #warning Include linux/gpio.h instead of asm/gpio.h
* #include <linux/gpio.h>
* Stolen from x86, which is derived from the generic GPIO API for powerpc: #endif
*
* Copyright (c) 2007-2008 MontaVista Software, Inc.
*
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
* 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.
*/
#ifndef _ASM_XTENSA_GPIO_H
#define _ASM_XTENSA_GPIO_H
#include <asm-generic/gpio.h>
#ifdef CONFIG_GPIOLIB
/*
* Just call gpiolib.
*/
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return __gpio_to_irq(gpio);
}
/*
* Not implemented, yet.
*/
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif /* CONFIG_GPIOLIB */
#endif /* _ASM_XTENSA_GPIO_H */
...@@ -2,6 +2,14 @@ ...@@ -2,6 +2,14 @@
# GPIO infrastructure and drivers # GPIO infrastructure and drivers
# #
config ARCH_HAVE_CUSTOM_GPIO_H
bool
help
Selecting this config option from the architecture Kconfig allows
the architecture to provide a custom asm/gpio.h implementation
overriding the default implementations. New uses of this are
strongly discouraged.
config ARCH_WANT_OPTIONAL_GPIOLIB config ARCH_WANT_OPTIONAL_GPIOLIB
bool bool
help help
...@@ -37,6 +45,10 @@ menuconfig GPIOLIB ...@@ -37,6 +45,10 @@ menuconfig GPIOLIB
if GPIOLIB if GPIOLIB
config OF_GPIO
def_bool y
depends on OF && !SPARC
config DEBUG_GPIO config DEBUG_GPIO
bool "Debug GPIO calls" bool "Debug GPIO calls"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
...@@ -249,7 +261,7 @@ config GPIO_MC9S08DZ60 ...@@ -249,7 +261,7 @@ config GPIO_MC9S08DZ60
Select this to enable the MC9S08DZ60 GPIO driver Select this to enable the MC9S08DZ60 GPIO driver
config GPIO_PCA953X config GPIO_PCA953X
tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports" tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports"
depends on I2C depends on I2C
help help
Say yes here to provide access to several register-oriented Say yes here to provide access to several register-oriented
...@@ -258,10 +270,11 @@ config GPIO_PCA953X ...@@ -258,10 +270,11 @@ config GPIO_PCA953X
4 bits: pca9536, pca9537 4 bits: pca9536, pca9537
8 bits: max7310, pca9534, pca9538, pca9554, pca9557, 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
tca6408 pca9556, pca9557, pca9574, tca6408
16 bits: pca9535, pca9539, pca9555, tca6416 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
tca6416
config GPIO_PCA953X_IRQ config GPIO_PCA953X_IRQ
bool "Interrupt controller support for PCA953x" bool "Interrupt controller support for PCA953x"
...@@ -294,6 +307,15 @@ config GPIO_PCF857X ...@@ -294,6 +307,15 @@ config GPIO_PCF857X
This driver provides an in-kernel interface to those GPIOs using This driver provides an in-kernel interface to those GPIOs using
platform-neutral GPIO calls. platform-neutral GPIO calls.
config GPIO_RC5T583
bool "RICOH RC5T583 GPIO"
depends on MFD_RC5T583
help
Select this option to enable GPIO driver for the Ricoh RC5T583
chip family.
This driver provides the support for driving/reading the gpio pins
of RC5T583 device through standard gpio library.
config GPIO_SX150X config GPIO_SX150X
bool "Semtech SX150x I2C GPIO expander" bool "Semtech SX150x I2C GPIO expander"
depends on I2C=y depends on I2C=y
...@@ -405,6 +427,7 @@ config GPIO_BT8XX ...@@ -405,6 +427,7 @@ config GPIO_BT8XX
config GPIO_LANGWELL config GPIO_LANGWELL
bool "Intel Langwell/Penwell GPIO support" bool "Intel Langwell/Penwell GPIO support"
depends on PCI && X86 depends on PCI && X86
select IRQ_DOMAIN
help help
Say Y here to support Intel Langwell/Penwell GPIO. Say Y here to support Intel Langwell/Penwell GPIO.
...@@ -520,4 +543,12 @@ config GPIO_TPS65910 ...@@ -520,4 +543,12 @@ config GPIO_TPS65910
help help
Select this option to enable GPIO driver for the TPS65910 Select this option to enable GPIO driver for the TPS65910
chip family. chip family.
config GPIO_MSIC
bool "Intel MSIC mixed signal gpio support"
depends on MFD_INTEL_MSIC
help
Enable support for GPIO on intel MSIC controllers found in
intel MID devices
endif endif
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
# Device drivers. Generally keep list sorted alphabetically # Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
...@@ -33,6 +34,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o ...@@ -33,6 +34,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o
obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
...@@ -43,6 +45,7 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o ...@@ -43,6 +45,7 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
......
...@@ -70,6 +70,35 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) ...@@ -70,6 +70,35 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
} }
EXPORT_SYMBOL(devm_gpio_request); EXPORT_SYMBOL(devm_gpio_request);
/**
* devm_gpio_request_one - request a single GPIO with initial setup
* @dev: device to request for
* @gpio: the GPIO number
* @flags: GPIO configuration as specified by GPIOF_*
* @label: a literal description string of this GPIO
*/
int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label)
{
unsigned *dr;
int rc;
dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL);
if (!dr)
return -ENOMEM;
rc = gpio_request_one(gpio, flags, label);
if (rc) {
devres_free(dr);
return rc;
}
*dr = gpio;
devres_add(dev, dr);
return 0;
}
/** /**
* devm_gpio_free - free an interrupt * devm_gpio_free - free an interrupt
* @dev: device to free gpio for * @dev: device to free gpio for
......
...@@ -328,17 +328,7 @@ static struct pci_driver bt8xxgpio_pci_driver = { ...@@ -328,17 +328,7 @@ static struct pci_driver bt8xxgpio_pci_driver = {
.resume = bt8xxgpio_resume, .resume = bt8xxgpio_resume,
}; };
static int __init bt8xxgpio_init(void) module_pci_driver(bt8xxgpio_pci_driver);
{
return pci_register_driver(&bt8xxgpio_pci_driver);
}
module_init(bt8xxgpio_init)
static void __exit bt8xxgpio_exit(void)
{
pci_unregister_driver(&bt8xxgpio_pci_driver);
}
module_exit(bt8xxgpio_exit)
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Buesch"); MODULE_AUTHOR("Michael Buesch");
......
...@@ -325,7 +325,7 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev, ...@@ -325,7 +325,7 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev,
void __iomem *dir = mmio_base + bank->dir; void __iomem *dir = mmio_base + bank->dir;
int err; int err;
err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, false); err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, 0);
if (err) if (err)
return err; return err;
......
...@@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(bgpio_remove); ...@@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(bgpio_remove);
int bgpio_init(struct bgpio_chip *bgc, struct device *dev, int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
unsigned long sz, void __iomem *dat, void __iomem *set, unsigned long sz, void __iomem *dat, void __iomem *set,
void __iomem *clr, void __iomem *dirout, void __iomem *dirin, void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
bool big_endian) unsigned long flags)
{ {
int ret; int ret;
...@@ -385,7 +385,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, ...@@ -385,7 +385,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
if (ret) if (ret)
return ret; return ret;
ret = bgpio_setup_accessors(dev, bgc, big_endian); ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN);
if (ret) if (ret)
return ret; return ret;
...@@ -394,6 +394,11 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, ...@@ -394,6 +394,11 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
return ret; return ret;
bgc->data = bgc->read_reg(bgc->reg_dat); bgc->data = bgc->read_reg(bgc->reg_dat);
if (bgc->gc.set == bgpio_set_set &&
!(flags & BGPIOF_UNREADABLE_REG_SET))
bgc->data = bgc->read_reg(bgc->reg_set);
if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
bgc->dir = bgc->read_reg(bgc->reg_dir);
return ret; return ret;
} }
...@@ -449,7 +454,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) ...@@ -449,7 +454,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
void __iomem *dirout; void __iomem *dirout;
void __iomem *dirin; void __iomem *dirin;
unsigned long sz; unsigned long sz;
bool be; unsigned long flags = 0;
int err; int err;
struct bgpio_chip *bgc; struct bgpio_chip *bgc;
struct bgpio_pdata *pdata = dev_get_platdata(dev); struct bgpio_pdata *pdata = dev_get_platdata(dev);
...@@ -480,13 +485,14 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) ...@@ -480,13 +485,14 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
if (err) if (err)
return err; return err;
be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"); if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"))
flags |= BGPIOF_BIG_ENDIAN;
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
if (!bgc) if (!bgc)
return -ENOMEM; return -ENOMEM;
err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be); err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, flags);
if (err) if (err)
return err; return err;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/irqdomain.h>
/* /*
* Langwell chip has 64 pins and thus there are 2 32bit registers to control * Langwell chip has 64 pins and thus there are 2 32bit registers to control
...@@ -66,8 +67,8 @@ struct lnw_gpio { ...@@ -66,8 +67,8 @@ struct lnw_gpio {
struct gpio_chip chip; struct gpio_chip chip;
void *reg_base; void *reg_base;
spinlock_t lock; spinlock_t lock;
unsigned irq_base;
struct pci_dev *pdev; struct pci_dev *pdev;
struct irq_domain *domain;
}; };
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
...@@ -176,13 +177,13 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip, ...@@ -176,13 +177,13 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
return lnw->irq_base + offset; return irq_create_mapping(lnw->domain, offset);
} }
static int lnw_irq_type(struct irq_data *d, unsigned type) static int lnw_irq_type(struct irq_data *d, unsigned type)
{ {
struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
u32 gpio = d->irq - lnw->irq_base; u32 gpio = irqd_to_hwirq(d);
unsigned long flags; unsigned long flags;
u32 value; u32 value;
void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
...@@ -249,20 +250,55 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) ...@@ -249,20 +250,55 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
/* check GPIO controller to check which pin triggered the interrupt */ /* check GPIO controller to check which pin triggered the interrupt */
for (base = 0; base < lnw->chip.ngpio; base += 32) { for (base = 0; base < lnw->chip.ngpio; base += 32) {
gedr = gpio_reg(&lnw->chip, base, GEDR); gedr = gpio_reg(&lnw->chip, base, GEDR);
pending = readl(gedr); while ((pending = readl(gedr))) {
while (pending) {
gpio = __ffs(pending); gpio = __ffs(pending);
mask = BIT(gpio); mask = BIT(gpio);
pending &= ~mask;
/* Clear before handling so we can't lose an edge */ /* Clear before handling so we can't lose an edge */
writel(mask, gedr); writel(mask, gedr);
generic_handle_irq(lnw->irq_base + base + gpio); generic_handle_irq(irq_find_mapping(lnw->domain,
base + gpio));
} }
} }
chip->irq_eoi(data); chip->irq_eoi(data);
} }
static void lnw_irq_init_hw(struct lnw_gpio *lnw)
{
void __iomem *reg;
unsigned base;
for (base = 0; base < lnw->chip.ngpio; base += 32) {
/* Clear the rising-edge detect register */
reg = gpio_reg(&lnw->chip, base, GRER);
writel(0, reg);
/* Clear the falling-edge detect register */
reg = gpio_reg(&lnw->chip, base, GFER);
writel(0, reg);
/* Clear the edge detect status register */
reg = gpio_reg(&lnw->chip, base, GEDR);
writel(~0, reg);
}
}
static int lnw_gpio_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
struct lnw_gpio *lnw = d->host_data;
irq_set_chip_and_handler_name(virq, &lnw_irqchip, handle_simple_irq,
"demux");
irq_set_chip_data(virq, lnw);
irq_set_irq_type(virq, IRQ_TYPE_NONE);
return 0;
}
static const struct irq_domain_ops lnw_gpio_irq_ops = {
.map = lnw_gpio_irq_map,
.xlate = irq_domain_xlate_twocell,
};
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int lnw_gpio_runtime_resume(struct device *dev) static int lnw_gpio_runtime_resume(struct device *dev)
{ {
...@@ -300,23 +336,22 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, ...@@ -300,23 +336,22 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
void *base; void *base;
int i;
resource_size_t start, len; resource_size_t start, len;
struct lnw_gpio *lnw; struct lnw_gpio *lnw;
u32 irq_base;
u32 gpio_base; u32 gpio_base;
int retval = 0; int retval = 0;
int ngpio = id->driver_data;
retval = pci_enable_device(pdev); retval = pci_enable_device(pdev);
if (retval) if (retval)
goto done; return retval;
retval = pci_request_regions(pdev, "langwell_gpio"); retval = pci_request_regions(pdev, "langwell_gpio");
if (retval) { if (retval) {
dev_err(&pdev->dev, "error requesting resources\n"); dev_err(&pdev->dev, "error requesting resources\n");
goto err2; goto err2;
} }
/* get the irq_base from bar1 */ /* get the gpio_base from bar1 */
start = pci_resource_start(pdev, 1); start = pci_resource_start(pdev, 1);
len = pci_resource_len(pdev, 1); len = pci_resource_len(pdev, 1);
base = ioremap_nocache(start, len); base = ioremap_nocache(start, len);
...@@ -324,28 +359,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, ...@@ -324,28 +359,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
dev_err(&pdev->dev, "error mapping bar1\n"); dev_err(&pdev->dev, "error mapping bar1\n");
goto err3; goto err3;
} }
irq_base = *(u32 *)base;
gpio_base = *((u32 *)base + 1); gpio_base = *((u32 *)base + 1);
/* release the IO mapping, since we already get the info from bar1 */ /* release the IO mapping, since we already get the info from bar1 */
iounmap(base); iounmap(base);
/* get the register base from bar0 */ /* get the register base from bar0 */
start = pci_resource_start(pdev, 0); start = pci_resource_start(pdev, 0);
len = pci_resource_len(pdev, 0); len = pci_resource_len(pdev, 0);
base = ioremap_nocache(start, len); base = devm_ioremap_nocache(&pdev->dev, start, len);
if (!base) { if (!base) {
dev_err(&pdev->dev, "error mapping bar0\n"); dev_err(&pdev->dev, "error mapping bar0\n");
retval = -EFAULT; retval = -EFAULT;
goto err3; goto err3;
} }
lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL); lnw = devm_kzalloc(&pdev->dev, sizeof(struct lnw_gpio), GFP_KERNEL);
if (!lnw) { if (!lnw) {
dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n"); dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
retval = -ENOMEM; retval = -ENOMEM;
goto err4; goto err3;
} }
lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
&lnw_gpio_irq_ops, lnw);
if (!lnw->domain)
goto err3;
lnw->reg_base = base; lnw->reg_base = base;
lnw->irq_base = irq_base;
lnw->chip.label = dev_name(&pdev->dev); lnw->chip.label = dev_name(&pdev->dev);
lnw->chip.request = lnw_gpio_request; lnw->chip.request = lnw_gpio_request;
lnw->chip.direction_input = lnw_gpio_direction_input; lnw->chip.direction_input = lnw_gpio_direction_input;
...@@ -354,38 +393,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, ...@@ -354,38 +393,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.set = lnw_gpio_set; lnw->chip.set = lnw_gpio_set;
lnw->chip.to_irq = lnw_gpio_to_irq; lnw->chip.to_irq = lnw_gpio_to_irq;
lnw->chip.base = gpio_base; lnw->chip.base = gpio_base;
lnw->chip.ngpio = id->driver_data; lnw->chip.ngpio = ngpio;
lnw->chip.can_sleep = 0; lnw->chip.can_sleep = 0;
lnw->pdev = pdev; lnw->pdev = pdev;
pci_set_drvdata(pdev, lnw); pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip); retval = gpiochip_add(&lnw->chip);
if (retval) { if (retval) {
dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
goto err5; goto err3;
} }
lnw_irq_init_hw(lnw);
irq_set_handler_data(pdev->irq, lnw); irq_set_handler_data(pdev->irq, lnw);
irq_set_chained_handler(pdev->irq, lnw_irq_handler); irq_set_chained_handler(pdev->irq, lnw_irq_handler);
for (i = 0; i < lnw->chip.ngpio; i++) {
irq_set_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip,
handle_simple_irq, "demux");
irq_set_chip_data(i + lnw->irq_base, lnw);
}
spin_lock_init(&lnw->lock); spin_lock_init(&lnw->lock);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev); pm_runtime_allow(&pdev->dev);
goto done; return 0;
err5:
kfree(lnw);
err4:
iounmap(base);
err3: err3:
pci_release_regions(pdev); pci_release_regions(pdev);
err2: err2:
pci_disable_device(pdev); pci_disable_device(pdev);
done:
return retval; return retval;
} }
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/platform.h> #include <mach/platform.h>
...@@ -454,10 +457,57 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { ...@@ -454,10 +457,57 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
}, },
}; };
/* Empty now, can be removed later when mach-lpc32xx is finally switched over
* to DT support
*/
void __init lpc32xx_gpio_init(void) void __init lpc32xx_gpio_init(void)
{
}
static int lpc32xx_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags)
{
/* Is this the correct bank? */
u32 bank = gpiospec->args[0];
if ((bank > ARRAY_SIZE(lpc32xx_gpiochip) ||
(gc != &lpc32xx_gpiochip[bank].chip)))
return -EINVAL;
if (flags)
*flags = gpiospec->args[2];
return gpiospec->args[1];
}
static int __devinit lpc32xx_gpio_probe(struct platform_device *pdev)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) {
if (pdev->dev.of_node) {
lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate;
lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3;
lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node;
}
gpiochip_add(&lpc32xx_gpiochip[i].chip); gpiochip_add(&lpc32xx_gpiochip[i].chip);
}
return 0;
} }
#ifdef CONFIG_OF
static struct of_device_id lpc32xx_gpio_of_match[] __devinitdata = {
{ .compatible = "nxp,lpc3220-gpio", },
{ },
};
#endif
static struct platform_driver lpc32xx_gpio_driver = {
.driver = {
.name = "lpc32xx-gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(lpc32xx_gpio_of_match),
},
.probe = lpc32xx_gpio_probe,
};
module_platform_driver(lpc32xx_gpio_driver);
...@@ -353,7 +353,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) ...@@ -353,7 +353,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
chip->base + t, bank, t, label, chip->base + t, bank, t, label,
(mcp->cache[MCP_IODIR] & mask) ? "in " : "out", (mcp->cache[MCP_IODIR] & mask) ? "in " : "out",
(mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
(mcp->cache[MCP_GPPU] & mask) ? " " : "up"); (mcp->cache[MCP_GPPU] & mask) ? "up" : " ");
/* NOTE: ignoring the irq-related registers */ /* NOTE: ignoring the irq-related registers */
seq_printf(s, "\n"); seq_printf(s, "\n");
} }
......
...@@ -611,17 +611,7 @@ static struct pci_driver ioh_gpio_driver = { ...@@ -611,17 +611,7 @@ static struct pci_driver ioh_gpio_driver = {
.resume = ioh_gpio_resume .resume = ioh_gpio_resume
}; };
static int __init ioh_gpio_pci_init(void) module_pci_driver(ioh_gpio_driver);
{
return pci_register_driver(&ioh_gpio_driver);
}
module_init(ioh_gpio_pci_init);
static void __exit ioh_gpio_pci_exit(void)
{
pci_unregister_driver(&ioh_gpio_driver);
}
module_exit(ioh_gpio_pci_exit);
MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver"); MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -163,7 +163,8 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) ...@@ -163,7 +163,8 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)
if (mask) if (mask)
generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
32 - ffs(mask))); 32 - ffs(mask)));
chip->irq_eoi(&desc->irq_data); if (chip->irq_eoi)
chip->irq_eoi(&desc->irq_data);
} }
static void mpc8xxx_irq_unmask(struct irq_data *d) static void mpc8xxx_irq_unmask(struct irq_data *d)
......
/*
* Intel Medfield MSIC GPIO driver>
* Copyright (c) 2011, Intel Corporation.
*
* Author: Mathias Nyman <mathias.nyman@linux.intel.com>
* Based on intel_pmic_gpio.c
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/mfd/intel_msic.h>
/* the offset for the mapping of global gpio pin to irq */
#define MSIC_GPIO_IRQ_OFFSET 0x100
#define MSIC_GPIO_DIR_IN 0
#define MSIC_GPIO_DIR_OUT BIT(5)
#define MSIC_GPIO_TRIG_FALL BIT(1)
#define MSIC_GPIO_TRIG_RISE BIT(2)
/* masks for msic gpio output GPIOxxxxCTLO registers */
#define MSIC_GPIO_DIR_MASK BIT(5)
#define MSIC_GPIO_DRV_MASK BIT(4)
#define MSIC_GPIO_REN_MASK BIT(3)
#define MSIC_GPIO_RVAL_MASK (BIT(2) | BIT(1))
#define MSIC_GPIO_DOUT_MASK BIT(0)
/* masks for msic gpio input GPIOxxxxCTLI registers */
#define MSIC_GPIO_GLBYP_MASK BIT(5)
#define MSIC_GPIO_DBNC_MASK (BIT(4) | BIT(3))
#define MSIC_GPIO_INTCNT_MASK (BIT(2) | BIT(1))
#define MSIC_GPIO_DIN_MASK BIT(0)
#define MSIC_NUM_GPIO 24
struct msic_gpio {
struct platform_device *pdev;
struct mutex buslock;
struct gpio_chip chip;
int irq;
unsigned irq_base;
unsigned long trig_change_mask;
unsigned trig_type;
};
/*
* MSIC has 24 gpios, 16 low voltage (1.2-1.8v) and 8 high voltage (3v).
* Both the high and low voltage gpios are divided in two banks.
* GPIOs are numbered with GPIO0LV0 as gpio_base in the following order:
* GPIO0LV0..GPIO0LV7: low voltage, bank 0, gpio_base
* GPIO1LV0..GPIO1LV7: low voltage, bank 1, gpio_base + 8
* GPIO0HV0..GPIO0HV3: high voltage, bank 0, gpio_base + 16
* GPIO1HV0..GPIO1HV3: high voltage, bank 1, gpio_base + 20
*/
static int msic_gpio_to_ireg(unsigned offset)
{
if (offset >= MSIC_NUM_GPIO)
return -EINVAL;
if (offset < 8)
return INTEL_MSIC_GPIO0LV0CTLI - offset;
if (offset < 16)
return INTEL_MSIC_GPIO1LV0CTLI - offset + 8;
if (offset < 20)
return INTEL_MSIC_GPIO0HV0CTLI - offset + 16;
return INTEL_MSIC_GPIO1HV0CTLI - offset + 20;
}
static int msic_gpio_to_oreg(unsigned offset)
{
if (offset >= MSIC_NUM_GPIO)
return -EINVAL;
if (offset < 8)
return INTEL_MSIC_GPIO0LV0CTLO - offset;
if (offset < 16)
return INTEL_MSIC_GPIO1LV0CTLO - offset + 8;
if (offset < 20)
return INTEL_MSIC_GPIO0HV0CTLO - offset + 16;
return INTEL_MSIC_GPIO1HV0CTLO + offset + 20;
}
static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
int reg;
reg = msic_gpio_to_oreg(offset);
if (reg < 0)
return reg;
return intel_msic_reg_update(reg, MSIC_GPIO_DIR_IN, MSIC_GPIO_DIR_MASK);
}
static int msic_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
int reg;
unsigned mask;
value = (!!value) | MSIC_GPIO_DIR_OUT;
mask = MSIC_GPIO_DIR_MASK | MSIC_GPIO_DOUT_MASK;
reg = msic_gpio_to_oreg(offset);
if (reg < 0)
return reg;
return intel_msic_reg_update(reg, value, mask);
}
static int msic_gpio_get(struct gpio_chip *chip, unsigned offset)
{
u8 r;
int ret;
int reg;
reg = msic_gpio_to_ireg(offset);
if (reg < 0)
return reg;
ret = intel_msic_reg_read(reg, &r);
if (ret < 0)
return ret;
return r & MSIC_GPIO_DIN_MASK;
}
static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
int reg;
reg = msic_gpio_to_oreg(offset);
if (reg < 0)
return;
intel_msic_reg_update(reg, !!value , MSIC_GPIO_DOUT_MASK);
}
/*
* This is called from genirq with mg->buslock locked and
* irq_desc->lock held. We can not access the scu bus here, so we
* store the change and update in the bus_sync_unlock() function below
*/
static int msic_irq_type(struct irq_data *data, unsigned type)
{
struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
u32 gpio = data->irq - mg->irq_base;
if (gpio >= mg->chip.ngpio)
return -EINVAL;
/* mark for which gpio the trigger changed, protected by buslock */
mg->trig_change_mask |= (1 << gpio);
mg->trig_type = type;
return 0;
}
static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct msic_gpio *mg = container_of(chip, struct msic_gpio, chip);
return mg->irq_base + offset;
}
static void msic_bus_lock(struct irq_data *data)
{
struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
mutex_lock(&mg->buslock);
}
static void msic_bus_sync_unlock(struct irq_data *data)
{
struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
int offset;
int reg;
u8 trig = 0;
/* We can only get one change at a time as the buslock covers the
entire transaction. The irq_desc->lock is dropped before we are
called but that is fine */
if (mg->trig_change_mask) {
offset = __ffs(mg->trig_change_mask);
reg = msic_gpio_to_ireg(offset);
if (reg < 0)
goto out;
if (mg->trig_type & IRQ_TYPE_EDGE_RISING)
trig |= MSIC_GPIO_TRIG_RISE;
if (mg->trig_type & IRQ_TYPE_EDGE_FALLING)
trig |= MSIC_GPIO_TRIG_FALL;
intel_msic_reg_update(reg, trig, MSIC_GPIO_INTCNT_MASK);
mg->trig_change_mask = 0;
}
out:
mutex_unlock(&mg->buslock);
}
/* Firmware does all the masking and unmasking for us, no masking here. */
static void msic_irq_unmask(struct irq_data *data) { }
static void msic_irq_mask(struct irq_data *data) { }
static struct irq_chip msic_irqchip = {
.name = "MSIC-GPIO",
.irq_mask = msic_irq_mask,
.irq_unmask = msic_irq_unmask,
.irq_set_type = msic_irq_type,
.irq_bus_lock = msic_bus_lock,
.irq_bus_sync_unlock = msic_bus_sync_unlock,
};
static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
struct irq_data *data = irq_desc_get_irq_data(desc);
struct msic_gpio *mg = irq_data_get_irq_handler_data(data);
struct irq_chip *chip = irq_data_get_irq_chip(data);
struct intel_msic *msic = pdev_to_intel_msic(mg->pdev);
int i;
int bitnr;
u8 pin;
unsigned long pending = 0;
for (i = 0; i < (mg->chip.ngpio / BITS_PER_BYTE); i++) {
intel_msic_irq_read(msic, INTEL_MSIC_GPIO0LVIRQ + i, &pin);
pending = pin;
if (pending) {
for_each_set_bit(bitnr, &pending, BITS_PER_BYTE)
generic_handle_irq(mg->irq_base +
(i * BITS_PER_BYTE) + bitnr);
}
}
chip->irq_eoi(data);
}
static int __devinit platform_msic_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct intel_msic_gpio_pdata *pdata = dev->platform_data;
struct msic_gpio *mg;
int irq = platform_get_irq(pdev, 0);
int retval;
int i;
if (irq < 0) {
dev_err(dev, "no IRQ line\n");
return -EINVAL;
}
if (!pdata || !pdata->gpio_base) {
dev_err(dev, "incorrect or missing platform data\n");
return -EINVAL;
}
mg = kzalloc(sizeof(*mg), GFP_KERNEL);
if (!mg)
return -ENOMEM;
dev_set_drvdata(dev, mg);
mg->pdev = pdev;
mg->irq = irq;
mg->irq_base = pdata->gpio_base + MSIC_GPIO_IRQ_OFFSET;
mg->chip.label = "msic_gpio";
mg->chip.direction_input = msic_gpio_direction_input;
mg->chip.direction_output = msic_gpio_direction_output;
mg->chip.get = msic_gpio_get;
mg->chip.set = msic_gpio_set;
mg->chip.to_irq = msic_gpio_to_irq;
mg->chip.base = pdata->gpio_base;
mg->chip.ngpio = MSIC_NUM_GPIO;
mg->chip.can_sleep = 1;
mg->chip.dev = dev;
mutex_init(&mg->buslock);
retval = gpiochip_add(&mg->chip);
if (retval) {
dev_err(dev, "Adding MSIC gpio chip failed\n");
goto err;
}
for (i = 0; i < mg->chip.ngpio; i++) {
irq_set_chip_data(i + mg->irq_base, mg);
irq_set_chip_and_handler_name(i + mg->irq_base,
&msic_irqchip,
handle_simple_irq,
"demux");
}
irq_set_chained_handler(mg->irq, msic_gpio_irq_handler);
irq_set_handler_data(mg->irq, mg);
return 0;
err:
kfree(mg);
return retval;
}
static struct platform_driver platform_msic_gpio_driver = {
.driver = {
.name = "msic_gpio",
.owner = THIS_MODULE,
},
.probe = platform_msic_gpio_probe,
};
static int __init platform_msic_gpio_init(void)
{
return platform_driver_register(&platform_msic_gpio_driver);
}
subsys_initcall(platform_msic_gpio_init);
MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>");
MODULE_DESCRIPTION("Intel Medfield MSIC GPIO driver");
MODULE_LICENSE("GPL v2");
...@@ -417,7 +417,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) ...@@ -417,7 +417,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev)
err = bgpio_init(&port->bgc, &pdev->dev, 4, err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + GPIO_PSR, port->base + GPIO_PSR,
port->base + GPIO_DR, NULL, port->base + GPIO_DR, NULL,
port->base + GPIO_GDIR, NULL, false); port->base + GPIO_GDIR, NULL, 0);
if (err) if (err)
goto out_iounmap; goto out_iounmap;
......
...@@ -244,7 +244,7 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) ...@@ -244,7 +244,7 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
err = bgpio_init(&port->bgc, &pdev->dev, 4, err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + PINCTRL_DIN(port->id), port->base + PINCTRL_DIN(port->id),
port->base + PINCTRL_DOUT(port->id), NULL, port->base + PINCTRL_DOUT(port->id), NULL,
port->base + PINCTRL_DOE(port->id), NULL, false); port->base + PINCTRL_DOE(port->id), NULL, 0);
if (err) if (err)
goto out_iounmap; goto out_iounmap;
......
...@@ -57,14 +57,10 @@ struct gpio_bank { ...@@ -57,14 +57,10 @@ struct gpio_bank {
u16 irq; u16 irq;
int irq_base; int irq_base;
struct irq_domain *domain; struct irq_domain *domain;
u32 suspend_wakeup;
u32 saved_wakeup;
u32 non_wakeup_gpios; u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios; u32 enabled_non_wakeup_gpios;
struct gpio_regs context; struct gpio_regs context;
u32 saved_datain; u32 saved_datain;
u32 saved_fallingdetect;
u32 saved_risingdetect;
u32 level_mask; u32 level_mask;
u32 toggle_mask; u32 toggle_mask;
spinlock_t lock; spinlock_t lock;
...@@ -516,11 +512,11 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) ...@@ -516,11 +512,11 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
if (enable) if (enable)
bank->suspend_wakeup |= gpio_bit; bank->context.wake_en |= gpio_bit;
else else
bank->suspend_wakeup &= ~gpio_bit; bank->context.wake_en &= ~gpio_bit;
__raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en); __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en);
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
return 0; return 0;
...@@ -640,7 +636,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -640,7 +636,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
u32 isr; u32 isr;
unsigned int gpio_irq, gpio_index; unsigned int gpio_irq, gpio_index;
struct gpio_bank *bank; struct gpio_bank *bank;
u32 retrigger = 0;
int unmasked = 0; int unmasked = 0;
struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_chip *chip = irq_desc_get_chip(desc);
...@@ -677,8 +672,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -677,8 +672,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);
} }
isr |= retrigger;
retrigger = 0;
if (!isr) if (!isr)
break; break;
...@@ -789,8 +782,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev) ...@@ -789,8 +782,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
bank->saved_wakeup = __raw_readl(mask_reg); __raw_writel(0xffff & ~bank->context.wake_en, mask_reg);
__raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg);
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
return 0; return 0;
...@@ -805,7 +797,7 @@ static int omap_mpuio_resume_noirq(struct device *dev) ...@@ -805,7 +797,7 @@ static int omap_mpuio_resume_noirq(struct device *dev)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
__raw_writel(bank->saved_wakeup, mask_reg); __raw_writel(bank->context.wake_en, mask_reg);
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
return 0; return 0;
...@@ -1152,54 +1144,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) ...@@ -1152,54 +1144,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_ARCH_OMAP2PLUS #ifdef CONFIG_ARCH_OMAP2PLUS
#if defined(CONFIG_PM_SLEEP)
static int omap_gpio_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *base = bank->base;
void __iomem *wakeup_enable;
unsigned long flags;
if (!bank->mod_usage || !bank->loses_context)
return 0;
if (!bank->regs->wkup_en || !bank->suspend_wakeup)
return 0;
wakeup_enable = bank->base + bank->regs->wkup_en;
spin_lock_irqsave(&bank->lock, flags);
bank->saved_wakeup = __raw_readl(wakeup_enable);
_gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
_gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
static int omap_gpio_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
void __iomem *base = bank->base;
unsigned long flags;
if (!bank->mod_usage || !bank->loses_context)
return 0;
if (!bank->regs->wkup_en || !bank->saved_wakeup)
return 0;
spin_lock_irqsave(&bank->lock, flags);
_gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
_gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
#if defined(CONFIG_PM_RUNTIME) #if defined(CONFIG_PM_RUNTIME)
static void omap_gpio_restore_context(struct gpio_bank *bank); static void omap_gpio_restore_context(struct gpio_bank *bank);
...@@ -1233,6 +1177,9 @@ static int omap_gpio_runtime_suspend(struct device *dev) ...@@ -1233,6 +1177,9 @@ static int omap_gpio_runtime_suspend(struct device *dev)
__raw_writel(wake_hi | bank->context.risingdetect, __raw_writel(wake_hi | bank->context.risingdetect,
bank->base + bank->regs->risingdetect); bank->base + bank->regs->risingdetect);
if (!bank->enabled_non_wakeup_gpios)
goto update_gpio_context_count;
if (bank->power_mode != OFF_MODE) { if (bank->power_mode != OFF_MODE) {
bank->power_mode = 0; bank->power_mode = 0;
goto update_gpio_context_count; goto update_gpio_context_count;
...@@ -1244,11 +1191,9 @@ static int omap_gpio_runtime_suspend(struct device *dev) ...@@ -1244,11 +1191,9 @@ static int omap_gpio_runtime_suspend(struct device *dev)
*/ */
bank->saved_datain = __raw_readl(bank->base + bank->saved_datain = __raw_readl(bank->base +
bank->regs->datain); bank->regs->datain);
l1 = __raw_readl(bank->base + bank->regs->fallingdetect); l1 = bank->context.fallingdetect;
l2 = __raw_readl(bank->base + bank->regs->risingdetect); l2 = bank->context.risingdetect;
bank->saved_fallingdetect = l1;
bank->saved_risingdetect = l2;
l1 &= ~bank->enabled_non_wakeup_gpios; l1 &= ~bank->enabled_non_wakeup_gpios;
l2 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios;
...@@ -1290,16 +1235,10 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1290,16 +1235,10 @@ static int omap_gpio_runtime_resume(struct device *dev)
__raw_writel(bank->context.risingdetect, __raw_writel(bank->context.risingdetect,
bank->base + bank->regs->risingdetect); bank->base + bank->regs->risingdetect);
if (!bank->workaround_enabled) {
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
if (bank->get_context_loss_count) { if (bank->get_context_loss_count) {
context_lost_cnt_after = context_lost_cnt_after =
bank->get_context_loss_count(bank->dev); bank->get_context_loss_count(bank->dev);
if (context_lost_cnt_after != bank->context_loss_count || if (context_lost_cnt_after != bank->context_loss_count) {
!context_lost_cnt_after) {
omap_gpio_restore_context(bank); omap_gpio_restore_context(bank);
} else { } else {
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
...@@ -1307,9 +1246,14 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1307,9 +1246,14 @@ static int omap_gpio_runtime_resume(struct device *dev)
} }
} }
__raw_writel(bank->saved_fallingdetect, if (!bank->workaround_enabled) {
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
__raw_writel(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect); bank->base + bank->regs->fallingdetect);
__raw_writel(bank->saved_risingdetect, __raw_writel(bank->context.risingdetect,
bank->base + bank->regs->risingdetect); bank->base + bank->regs->risingdetect);
l = __raw_readl(bank->base + bank->regs->datain); l = __raw_readl(bank->base + bank->regs->datain);
...@@ -1326,14 +1270,15 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1326,14 +1270,15 @@ static int omap_gpio_runtime_resume(struct device *dev)
* No need to generate IRQs for the rising edge for gpio IRQs * No need to generate IRQs for the rising edge for gpio IRQs
* configured with falling edge only; and vice versa. * configured with falling edge only; and vice versa.
*/ */
gen0 = l & bank->saved_fallingdetect; gen0 = l & bank->context.fallingdetect;
gen0 &= bank->saved_datain; gen0 &= bank->saved_datain;
gen1 = l & bank->saved_risingdetect; gen1 = l & bank->context.risingdetect;
gen1 &= ~(bank->saved_datain); gen1 &= ~(bank->saved_datain);
/* FIXME: Consider GPIO IRQs with level detections properly! */ /* FIXME: Consider GPIO IRQs with level detections properly! */
gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect)); gen = l & (~(bank->context.fallingdetect) &
~(bank->context.risingdetect));
/* Consider all GPIO IRQs needed to be updated */ /* Consider all GPIO IRQs needed to be updated */
gen |= gen0 | gen1; gen |= gen0 | gen1;
...@@ -1343,14 +1288,14 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1343,14 +1288,14 @@ static int omap_gpio_runtime_resume(struct device *dev)
old0 = __raw_readl(bank->base + bank->regs->leveldetect0); old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
old1 = __raw_readl(bank->base + bank->regs->leveldetect1); old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
if (cpu_is_omap24xx() || cpu_is_omap34xx()) { if (!bank->regs->irqstatus_raw0) {
__raw_writel(old0 | gen, bank->base + __raw_writel(old0 | gen, bank->base +
bank->regs->leveldetect0); bank->regs->leveldetect0);
__raw_writel(old1 | gen, bank->base + __raw_writel(old1 | gen, bank->base +
bank->regs->leveldetect1); bank->regs->leveldetect1);
} }
if (cpu_is_omap44xx()) { if (bank->regs->irqstatus_raw0) {
__raw_writel(old0 | l, bank->base + __raw_writel(old0 | l, bank->base +
bank->regs->leveldetect0); bank->regs->leveldetect0);
__raw_writel(old1 | l, bank->base + __raw_writel(old1 | l, bank->base +
...@@ -1429,14 +1374,11 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) ...@@ -1429,14 +1374,11 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
} }
#endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM_RUNTIME */
#else #else
#define omap_gpio_suspend NULL
#define omap_gpio_resume NULL
#define omap_gpio_runtime_suspend NULL #define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL #define omap_gpio_runtime_resume NULL
#endif #endif
static const struct dev_pm_ops gpio_pm_ops = { static const struct dev_pm_ops gpio_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
NULL) NULL)
}; };
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#define PCA953X_INVERT 2 #define PCA953X_INVERT 2
#define PCA953X_DIRECTION 3 #define PCA953X_DIRECTION 3
#define REG_ADDR_AI 0x80
#define PCA957X_IN 0 #define PCA957X_IN 0
#define PCA957X_INVRT 1 #define PCA957X_INVRT 1
#define PCA957X_BKEN 2 #define PCA957X_BKEN 2
...@@ -63,15 +65,15 @@ static const struct i2c_device_id pca953x_id[] = { ...@@ -63,15 +65,15 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca6107", 8 | PCA953X_TYPE | PCA_INT, }, { "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
/* NYET: { "tca6424", 24, }, */ { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, pca953x_id); MODULE_DEVICE_TABLE(i2c, pca953x_id);
struct pca953x_chip { struct pca953x_chip {
unsigned gpio_start; unsigned gpio_start;
uint16_t reg_output; u32 reg_output;
uint16_t reg_direction; u32 reg_direction;
struct mutex i2c_lock; struct mutex i2c_lock;
#ifdef CONFIG_GPIO_PCA953X_IRQ #ifdef CONFIG_GPIO_PCA953X_IRQ
...@@ -89,12 +91,20 @@ struct pca953x_chip { ...@@ -89,12 +91,20 @@ struct pca953x_chip {
int chip_type; int chip_type;
}; };
static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
{ {
int ret = 0; int ret = 0;
if (chip->gpio_chip.ngpio <= 8) if (chip->gpio_chip.ngpio <= 8)
ret = i2c_smbus_write_byte_data(chip->client, reg, val); ret = i2c_smbus_write_byte_data(chip->client, reg, val);
else if (chip->gpio_chip.ngpio == 24) {
ret = i2c_smbus_write_word_data(chip->client,
(reg << 2) | REG_ADDR_AI,
val & 0xffff);
ret = i2c_smbus_write_byte_data(chip->client,
(reg << 2) + 2,
(val & 0xff0000) >> 16);
}
else { else {
switch (chip->chip_type) { switch (chip->chip_type) {
case PCA953X_TYPE: case PCA953X_TYPE:
...@@ -121,12 +131,17 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) ...@@ -121,12 +131,17 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
return 0; return 0;
} }
static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
{ {
int ret; int ret;
if (chip->gpio_chip.ngpio <= 8) if (chip->gpio_chip.ngpio <= 8)
ret = i2c_smbus_read_byte_data(chip->client, reg); ret = i2c_smbus_read_byte_data(chip->client, reg);
else if (chip->gpio_chip.ngpio == 24) {
ret = i2c_smbus_read_word_data(chip->client, reg << 2);
ret |= (i2c_smbus_read_byte_data(chip->client,
(reg << 2) + 2)<<16);
}
else else
ret = i2c_smbus_read_word_data(chip->client, reg << 1); ret = i2c_smbus_read_word_data(chip->client, reg << 1);
...@@ -135,14 +150,14 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) ...@@ -135,14 +150,14 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val)
return ret; return ret;
} }
*val = (uint16_t)ret; *val = (u32)ret;
return 0; return 0;
} }
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint16_t reg_val; uint reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
...@@ -173,7 +188,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -173,7 +188,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val) unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint16_t reg_val; uint reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
...@@ -223,7 +238,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, ...@@ -223,7 +238,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint16_t reg_val; u32 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
...@@ -253,7 +268,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) ...@@ -253,7 +268,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{ {
struct pca953x_chip *chip; struct pca953x_chip *chip;
uint16_t reg_val; u32 reg_val;
int ret, offset = 0; int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip); chip = container_of(gc, struct pca953x_chip, gpio_chip);
...@@ -386,7 +401,7 @@ static struct irq_chip pca953x_irq_chip = { ...@@ -386,7 +401,7 @@ static struct irq_chip pca953x_irq_chip = {
static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
{ {
uint16_t cur_stat; u32 cur_stat;
uint16_t old_stat; uint16_t old_stat;
uint16_t pending; uint16_t pending;
uint16_t trigger; uint16_t trigger;
...@@ -449,6 +464,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -449,6 +464,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
{ {
struct i2c_client *client = chip->client; struct i2c_client *client = chip->client;
int ret, offset = 0; int ret, offset = 0;
u32 temporary;
if (irq_base != -1 if (irq_base != -1
&& (id->driver_data & PCA_INT)) { && (id->driver_data & PCA_INT)) {
...@@ -462,7 +478,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, ...@@ -462,7 +478,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
offset = PCA957X_IN; offset = PCA957X_IN;
break; break;
} }
ret = pca953x_read_reg(chip, offset, &chip->irq_stat); ret = pca953x_read_reg(chip, offset, &temporary);
chip->irq_stat = temporary;
if (ret) if (ret)
goto out_failed; goto out_failed;
...@@ -603,7 +620,7 @@ static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert) ...@@ -603,7 +620,7 @@ static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert)
static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert) static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert)
{ {
int ret; int ret;
uint16_t val = 0; u32 val = 0;
/* Let every port in proper state, that could save power */ /* Let every port in proper state, that could save power */
pca953x_write_reg(chip, PCA957X_PUPD, 0x0); pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
......
...@@ -538,17 +538,7 @@ static struct pci_driver pch_gpio_driver = { ...@@ -538,17 +538,7 @@ static struct pci_driver pch_gpio_driver = {
.resume = pch_gpio_resume .resume = pch_gpio_resume
}; };
static int __init pch_gpio_pci_init(void) module_pci_driver(pch_gpio_driver);
{
return pci_register_driver(&pch_gpio_driver);
}
module_init(pch_gpio_pci_init);
static void __exit pch_gpio_pci_exit(void)
{
pci_unregister_driver(&pch_gpio_driver);
}
module_exit(pch_gpio_pci_exit);
MODULE_DESCRIPTION("PCH GPIO PCI Driver"); MODULE_DESCRIPTION("PCH GPIO PCI Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*
* GPIO driver for RICOH583 power management chip.
*
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
* Author: Laxman dewangan <ldewangan@nvidia.com>
*
* Based on code
* Copyright (C) 2011 RICOH COMPANY,LTD
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/mfd/rc5t583.h>
struct rc5t583_gpio {
struct gpio_chip gpio_chip;
struct rc5t583 *rc5t583;
};
static inline struct rc5t583_gpio *to_rc5t583_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct rc5t583_gpio, gpio_chip);
}
static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
uint8_t val = 0;
int ret;
ret = rc5t583_read(parent, RC5T583_GPIO_MON_IOIN, &val);
if (ret < 0)
return ret;
return !!(val & BIT(offset));
}
static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
if (val)
rc5t583_set_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
else
rc5t583_clear_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
}
static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
int ret;
ret = rc5t583_clear_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset));
if (ret < 0)
return ret;
/* Set pin to gpio mode */
return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
}
static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset,
int value)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
int ret;
rc5t583_gpio_set(gc, offset, value);
ret = rc5t583_set_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset));
if (ret < 0)
return ret;
/* Set pin to gpio mode */
return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
}
static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
if ((offset >= 0) && (offset < 8))
return rc5t583_gpio->rc5t583->irq_base +
RC5T583_IRQ_GPIO0 + offset;
return -EINVAL;
}
static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
struct device *parent = rc5t583_gpio->rc5t583->dev;
rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
}
static int __devinit rc5t583_gpio_probe(struct platform_device *pdev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
struct rc5t583_gpio *rc5t583_gpio;
rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio),
GFP_KERNEL);
if (!rc5t583_gpio) {
dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed");
return -ENOMEM;
}
rc5t583_gpio->gpio_chip.label = "gpio-rc5t583",
rc5t583_gpio->gpio_chip.owner = THIS_MODULE,
rc5t583_gpio->gpio_chip.free = rc5t583_gpio_free,
rc5t583_gpio->gpio_chip.direction_input = rc5t583_gpio_dir_input,
rc5t583_gpio->gpio_chip.direction_output = rc5t583_gpio_dir_output,
rc5t583_gpio->gpio_chip.set = rc5t583_gpio_set,
rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get,
rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq,
rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO,
rc5t583_gpio->gpio_chip.can_sleep = 1,
rc5t583_gpio->gpio_chip.dev = &pdev->dev;
rc5t583_gpio->gpio_chip.base = -1;
rc5t583_gpio->rc5t583 = rc5t583;
if (pdata && pdata->gpio_base)
rc5t583_gpio->gpio_chip.base = pdata->gpio_base;
platform_set_drvdata(pdev, rc5t583_gpio);
return gpiochip_add(&rc5t583_gpio->gpio_chip);
}
static int __devexit rc5t583_gpio_remove(struct platform_device *pdev)
{
struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev);
return gpiochip_remove(&rc5t583_gpio->gpio_chip);
}
static struct platform_driver rc5t583_gpio_driver = {
.driver = {
.name = "rc5t583-gpio",
.owner = THIS_MODULE,
},
.probe = rc5t583_gpio_probe,
.remove = __devexit_p(rc5t583_gpio_remove),
};
static int __init rc5t583_gpio_init(void)
{
return platform_driver_register(&rc5t583_gpio_driver);
}
subsys_initcall(rc5t583_gpio_init);
static void __exit rc5t583_gpio_exit(void)
{
platform_driver_unregister(&rc5t583_gpio_driver);
}
module_exit(rc5t583_gpio_exit);
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_DESCRIPTION("GPIO interface for RC5T583");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:rc5t583-gpio");
...@@ -2716,14 +2716,224 @@ static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, ...@@ -2716,14 +2716,224 @@ static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
} }
#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */ #endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */
static __init void exynos4_gpiolib_init(void)
{
#ifdef CONFIG_CPU_EXYNOS4210
struct samsung_gpio_chip *chip;
int i, nr_chips;
void __iomem *gpio_base1, *gpio_base2, *gpio_base3;
int group = 0;
void __iomem *gpx_base;
/* gpio part1 */
gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
if (gpio_base1 == NULL) {
pr_err("unable to ioremap for gpio_base1\n");
goto err_ioremap1;
}
chip = exynos4_gpios_1;
nr_chips = ARRAY_SIZE(exynos4_gpios_1);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO1, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
nr_chips, gpio_base1);
/* gpio part2 */
gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
if (gpio_base2 == NULL) {
pr_err("unable to ioremap for gpio_base2\n");
goto err_ioremap2;
}
/* need to set base address for gpx */
chip = &exynos4_gpios_2[16];
gpx_base = gpio_base2 + 0xC00;
for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
chip->base = gpx_base;
chip = exynos4_gpios_2;
nr_chips = ARRAY_SIZE(exynos4_gpios_2);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO2, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
nr_chips, gpio_base2);
/* gpio part3 */
gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
if (gpio_base3 == NULL) {
pr_err("unable to ioremap for gpio_base3\n");
goto err_ioremap3;
}
chip = exynos4_gpios_3;
nr_chips = ARRAY_SIZE(exynos4_gpios_3);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO3, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
nr_chips, gpio_base3);
#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
#endif
return;
err_ioremap3:
iounmap(gpio_base2);
err_ioremap2:
iounmap(gpio_base1);
err_ioremap1:
return;
#endif /* CONFIG_CPU_EXYNOS4210 */
}
static __init void exynos5_gpiolib_init(void)
{
#ifdef CONFIG_SOC_EXYNOS5250
struct samsung_gpio_chip *chip;
int i, nr_chips;
void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
int group = 0;
void __iomem *gpx_base;
/* gpio part1 */
gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
if (gpio_base1 == NULL) {
pr_err("unable to ioremap for gpio_base1\n");
goto err_ioremap1;
}
/* need to set base address for gpx */
chip = &exynos5_gpios_1[20];
gpx_base = gpio_base1 + 0xC00;
for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
chip->base = gpx_base;
chip = exynos5_gpios_1;
nr_chips = ARRAY_SIZE(exynos5_gpios_1);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO1, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
nr_chips, gpio_base1);
/* gpio part2 */
gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
if (gpio_base2 == NULL) {
pr_err("unable to ioremap for gpio_base2\n");
goto err_ioremap2;
}
chip = exynos5_gpios_2;
nr_chips = ARRAY_SIZE(exynos5_gpios_2);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO2, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
nr_chips, gpio_base2);
/* gpio part3 */
gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
if (gpio_base3 == NULL) {
pr_err("unable to ioremap for gpio_base3\n");
goto err_ioremap3;
}
/* need to set base address for gpv */
exynos5_gpios_3[0].base = gpio_base3;
exynos5_gpios_3[1].base = gpio_base3 + 0x20;
exynos5_gpios_3[2].base = gpio_base3 + 0x60;
exynos5_gpios_3[3].base = gpio_base3 + 0x80;
exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
chip = exynos5_gpios_3;
nr_chips = ARRAY_SIZE(exynos5_gpios_3);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO3, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
nr_chips, gpio_base3);
/* gpio part4 */
gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
if (gpio_base4 == NULL) {
pr_err("unable to ioremap for gpio_base4\n");
goto err_ioremap4;
}
chip = exynos5_gpios_4;
nr_chips = ARRAY_SIZE(exynos5_gpios_4);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO4, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
nr_chips, gpio_base4);
return;
err_ioremap4:
iounmap(gpio_base3);
err_ioremap3:
iounmap(gpio_base2);
err_ioremap2:
iounmap(gpio_base1);
err_ioremap1:
return;
#endif /* CONFIG_SOC_EXYNOS5250 */
}
/* TODO: cleanup soc_is_* */ /* TODO: cleanup soc_is_* */
static __init int samsung_gpiolib_init(void) static __init int samsung_gpiolib_init(void)
{ {
struct samsung_gpio_chip *chip; struct samsung_gpio_chip *chip;
int i, nr_chips; int i, nr_chips;
#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250)
void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
#endif
int group = 0; int group = 0;
samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs));
...@@ -2789,202 +2999,15 @@ static __init int samsung_gpiolib_init(void) ...@@ -2789,202 +2999,15 @@ static __init int samsung_gpiolib_init(void)
s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
#endif #endif
} else if (soc_is_exynos4210()) { } else if (soc_is_exynos4210()) {
#ifdef CONFIG_CPU_EXYNOS4210 exynos4_gpiolib_init();
void __iomem *gpx_base;
/* gpio part1 */
gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
if (gpio_base1 == NULL) {
pr_err("unable to ioremap for gpio_base1\n");
goto err_ioremap1;
}
chip = exynos4_gpios_1;
nr_chips = ARRAY_SIZE(exynos4_gpios_1);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO1, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
nr_chips, gpio_base1);
/* gpio part2 */
gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
if (gpio_base2 == NULL) {
pr_err("unable to ioremap for gpio_base2\n");
goto err_ioremap2;
}
/* need to set base address for gpx */
chip = &exynos4_gpios_2[16];
gpx_base = gpio_base2 + 0xC00;
for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
chip->base = gpx_base;
chip = exynos4_gpios_2;
nr_chips = ARRAY_SIZE(exynos4_gpios_2);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO2, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
nr_chips, gpio_base2);
/* gpio part3 */
gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
if (gpio_base3 == NULL) {
pr_err("unable to ioremap for gpio_base3\n");
goto err_ioremap3;
}
chip = exynos4_gpios_3;
nr_chips = ARRAY_SIZE(exynos4_gpios_3);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS4_PA_GPIO3, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
nr_chips, gpio_base3);
#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
#endif
#endif /* CONFIG_CPU_EXYNOS4210 */
} else if (soc_is_exynos5250()) { } else if (soc_is_exynos5250()) {
#ifdef CONFIG_SOC_EXYNOS5250 exynos5_gpiolib_init();
void __iomem *gpx_base;
/* gpio part1 */
gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
if (gpio_base1 == NULL) {
pr_err("unable to ioremap for gpio_base1\n");
goto err_ioremap1;
}
/* need to set base address for gpx */
chip = &exynos5_gpios_1[20];
gpx_base = gpio_base1 + 0xC00;
for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
chip->base = gpx_base;
chip = exynos5_gpios_1;
nr_chips = ARRAY_SIZE(exynos5_gpios_1);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO1, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
nr_chips, gpio_base1);
/* gpio part2 */
gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
if (gpio_base2 == NULL) {
pr_err("unable to ioremap for gpio_base2\n");
goto err_ioremap2;
}
chip = exynos5_gpios_2;
nr_chips = ARRAY_SIZE(exynos5_gpios_2);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO2, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
nr_chips, gpio_base2);
/* gpio part3 */
gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
if (gpio_base3 == NULL) {
pr_err("unable to ioremap for gpio_base3\n");
goto err_ioremap3;
}
/* need to set base address for gpv */
exynos5_gpios_3[0].base = gpio_base3;
exynos5_gpios_3[1].base = gpio_base3 + 0x20;
exynos5_gpios_3[2].base = gpio_base3 + 0x60;
exynos5_gpios_3[3].base = gpio_base3 + 0x80;
exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
chip = exynos5_gpios_3;
nr_chips = ARRAY_SIZE(exynos5_gpios_3);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO3, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
nr_chips, gpio_base3);
/* gpio part4 */
gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
if (gpio_base4 == NULL) {
pr_err("unable to ioremap for gpio_base4\n");
goto err_ioremap4;
}
chip = exynos5_gpios_4;
nr_chips = ARRAY_SIZE(exynos5_gpios_4);
for (i = 0; i < nr_chips; i++, chip++) {
if (!chip->config) {
chip->config = &exynos_gpio_cfg;
chip->group = group++;
}
exynos_gpiolib_attach_ofnode(chip,
EXYNOS5_PA_GPIO4, i * 0x20);
}
samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
nr_chips, gpio_base4);
#endif /* CONFIG_SOC_EXYNOS5250 */
} else { } else {
WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n"); WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
return -ENODEV; return -ENODEV;
} }
return 0; return 0;
#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250)
err_ioremap4:
iounmap(gpio_base3);
err_ioremap3:
iounmap(gpio_base2);
err_ioremap2:
iounmap(gpio_base1);
err_ioremap1:
return -ENOMEM;
#endif
} }
core_initcall(samsung_gpiolib_init); core_initcall(samsung_gpiolib_init);
......
...@@ -224,7 +224,7 @@ static int __devinit sdv_gpio_probe(struct pci_dev *pdev, ...@@ -224,7 +224,7 @@ static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
ret = bgpio_init(&sd->bgpio, &pdev->dev, 4, ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR, sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
NULL, sd->gpio_pub_base + GPOER, NULL, false); NULL, sd->gpio_pub_base + GPOER, NULL, 0);
if (ret) if (ret)
goto unmap; goto unmap;
sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS; sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
...@@ -282,17 +282,7 @@ static struct pci_driver sdv_gpio_driver = { ...@@ -282,17 +282,7 @@ static struct pci_driver sdv_gpio_driver = {
.remove = sdv_gpio_remove, .remove = sdv_gpio_remove,
}; };
static int __init sdv_gpio_init(void) module_pci_driver(sdv_gpio_driver);
{
return pci_register_driver(&sdv_gpio_driver);
}
module_init(sdv_gpio_init);
static void __exit sdv_gpio_exit(void)
{
pci_unregister_driver(&sdv_gpio_driver);
}
module_exit(sdv_gpio_exit);
MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>"); MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>");
MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs");
......
...@@ -15,11 +15,39 @@ ...@@ -15,11 +15,39 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
/* Private data structure for of_gpiochip_is_match */
struct gg_data {
enum of_gpio_flags *flags;
struct of_phandle_args gpiospec;
int out_gpio;
};
/* Private function for resolving node pointer to gpio_chip */
static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
{
struct gg_data *gg_data = data;
int ret;
if ((gc->of_node != gg_data->gpiospec.np) ||
(gc->of_gpio_n_cells != gg_data->gpiospec.args_count) ||
(!gc->of_xlate))
return false;
ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
if (ret < 0)
return false;
gg_data->out_gpio = ret + gc->base;
return true;
}
/** /**
* of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API
* @np: device node to get GPIO from * @np: device node to get GPIO from
...@@ -34,46 +62,25 @@ ...@@ -34,46 +62,25 @@
int of_get_named_gpio_flags(struct device_node *np, const char *propname, int of_get_named_gpio_flags(struct device_node *np, const char *propname,
int index, enum of_gpio_flags *flags) int index, enum of_gpio_flags *flags)
{ {
struct gg_data gg_data = { .flags = flags, .out_gpio = -ENODEV };
int ret; int ret;
struct gpio_chip *gc;
struct of_phandle_args gpiospec; /* .of_xlate might decide to not fill in the flags, so clear it. */
if (flags)
*flags = 0;
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
&gpiospec); &gg_data.gpiospec);
if (ret) { if (ret) {
pr_debug("%s: can't parse gpios property\n", __func__); pr_debug("%s: can't parse gpios property\n", __func__);
goto err0; return -EINVAL;
}
gc = of_node_to_gpiochip(gpiospec.np);
if (!gc) {
pr_debug("%s: gpio controller %s isn't registered\n",
np->full_name, gpiospec.np->full_name);
ret = -ENODEV;
goto err1;
}
if (gpiospec.args_count != gc->of_gpio_n_cells) {
pr_debug("%s: wrong #gpio-cells for %s\n",
np->full_name, gpiospec.np->full_name);
ret = -EINVAL;
goto err1;
} }
/* .xlate might decide to not fill in the flags, so clear it. */ gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
if (flags)
*flags = 0;
ret = gc->of_xlate(gc, &gpiospec, flags);
if (ret < 0)
goto err1;
ret += gc->base; of_node_put(gg_data.gpiospec.np);
err1:
of_node_put(gpiospec.np);
err0:
pr_debug("%s exited with status %d\n", __func__, ret); pr_debug("%s exited with status %d\n", __func__, ret);
return ret; return gg_data.out_gpio;
} }
EXPORT_SYMBOL(of_get_named_gpio_flags); EXPORT_SYMBOL(of_get_named_gpio_flags);
...@@ -227,14 +234,3 @@ void of_gpiochip_remove(struct gpio_chip *chip) ...@@ -227,14 +234,3 @@ void of_gpiochip_remove(struct gpio_chip *chip)
if (chip->of_node) if (chip->of_node)
of_node_put(chip->of_node); of_node_put(chip->of_node);
} }
/* Private function for resolving node pointer to gpio_chip */
static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data)
{
return chip->of_node == data;
}
struct gpio_chip *of_node_to_gpiochip(struct device_node *np)
{
return gpiochip_find(np, of_gpiochip_is_match);
}
...@@ -1093,7 +1093,7 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -1093,7 +1093,7 @@ int gpiochip_add(struct gpio_chip *chip)
if (status) if (status)
goto fail; goto fail;
pr_info("gpiochip_add: registered GPIOs %d to %d on device: %s\n", pr_debug("gpiochip_add: registered GPIOs %d to %d on device: %s\n",
chip->base, chip->base + chip->ngpio - 1, chip->base, chip->base + chip->ngpio - 1,
chip->label ? : "generic"); chip->label ? : "generic");
...@@ -1154,9 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove); ...@@ -1154,9 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
* non-zero, this function will return to the caller and not iterate over any * non-zero, this function will return to the caller and not iterate over any
* more gpio_chips. * more gpio_chips.
*/ */
struct gpio_chip *gpiochip_find(const void *data, struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, int (*match)(struct gpio_chip *chip,
const void *data)) void *data))
{ {
struct gpio_chip *chip = NULL; struct gpio_chip *chip = NULL;
unsigned long flags; unsigned long flags;
...@@ -1302,8 +1302,18 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) ...@@ -1302,8 +1302,18 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
(flags & GPIOF_INIT_HIGH) ? 1 : 0); (flags & GPIOF_INIT_HIGH) ? 1 : 0);
if (err) if (err)
gpio_free(gpio); goto free_gpio;
if (flags & GPIOF_EXPORT) {
err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE);
if (err)
goto free_gpio;
}
return 0;
free_gpio:
gpio_free(gpio);
return err; return err;
} }
EXPORT_SYMBOL_GPL(gpio_request_one); EXPORT_SYMBOL_GPL(gpio_request_one);
......
...@@ -51,12 +51,6 @@ config OF_IRQ ...@@ -51,12 +51,6 @@ config OF_IRQ
config OF_DEVICE config OF_DEVICE
def_bool y def_bool y
config OF_GPIO
def_bool y
depends on GPIOLIB && !SPARC
help
OpenFirmware GPIO accessors
config OF_I2C config OF_I2C
def_tristate I2C def_tristate I2C
depends on I2C && !SPARC depends on I2C && !SPARC
......
...@@ -4,7 +4,6 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o ...@@ -4,7 +4,6 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o
obj-$(CONFIG_OF_GPIO) += gpio.o
obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_I2C) += of_i2c.o
obj-$(CONFIG_OF_NET) += of_net.o obj-$(CONFIG_OF_NET) += of_net.o
obj-$(CONFIG_OF_SELFTEST) += selftest.o obj-$(CONFIG_OF_SELFTEST) += selftest.o
......
...@@ -142,9 +142,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio); ...@@ -142,9 +142,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio);
/* add/remove chips */ /* add/remove chips */
extern int gpiochip_add(struct gpio_chip *chip); extern int gpiochip_add(struct gpio_chip *chip);
extern int __must_check gpiochip_remove(struct gpio_chip *chip); extern int __must_check gpiochip_remove(struct gpio_chip *chip);
extern struct gpio_chip *gpiochip_find(const void *data, extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip, int (*match)(struct gpio_chip *chip,
const void *data)); void *data));
/* Always use the library code for GPIO management calls, /* Always use the library code for GPIO management calls,
...@@ -179,6 +179,8 @@ extern void gpio_free_array(const struct gpio *array, size_t num); ...@@ -179,6 +179,8 @@ extern void gpio_free_array(const struct gpio *array, size_t num);
/* bindings for managed devices that want to request gpios */ /* bindings for managed devices that want to request gpios */
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label);
void devm_gpio_free(struct device *dev, unsigned int gpio); void devm_gpio_free(struct device *dev, unsigned int gpio);
#ifdef CONFIG_GPIO_SYSFS #ifdef CONFIG_GPIO_SYSFS
......
...@@ -67,6 +67,10 @@ int bgpio_remove(struct bgpio_chip *bgc); ...@@ -67,6 +67,10 @@ int bgpio_remove(struct bgpio_chip *bgc);
int bgpio_init(struct bgpio_chip *bgc, struct device *dev, int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
unsigned long sz, void __iomem *dat, void __iomem *set, unsigned long sz, void __iomem *dat, void __iomem *set,
void __iomem *clr, void __iomem *dirout, void __iomem *dirin, void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
bool big_endian); unsigned long flags);
#define BGPIOF_BIG_ENDIAN BIT(0)
#define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */
#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */
#endif /* __BASIC_MMIO_GPIO_H */ #endif /* __BASIC_MMIO_GPIO_H */
#ifndef __LINUX_GPIO_H #ifndef __LINUX_GPIO_H
#define __LINUX_GPIO_H #define __LINUX_GPIO_H
#include <linux/errno.h>
/* see Documentation/gpio.txt */ /* see Documentation/gpio.txt */
/* make these flag values available regardless of GPIO kconfig options */ /* make these flag values available regardless of GPIO kconfig options */
...@@ -20,6 +22,11 @@ ...@@ -20,6 +22,11 @@
/* Gpio pin is open source */ /* Gpio pin is open source */
#define GPIOF_OPEN_SOURCE (1 << 3) #define GPIOF_OPEN_SOURCE (1 << 3)
#define GPIOF_EXPORT (1 << 2)
#define GPIOF_EXPORT_CHANGEABLE (1 << 3)
#define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT)
#define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
/** /**
* struct gpio - a structure describing a GPIO with configuration * struct gpio - a structure describing a GPIO with configuration
* @gpio: the GPIO number * @gpio: the GPIO number
...@@ -33,7 +40,39 @@ struct gpio { ...@@ -33,7 +40,39 @@ struct gpio {
}; };
#ifdef CONFIG_GENERIC_GPIO #ifdef CONFIG_GENERIC_GPIO
#ifdef CONFIG_ARCH_HAVE_CUSTOM_GPIO_H
#include <asm/gpio.h> #include <asm/gpio.h>
#else
#include <asm-generic/gpio.h>
static inline int gpio_get_value(unsigned int gpio)
{
return __gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned int gpio, int value)
{
__gpio_set_value(gpio, value);
}
static inline int gpio_cansleep(unsigned int gpio)
{
return __gpio_cansleep(gpio);
}
static inline int gpio_to_irq(unsigned int gpio)
{
return __gpio_to_irq(gpio);
}
static inline int irq_to_gpio(unsigned int irq)
{
return -EINVAL;
}
#endif
#else #else
...@@ -55,12 +94,24 @@ static inline int gpio_request(unsigned gpio, const char *label) ...@@ -55,12 +94,24 @@ static inline int gpio_request(unsigned gpio, const char *label)
return -ENOSYS; return -ENOSYS;
} }
static inline int devm_gpio_request(struct device *dev, unsigned gpio,
const char *label)
{
return -ENOSYS;
}
static inline int gpio_request_one(unsigned gpio, static inline int gpio_request_one(unsigned gpio,
unsigned long flags, const char *label) unsigned long flags, const char *label)
{ {
return -ENOSYS; return -ENOSYS;
} }
static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label)
{
return -ENOSYS;
}
static inline int gpio_request_array(const struct gpio *array, size_t num) static inline int gpio_request_array(const struct gpio *array, size_t num)
{ {
return -ENOSYS; return -ENOSYS;
...@@ -74,6 +125,14 @@ static inline void gpio_free(unsigned gpio) ...@@ -74,6 +125,14 @@ static inline void gpio_free(unsigned gpio)
WARN_ON(1); WARN_ON(1);
} }
static inline void devm_gpio_free(struct device *dev, unsigned gpio)
{
might_sleep();
/* GPIO can never have been requested */
WARN_ON(1);
}
static inline void gpio_free_array(const struct gpio *array, size_t num) static inline void gpio_free_array(const struct gpio *array, size_t num)
{ {
might_sleep(); might_sleep();
......
...@@ -292,6 +292,7 @@ struct rc5t583 { ...@@ -292,6 +292,7 @@ struct rc5t583 {
* rc5t583_platform_data: Platform data for ricoh rc5t583 pmu. * rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
* The board specific data is provided through this structure. * The board specific data is provided through this structure.
* @irq_base: Irq base number on which this device registers their interrupts. * @irq_base: Irq base number on which this device registers their interrupts.
* @gpio_base: GPIO base from which gpio of this device will start.
* @enable_shutdown: Enable shutdown through the input pin "shutdown". * @enable_shutdown: Enable shutdown through the input pin "shutdown".
* @regulator_deepsleep_slot: The slot number on which device goes to sleep * @regulator_deepsleep_slot: The slot number on which device goes to sleep
* in device sleep mode. * in device sleep mode.
...@@ -303,6 +304,7 @@ struct rc5t583 { ...@@ -303,6 +304,7 @@ struct rc5t583 {
struct rc5t583_platform_data { struct rc5t583_platform_data {
int irq_base; int irq_base;
int gpio_base;
bool enable_shutdown; bool enable_shutdown;
int regulator_deepsleep_slot[RC5T583_REGULATOR_MAX]; int regulator_deepsleep_slot[RC5T583_REGULATOR_MAX];
unsigned long regulator_ext_pwr_control[RC5T583_REGULATOR_MAX]; unsigned long regulator_ext_pwr_control[RC5T583_REGULATOR_MAX];
......
...@@ -58,7 +58,6 @@ extern int of_mm_gpiochip_add(struct device_node *np, ...@@ -58,7 +58,6 @@ extern int of_mm_gpiochip_add(struct device_node *np,
extern void of_gpiochip_add(struct gpio_chip *gc); extern void of_gpiochip_add(struct gpio_chip *gc);
extern void of_gpiochip_remove(struct gpio_chip *gc); extern void of_gpiochip_remove(struct gpio_chip *gc);
extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
extern int of_gpio_simple_xlate(struct gpio_chip *gc, extern int of_gpio_simple_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, const struct of_phandle_args *gpiospec,
u32 *flags); u32 *flags);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册