Commit c2d33069 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v3.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO changes from Linus Walleij:
 "Here is the bulk of GPIO changes for the v3.13 development cycle.

  I've got ACKs for the things that affect other subsystems (or it's my
  own subsystem, like pinctrl).  Most of that pertain to an attempt from
  my side to consolidate and get rid of custom GPIO implementations in
  the ARM tree.  I will continue doing this.

  The main change this time is the new GPIO descriptor API, background
  for this can be found in Corbet's summary from this january in LWN:

    http://lwn.net/Articles/533632/

  Summary:

   - Merged the GPIO descriptor API from Alexandre Courbot.  This is a
     first step toward trying to get rid of the global GPIO numberspace
     for the future.

   - Add an API so that driver can flag that a certain GPIO line is
     being used by a irqchip backend for generating IRQs, so that we can
     enforce checks, like not allowing users to switch that line to an
     output at runtime, since this makes no sense.  Implemented
     corresponding calls in a few select drivers.

   - ACPI GPIO cleanups, refactorings and switch to using the
     descriptor-based interface.

   - Support for the TPS80036 Palmas GPIO variant.

   - A new driver for the Broadcom Kona GPIO SoC IP block.

   - Device tree support for the PCF857x driver.

   - A set of ARM GPIO refactorings with the goal of getting rid of a
     bunch of custom GPIO implementations from the arch/arm/* tree:

     * Move the IOP GPIO driver to the GPIO subsystem and fix all users
       to use the gpiolib API for accessing GPIOs.  Delete the old
       custom GPIO implementation.

     * Delete the unused custom PXA GPIO implemention.

     * Convert all users of the IXP4 custom GPIO implementation to use
       gpiolib and delete the custom implementation.

     * Delete the custom Gemini GPIO implementation, also completely
       unused.

   - Various cleanups and renamings"

* tag 'gpio-v3.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (85 commits)
  gpio: gpio-mxs: Remove unneeded dt checks
  gpio: pl061: don't depend on CONFIG_ARM
  gpio: bcm-kona: add missing .owner to struct gpio_chip
  gpiolib: provide a declaration of seq_file in gpio/driver.h
  gpiolib: include gpio/consumer.h in of_gpio.h for desc_to_gpio()
  gpio: provide stubs for devres gpio functions
  gpiolib: devres: add missing headers
  gpiolib: make GPIO_DEVRES depend on GPIOLIB
  gpiolib: devres: fix devm_gpiod_get_index()
  gpiolib / ACPI: document the GPIO descriptor based interface
  gpiolib / ACPI: allow passing GPIOF_ACTIVE_LOW for GpioInt resources
  gpiolib / ACPI: add ACPI support for gpiod_get_index()
  gpiolib / ACPI: convert to gpiod interfaces
  gpiolib: add gpiod_get() and gpiod_put() functions
  gpiolib: port of_ functions to use gpiod
  gpiolib: export descriptor-based GPIO interface
  Fixup "MAINTAINERS: GPIO-INTEL-MID: add maintainer"
  gpio: bcm281xx: Don't print addresses of GPIO area in probe()
  gpio: tegra: use new gpio_lock_as_irq() API
  gpio: rcar: Include linux/of.h header
  ...
parents 8a5dc585 99357127
...@@ -295,10 +295,6 @@ These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" ...@@ -295,10 +295,6 @@ These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0"
specifies the path to the controller. In order to use these GPIOs in Linux specifies the path to the controller. In order to use these GPIOs in Linux
we need to translate them to the Linux GPIO numbers. we need to translate them to the Linux GPIO numbers.
The driver can do this by including <linux/acpi_gpio.h> and then calling
acpi_get_gpio(path, gpio). This will return the Linux GPIO number or
negative errno if there was no translation found.
In a simple case of just getting the Linux GPIO number from device In a simple case of just getting the Linux GPIO number from device
resources one can use acpi_get_gpio_by_index() helper function. It takes resources one can use acpi_get_gpio_by_index() helper function. It takes
pointer to the device and index of the GpioIo/GpioInt descriptor in the pointer to the device and index of the GpioIo/GpioInt descriptor in the
...@@ -322,3 +318,25 @@ suitable to the gpiolib before passing them. ...@@ -322,3 +318,25 @@ suitable to the gpiolib before passing them.
In case of GpioInt resource an additional call to gpio_to_irq() must be In case of GpioInt resource an additional call to gpio_to_irq() must be
done before calling request_irq(). done before calling request_irq().
Note that the above API is ACPI specific and not recommended for drivers
that need to support non-ACPI systems. The recommended way is to use
the descriptor based GPIO interfaces. The above example looks like this
when converted to the GPIO desc:
#include <linux/gpio/consumer.h>
...
struct gpio_desc *irq_desc, *power_desc;
irq_desc = gpiod_get_index(dev, NULL, 1);
if (IS_ERR(irq_desc))
/* handle error */
power_desc = gpiod_get_index(dev, NULL, 0);
if (IS_ERR(power_desc))
/* handle error */
/* Now we can use the GPIO descriptors */
See also Documentation/gpio.txt.
Broadcom Kona Family GPIO
=========================
This GPIO driver is used in the following Broadcom SoCs:
BCM11130, BCM11140, BCM11351, BCM28145, BCM28155
The Broadcom GPIO Controller IP can be configured prior to synthesis to
support up to 8 banks of 32 GPIOs where each bank has its own IRQ. The
GPIO controller only supports edge, not level, triggering of interrupts.
Required properties
-------------------
- compatible: "brcm,bcm11351-gpio", "brcm,kona-gpio"
- reg: Physical base address and length of the controller's registers.
- interrupts: The interrupt outputs from the controller. There is one GPIO
interrupt per GPIO bank. The number of interrupts listed depends on the
number of GPIO banks on the SoC. The interrupts must be ordered by bank,
starting with bank 0. There is always a 1:1 mapping between banks and
IRQs.
- #gpio-cells: Should be <2>. The first cell is the pin number, the second
cell is used to specify optional parameters:
- bit 0 specifies polarity (0 for normal, 1 for inverted)
See also "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
- #interrupt-cells: Should be <2>. The first cell is the GPIO number. The
second cell is used to specify flags. The following subset of flags is
supported:
- trigger type (bits[1:0]):
1 = low-to-high edge triggered.
2 = high-to-low edge triggered.
3 = low-to-high or high-to-low edge triggered
Valid values are 1, 2, 3
See also .../devicetree/bindings/interrupt-controller/interrupts.txt.
- gpio-controller: Marks the device node as a GPIO controller.
- interrupt-controller: Marks the device node as an interrupt controller.
Example:
gpio: gpio@35003000 {
compatible = "brcm,bcm11351-gpio", "brcm,kona-gpio";
reg = <0x35003000 0x800>;
interrupts =
<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH
GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH
GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH
GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH
GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH
GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
#gpio-cells = <2>;
#interrupt-cells = <2>;
gpio-controller;
interrupt-controller;
};
* PCF857x-compatible I/O expanders
The PCF857x-compatible chips have "quasi-bidirectional" I/O lines that can be
driven high by a pull-up current source or driven low to ground. This combines
the direction and output level into a single bit per line, which can't be read
back. We can't actually know at initialization time whether a line is configured
(a) as output and driving the signal low/high, or (b) as input and reporting a
low/high value, without knowing the last value written since the chip came out
of reset (if any). The only reliable solution for setting up line direction is
thus to do it explicitly.
Required Properties:
- compatible: should be one of the following.
- "maxim,max7328": For the Maxim MAX7378
- "maxim,max7329": For the Maxim MAX7329
- "nxp,pca8574": For the NXP PCA8574
- "nxp,pca8575": For the NXP PCA8575
- "nxp,pca9670": For the NXP PCA9670
- "nxp,pca9671": For the NXP PCA9671
- "nxp,pca9672": For the NXP PCA9672
- "nxp,pca9673": For the NXP PCA9673
- "nxp,pca9674": For the NXP PCA9674
- "nxp,pca9675": For the NXP PCA9675
- "nxp,pcf8574": For the NXP PCF8574
- "nxp,pcf8574a": For the NXP PCF8574A
- "nxp,pcf8575": For the NXP PCF8575
- "ti,tca9554": For the TI TCA9554
- reg: I2C slave address.
- gpio-controller: Marks the device node as a gpio controller.
- #gpio-cells: Should be 2. The first cell is the GPIO number and the second
cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
Optional Properties:
- lines-initial-states: Bitmask that specifies the initial state of each
line. When a bit is set to zero, the corresponding line will be initialized to
the input (pulled-up) state. When the bit is set to one, the line will be
initialized the the low-level output state. If the property is not specified
all lines will be initialized to the input state.
The I/O expander can detect input state changes, and thus optionally act as
an interrupt controller. When the expander interrupt line is connected all the
following properties must be set. For more information please see the
interrupt controller device tree bindings documentation available at
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt.
- interrupt-controller: Identifies the node as an interrupt controller.
- #interrupt-cells: Number of cells to encode an interrupt source, shall be 2.
- interrupt-parent: phandle of the parent interrupt controller.
- interrupts: Interrupt specifier for the controllers interrupt.
Please refer to gpio.txt in this directory for details of the common GPIO
bindings used by client devices.
Example: PCF8575 I/O expander node
pcf8575: gpio@20 {
compatible = "nxp,pcf8575";
reg = <0x20>;
interrupt-parent = <&irqpin2>;
interrupts = <3 0>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
...@@ -4440,6 +4440,12 @@ F: Documentation/networking/ixgbevf.txt ...@@ -4440,6 +4440,12 @@ F: Documentation/networking/ixgbevf.txt
F: Documentation/networking/i40e.txt F: Documentation/networking/i40e.txt
F: drivers/net/ethernet/intel/ F: drivers/net/ethernet/intel/
INTEL-MID GPIO DRIVER
M: David Cohen <david.a.cohen@linux.intel.com>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-intel-mid.c
INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
M: Stanislav Yakovlev <stas.yakovlev@gmail.com> M: Stanislav Yakovlev <stas.yakovlev@gmail.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
......
...@@ -389,7 +389,6 @@ config ARCH_GEMINI ...@@ -389,7 +389,6 @@ config ARCH_GEMINI
select CLKSRC_MMIO select CLKSRC_MMIO
select CPU_FA526 select CPU_FA526
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select NEED_MACH_GPIO_H
help help
Support for the Cortina Systems Gemini family SoCs Support for the Cortina Systems Gemini family SoCs
...@@ -458,7 +457,7 @@ config ARCH_IOP32X ...@@ -458,7 +457,7 @@ config ARCH_IOP32X
depends on MMU depends on MMU
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select CPU_XSCALE select CPU_XSCALE
select NEED_MACH_GPIO_H select GPIO_IOP
select NEED_RET_TO_USER select NEED_RET_TO_USER
select PCI select PCI
select PLAT_IOP select PLAT_IOP
...@@ -471,7 +470,7 @@ config ARCH_IOP33X ...@@ -471,7 +470,7 @@ config ARCH_IOP33X
depends on MMU depends on MMU
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select CPU_XSCALE select CPU_XSCALE
select NEED_MACH_GPIO_H select GPIO_IOP
select NEED_RET_TO_USER select NEED_RET_TO_USER
select PCI select PCI
select PLAT_IOP select PLAT_IOP
...@@ -560,7 +559,6 @@ config ARCH_MMP ...@@ -560,7 +559,6 @@ config ARCH_MMP
select GPIO_PXA select GPIO_PXA
select IRQ_DOMAIN select IRQ_DOMAIN
select MULTI_IRQ_HANDLER select MULTI_IRQ_HANDLER
select NEED_MACH_GPIO_H
select PINCTRL select PINCTRL
select PLAT_PXA select PLAT_PXA
select SPARSE_IRQ select SPARSE_IRQ
...@@ -623,7 +621,6 @@ config ARCH_PXA ...@@ -623,7 +621,6 @@ config ARCH_PXA
select GPIO_PXA select GPIO_PXA
select HAVE_IDE select HAVE_IDE
select MULTI_IRQ_HANDLER select MULTI_IRQ_HANDLER
select NEED_MACH_GPIO_H
select PLAT_PXA select PLAT_PXA
select SPARSE_IRQ select SPARSE_IRQ
help help
......
/*
* arch/arm/include/asm/hardware/iop3xx-gpio.h
*
* IOP3xx GPIO wrappers
*
* Copyright (c) 2008 Arnaud Patard <arnaud.patard@rtp-net.org>
* Based on IXP4XX gpio.h file
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __ASM_ARM_HARDWARE_IOP3XX_GPIO_H
#define __ASM_ARM_HARDWARE_IOP3XX_GPIO_H
#include <mach/hardware.h>
#include <asm-generic/gpio.h>
#define __ARM_GPIOLIB_COMPLEX
#define IOP3XX_N_GPIOS 8
static inline int gpio_get_value(unsigned gpio)
{
if (gpio > IOP3XX_N_GPIOS)
return __gpio_get_value(gpio);
return gpio_line_get(gpio);
}
static inline void gpio_set_value(unsigned gpio, int value)
{
if (gpio > IOP3XX_N_GPIOS) {
__gpio_set_value(gpio, value);
return;
}
gpio_line_set(gpio, value);
}
static inline int gpio_cansleep(unsigned gpio)
{
if (gpio < IOP3XX_N_GPIOS)
return 0;
else
return __gpio_cansleep(gpio);
}
/*
* The GPIOs are not generating any interrupt
* Note : manuals are not clear about this
*/
static inline int gpio_to_irq(int gpio)
{
return -EINVAL;
}
static inline int irq_to_gpio(int gpio)
{
return -EINVAL;
}
#endif
...@@ -18,16 +18,9 @@ ...@@ -18,16 +18,9 @@
/* /*
* IOP3XX GPIO handling * IOP3XX GPIO handling
*/ */
#define GPIO_IN 0
#define GPIO_OUT 1
#define GPIO_LOW 0
#define GPIO_HIGH 1
#define IOP3XX_GPIO_LINE(x) (x) #define IOP3XX_GPIO_LINE(x) (x)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void gpio_line_config(int line, int direction);
extern int gpio_line_get(int line);
extern void gpio_line_set(int line, int value);
extern int init_atu; extern int init_atu;
extern int iop3xx_get_init_atu(void); extern int iop3xx_get_init_atu(void);
#endif #endif
...@@ -168,11 +161,6 @@ extern int iop3xx_get_init_atu(void); ...@@ -168,11 +161,6 @@ extern int iop3xx_get_init_atu(void);
/* PERCR0 DOESN'T EXIST - index from 1! */ /* PERCR0 DOESN'T EXIST - index from 1! */
#define IOP3XX_PERCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0710) #define IOP3XX_PERCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0710)
/* General Purpose I/O */
#define IOP3XX_GPOE (volatile u32 *)IOP3XX_GPIO_REG(0x0000)
#define IOP3XX_GPID (volatile u32 *)IOP3XX_GPIO_REG(0x0004)
#define IOP3XX_GPOD (volatile u32 *)IOP3XX_GPIO_REG(0x0008)
/* Timers */ /* Timers */
#define IOP3XX_TU_TMR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0000) #define IOP3XX_TU_TMR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0000)
#define IOP3XX_TU_TMR1 (volatile u32 *)IOP3XX_TIMER_REG(0x0004) #define IOP3XX_TU_TMR1 (volatile u32 *)IOP3XX_TIMER_REG(0x0004)
......
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include <mach/gpio.h>
#define GPIO_BASE(x) IO_ADDRESS(GEMINI_GPIO_BASE(x)) #define GPIO_BASE(x) IO_ADDRESS(GEMINI_GPIO_BASE(x))
#define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE)
/* GPIO registers definition */ /* GPIO registers definition */
#define GPIO_DATA_OUT 0x0 #define GPIO_DATA_OUT 0x0
......
/*
* Gemini gpiolib specific defines
*
* Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
*
* 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 __MACH_GPIO_H__
#define __MACH_GPIO_H__
#include <mach/irqs.h>
#define gpio_to_irq(x) ((x) + GPIO_IRQ_BASE)
#define irq_to_gpio(x) ((x) - GPIO_IRQ_BASE)
#endif /* __MACH_GPIO_H__ */
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <mach/time.h> #include <mach/time.h>
#include "gpio-iop32x.h"
static void __init em7210_timer_init(void) static void __init em7210_timer_init(void)
{ {
...@@ -183,6 +184,7 @@ void em7210_power_off(void) ...@@ -183,6 +184,7 @@ void em7210_power_off(void)
static void __init em7210_init_machine(void) static void __init em7210_init_machine(void)
{ {
register_iop32x_gpio();
platform_device_register(&em7210_serial_device); platform_device_register(&em7210_serial_device);
platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop3xx_i2c1_device);
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/page.h> #include <asm/page.h>
#include <mach/time.h> #include <mach/time.h>
#include "gpio-iop32x.h"
/* /*
* GLAN Tank timer tick configuration. * GLAN Tank timer tick configuration.
...@@ -187,6 +188,7 @@ static void glantank_power_off(void) ...@@ -187,6 +188,7 @@ static void glantank_power_off(void)
static void __init glantank_init_machine(void) static void __init glantank_init_machine(void)
{ {
register_iop32x_gpio();
platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&glantank_flash_device); platform_device_register(&glantank_flash_device);
......
static struct resource iop32x_gpio_res[] = {
DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x07c4), 0x10),
};
static inline void register_iop32x_gpio(void)
{
platform_device_register_simple("gpio-iop", 0,
iop32x_gpio_res,
ARRAY_SIZE(iop32x_gpio_res));
}
#ifndef __ASM_ARCH_IOP32X_GPIO_H
#define __ASM_ARCH_IOP32X_GPIO_H
#include <asm/hardware/iop3xx-gpio.h>
#endif
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
* Peripherals that are shared between the iop32x and iop33x but * Peripherals that are shared between the iop32x and iop33x but
* located at different addresses. * located at different addresses.
*/ */
#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07c4 + (reg))
#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg)) #define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg))
#include <asm/hardware/iop3xx.h> #include <asm/hardware/iop3xx.h>
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <mach/time.h> #include <mach/time.h>
#include "gpio-iop32x.h"
/* /*
* Until March of 2007 iq31244 platforms and ep80219 platforms shared the * Until March of 2007 iq31244 platforms and ep80219 platforms shared the
...@@ -283,6 +284,7 @@ void ep80219_power_off(void) ...@@ -283,6 +284,7 @@ void ep80219_power_off(void)
static void __init iq31244_init_machine(void) static void __init iq31244_init_machine(void)
{ {
register_iop32x_gpio();
platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq31244_flash_device); platform_device_register(&iq31244_flash_device);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <mach/time.h> #include <mach/time.h>
#include "gpio-iop32x.h"
/* /*
* IQ80321 timer tick configuration. * IQ80321 timer tick configuration.
...@@ -170,6 +171,7 @@ static struct platform_device iq80321_serial_device = { ...@@ -170,6 +171,7 @@ static struct platform_device iq80321_serial_device = {
static void __init iq80321_init_machine(void) static void __init iq80321_init_machine(void)
{ {
register_iop32x_gpio();
platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq80321_flash_device); platform_device_register(&iq80321_flash_device);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gpio.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <mach/time.h> #include <mach/time.h>
#include "gpio-iop32x.h"
/* /*
* N2100 timer tick configuration. * N2100 timer tick configuration.
...@@ -288,8 +290,14 @@ static void n2100_power_off(void) ...@@ -288,8 +290,14 @@ static void n2100_power_off(void)
static void n2100_restart(enum reboot_mode mode, const char *cmd) static void n2100_restart(enum reboot_mode mode, const char *cmd)
{ {
gpio_line_set(N2100_HARDWARE_RESET, GPIO_LOW); int ret;
gpio_line_config(N2100_HARDWARE_RESET, GPIO_OUT);
ret = gpio_direction_output(N2100_HARDWARE_RESET, 0);
if (ret) {
pr_crit("could not drive reset GPIO low\n");
return;
}
/* Wait for reset to happen */
while (1) while (1)
; ;
} }
...@@ -299,7 +307,7 @@ static struct timer_list power_button_poll_timer; ...@@ -299,7 +307,7 @@ static struct timer_list power_button_poll_timer;
static void power_button_poll(unsigned long dummy) static void power_button_poll(unsigned long dummy)
{ {
if (gpio_line_get(N2100_POWER_BUTTON) == 0) { if (gpio_get_value(N2100_POWER_BUTTON) == 0) {
ctrl_alt_del(); ctrl_alt_del();
return; return;
} }
...@@ -308,9 +316,37 @@ static void power_button_poll(unsigned long dummy) ...@@ -308,9 +316,37 @@ static void power_button_poll(unsigned long dummy)
add_timer(&power_button_poll_timer); add_timer(&power_button_poll_timer);
} }
static int __init n2100_request_gpios(void)
{
int ret;
if (!machine_is_n2100())
return 0;
ret = gpio_request(N2100_HARDWARE_RESET, "reset");
if (ret)
pr_err("could not request reset GPIO\n");
ret = gpio_request(N2100_POWER_BUTTON, "power");
if (ret)
pr_err("could not request power GPIO\n");
else {
ret = gpio_direction_input(N2100_POWER_BUTTON);
if (ret)
pr_err("could not set power GPIO as input\n");
}
/* Set up power button poll timer */
init_timer(&power_button_poll_timer);
power_button_poll_timer.function = power_button_poll;
power_button_poll_timer.expires = jiffies + (HZ / 10);
add_timer(&power_button_poll_timer);
return 0;
}
device_initcall(n2100_request_gpios);
static void __init n2100_init_machine(void) static void __init n2100_init_machine(void)
{ {
register_iop32x_gpio();
platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&n2100_flash_device); platform_device_register(&n2100_flash_device);
platform_device_register(&n2100_serial_device); platform_device_register(&n2100_serial_device);
...@@ -321,11 +357,6 @@ static void __init n2100_init_machine(void) ...@@ -321,11 +357,6 @@ static void __init n2100_init_machine(void)
ARRAY_SIZE(n2100_i2c_devices)); ARRAY_SIZE(n2100_i2c_devices));
pm_power_off = n2100_power_off; pm_power_off = n2100_power_off;
init_timer(&power_button_poll_timer);
power_button_poll_timer.function = power_button_poll;
power_button_poll_timer.expires = jiffies + (HZ / 10);
add_timer(&power_button_poll_timer);
} }
MACHINE_START(N2100, "Thecus N2100") MACHINE_START(N2100, "Thecus N2100")
......
#ifndef __ASM_ARCH_IOP33X_GPIO_H
#define __ASM_ARCH_IOP33X_GPIO_H
#include <asm/hardware/iop3xx-gpio.h>
#endif
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
* Peripherals that are shared between the iop32x and iop33x but * Peripherals that are shared between the iop32x and iop33x but
* located at different addresses. * located at different addresses.
*/ */
#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1780 + (reg))
#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07d0 + (reg)) #define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07d0 + (reg))
#include <asm/hardware/iop3xx.h> #include <asm/hardware/iop3xx.h>
......
...@@ -122,8 +122,15 @@ static struct platform_device iq80331_flash_device = { ...@@ -122,8 +122,15 @@ static struct platform_device iq80331_flash_device = {
.resource = &iq80331_flash_resource, .resource = &iq80331_flash_resource,
}; };
static struct resource iq80331_gpio_res[] = {
DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x1780), 0x10),
};
static void __init iq80331_init_machine(void) static void __init iq80331_init_machine(void)
{ {
platform_device_register_simple("gpio-iop", 0,
iq80331_gpio_res,
ARRAY_SIZE(iq80331_gpio_res));
platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iop33x_uart0_device); platform_device_register(&iop33x_uart0_device);
......
...@@ -122,8 +122,15 @@ static struct platform_device iq80332_flash_device = { ...@@ -122,8 +122,15 @@ static struct platform_device iq80332_flash_device = {
.resource = &iq80332_flash_resource, .resource = &iq80332_flash_resource,
}; };
static struct resource iq80332_gpio_res[] = {
DEFINE_RES_MEM((IOP3XX_PERIPHERAL_PHYS_BASE + 0x1780), 0x10),
};
static void __init iq80332_init_machine(void) static void __init iq80332_init_machine(void)
{ {
platform_device_register_simple("gpio-iop", 0,
iq80332_gpio_res,
ARRAY_SIZE(iq80332_gpio_res));
platform_device_register(&iop3xx_i2c0_device); platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&iop3xx_i2c1_device); platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iop33x_uart0_device); platform_device_register(&iop33x_uart0_device);
......
...@@ -81,6 +81,44 @@ void __init ixp4xx_map_io(void) ...@@ -81,6 +81,44 @@ void __init ixp4xx_map_io(void)
iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc)); iotable_init(ixp4xx_io_desc, ARRAY_SIZE(ixp4xx_io_desc));
} }
/*
* GPIO-functions
*/
/*
* The following converted to the real HW bits the gpio_line_config
*/
/* GPIO pin types */
#define IXP4XX_GPIO_OUT 0x1
#define IXP4XX_GPIO_IN 0x2
/* GPIO signal types */
#define IXP4XX_GPIO_LOW 0
#define IXP4XX_GPIO_HIGH 1
/* GPIO Clocks */
#define IXP4XX_GPIO_CLK_0 14
#define IXP4XX_GPIO_CLK_1 15
static void gpio_line_config(u8 line, u32 direction)
{
if (direction == IXP4XX_GPIO_IN)
*IXP4XX_GPIO_GPOER |= (1 << line);
else
*IXP4XX_GPIO_GPOER &= ~(1 << line);
}
static void gpio_line_get(u8 line, int *value)
{
*value = (*IXP4XX_GPIO_GPINR >> line) & 0x1;
}
static void gpio_line_set(u8 line, int value)
{
if (value == IXP4XX_GPIO_HIGH)
*IXP4XX_GPIO_GPOUTR |= (1 << line);
else if (value == IXP4XX_GPIO_LOW)
*IXP4XX_GPIO_GPOUTR &= ~(1 << line);
}
/************************************************************************* /*************************************************************************
* IXP4xx chipset IRQ handling * IXP4xx chipset IRQ handling
...@@ -117,17 +155,6 @@ static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) ...@@ -117,17 +155,6 @@ static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
return -EINVAL; return -EINVAL;
} }
int irq_to_gpio(unsigned int irq)
{
int gpio = (irq < 32) ? irq2gpio[irq] : -EINVAL;
if (gpio == -1)
return -EINVAL;
return gpio;
}
EXPORT_SYMBOL(irq_to_gpio);
static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type) static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
{ {
int line = irq2gpio[d->irq]; int line = irq2gpio[d->irq];
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-gpio.h> #include <linux/i2c-gpio.h>
#include <linux/gpio.h>
#include <mach/hardware.h> #include <mach/hardware.h>
...@@ -161,11 +162,8 @@ static struct platform_device *dsmg600_devices[] __initdata = { ...@@ -161,11 +162,8 @@ static struct platform_device *dsmg600_devices[] __initdata = {
static void dsmg600_power_off(void) static void dsmg600_power_off(void)
{ {
/* enable the pwr cntl gpio */ /* enable the pwr cntl and drive it high */
gpio_line_config(DSMG600_PO_GPIO, IXP4XX_GPIO_OUT); gpio_direction_output(DSMG600_PO_GPIO, 1);
/* poweroff */
gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);
} }
/* This is used to make sure the power-button pusher is serious. The button /* This is used to make sure the power-button pusher is serious. The button
...@@ -202,7 +200,7 @@ static void dsmg600_power_handler(unsigned long data) ...@@ -202,7 +200,7 @@ static void dsmg600_power_handler(unsigned long data)
ctrl_alt_del(); ctrl_alt_del();
/* Change the state of the power LED to "blink" */ /* Change the state of the power LED to "blink" */
gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW); gpio_set_value(DSMG600_LED_PWR_GPIO, 0);
} else { } else {
power_button_countdown = PBUTTON_HOLDDOWN_COUNT; power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
} }
...@@ -228,6 +226,40 @@ static void __init dsmg600_timer_init(void) ...@@ -228,6 +226,40 @@ static void __init dsmg600_timer_init(void)
ixp4xx_timer_init(); ixp4xx_timer_init();
} }
static int __init dsmg600_gpio_init(void)
{
if (!machine_is_dsmg600())
return 0;
gpio_request(DSMG600_RB_GPIO, "reset button");
if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler,
IRQF_DISABLED | IRQF_TRIGGER_LOW,
"DSM-G600 reset button", NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
gpio_to_irq(DSMG600_RB_GPIO));
}
/*
* The power button on the D-Link DSM-G600 is on GPIO 15, but
* it cannot handle interrupts on that GPIO line. So we'll
* have to poll it with a kernel timer.
*/
/* Make sure that the power button GPIO is set up as an input */
gpio_request(DSMG600_PB_GPIO, "power button");
gpio_direction_input(DSMG600_PB_GPIO);
/* Request poweroff GPIO line */
gpio_request(DSMG600_PO_GPIO, "power off button");
/* Set the initial value for the power button IRQ handler */
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
return 0;
}
device_initcall(dsmg600_gpio_init);
static void __init dsmg600_init(void) static void __init dsmg600_init(void)
{ {
ixp4xx_sys_init(); ixp4xx_sys_init();
...@@ -251,27 +283,6 @@ static void __init dsmg600_init(void) ...@@ -251,27 +283,6 @@ static void __init dsmg600_init(void)
platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices)); platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices));
pm_power_off = dsmg600_power_off; pm_power_off = dsmg600_power_off;
if (request_irq(gpio_to_irq(DSMG600_RB_GPIO), &dsmg600_reset_handler,
IRQF_DISABLED | IRQF_TRIGGER_LOW,
"DSM-G600 reset button", NULL) < 0) {
printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
gpio_to_irq(DSMG600_RB_GPIO));
}
/* The power button on the D-Link DSM-G600 is on GPIO 15, but
* it cannot handle interrupts on that GPIO line. So we'll
* have to poll it with a kernel timer.
*/
/* Make sure that the power button GPIO is set up as an input */
gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
/* Set the initial value for the power button IRQ handler */
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
} }
MACHINE_START(DSMG600, "D-Link DSM-G600 RevA") MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
......
...@@ -131,44 +131,5 @@ struct pci_sys_data; ...@@ -131,44 +131,5 @@ struct pci_sys_data;
extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
extern struct pci_ops ixp4xx_ops; extern struct pci_ops ixp4xx_ops;
/*
* GPIO-functions
*/
/*
* The following converted to the real HW bits the gpio_line_config
*/
/* GPIO pin types */
#define IXP4XX_GPIO_OUT 0x1
#define IXP4XX_GPIO_IN 0x2
/* GPIO signal types */
#define IXP4XX_GPIO_LOW 0
#define IXP4XX_GPIO_HIGH 1
/* GPIO Clocks */
#define IXP4XX_GPIO_CLK_0 14
#define IXP4XX_GPIO_CLK_1 15
static inline void gpio_line_config(u8 line, u32 direction)
{
if (direction == IXP4XX_GPIO_IN)
*IXP4XX_GPIO_GPOER |= (1 << line);
else
*IXP4XX_GPIO_GPOER &= ~(1 << line);
}
static inline void gpio_line_get(u8 line, int *value)
{
*value = (*IXP4XX_GPIO_GPINR >> line) & 0x1;
}
static inline void gpio_line_set(u8 line, int value)
{
if (value == IXP4XX_GPIO_HIGH)
*IXP4XX_GPIO_GPOUTR |= (1 << line);
else if (value == IXP4XX_GPIO_LOW)
*IXP4XX_GPIO_GPOUTR &= ~(1 << line);
}
#endif // __ASSEMBLY__ #endif // __ASSEMBLY__
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/memory.h> #include <asm/memory.h>
...@@ -80,10 +81,10 @@ ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) ...@@ -80,10 +81,10 @@ ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
if (ctrl & NAND_CTRL_CHANGE) { if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE) { if (ctrl & NAND_NCE) {
gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_LOW); gpio_set_value(IXDP425_NAND_NCE_PIN, 0);
udelay(5); udelay(5);
} else } else
gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_HIGH); gpio_set_value(IXDP425_NAND_NCE_PIN, 1);
offset = (ctrl & NAND_CLE) ? IXDP425_NAND_CMD_BYTE : 0; offset = (ctrl & NAND_CLE) ? IXDP425_NAND_CMD_BYTE : 0;
offset |= (ctrl & NAND_ALE) ? IXDP425_NAND_ADDR_BYTE : 0; offset |= (ctrl & NAND_ALE) ? IXDP425_NAND_ADDR_BYTE : 0;
...@@ -227,7 +228,8 @@ static void __init ixdp425_init(void) ...@@ -227,7 +228,8 @@ static void __init ixdp425_init(void)
ixdp425_flash_nand_resource.start = IXP4XX_EXP_BUS_BASE(3), ixdp425_flash_nand_resource.start = IXP4XX_EXP_BUS_BASE(3),
ixdp425_flash_nand_resource.end = IXP4XX_EXP_BUS_BASE(3) + 0x10 - 1; ixdp425_flash_nand_resource.end = IXP4XX_EXP_BUS_BASE(3) + 0x10 - 1;
gpio_line_config(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_OUT); gpio_request(IXDP425_NAND_NCE_PIN, "NAND NCE pin");
gpio_direction_output(IXDP425_NAND_NCE_PIN, 0);
/* Configure expansion bus for NAND Flash */ /* Configure expansion bus for NAND Flash */
*IXP4XX_EXP_CS3 = IXP4XX_EXP_BUS_CS_EN | *IXP4XX_EXP_CS3 = IXP4XX_EXP_BUS_CS_EN |
......
...@@ -184,11 +184,8 @@ static void nas100d_power_off(void) ...@@ -184,11 +184,8 @@ static void nas100d_power_off(void)
{ {
/* This causes the box to drop the power and go dead. */ /* This causes the box to drop the power and go dead. */
/* enable the pwr cntl gpio */ /* enable the pwr cntl gpio and assert power off */
gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT); gpio_direction_output(NAS100D_PO_GPIO, 1);
/* do the deed */
gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
} }
/* This is used to make sure the power-button pusher is serious. The button /* This is used to make sure the power-button pusher is serious. The button
...@@ -225,7 +222,7 @@ static void nas100d_power_handler(unsigned long data) ...@@ -225,7 +222,7 @@ static void nas100d_power_handler(unsigned long data)
ctrl_alt_del(); ctrl_alt_del();
/* Change the state of the power LED to "blink" */ /* Change the state of the power LED to "blink" */
gpio_line_set(NAS100D_LED_PWR_GPIO, IXP4XX_GPIO_LOW); gpio_set_value(NAS100D_LED_PWR_GPIO, 0);
} else { } else {
power_button_countdown = PBUTTON_HOLDDOWN_COUNT; power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
} }
...@@ -242,6 +239,33 @@ static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) ...@@ -242,6 +239,33 @@ static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int __init nas100d_gpio_init(void)
{
if (!machine_is_nas100d())
return 0;
/*
* The power button on the Iomega NAS100d is on GPIO 14, but
* it cannot handle interrupts on that GPIO line. So we'll
* have to poll it with a kernel timer.
*/
/* Request the power off GPIO */
gpio_request(NAS100D_PO_GPIO, "power off");
/* Make sure that the power button GPIO is set up as an input */
gpio_request(NAS100D_PB_GPIO, "power button");
gpio_direction_input(NAS100D_PB_GPIO);
/* Set the initial value for the power button IRQ handler */
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
return 0;
}
device_initcall(nas100d_gpio_init);
static void __init nas100d_init(void) static void __init nas100d_init(void)
{ {
uint8_t __iomem *f; uint8_t __iomem *f;
...@@ -278,19 +302,6 @@ static void __init nas100d_init(void) ...@@ -278,19 +302,6 @@ static void __init nas100d_init(void)
gpio_to_irq(NAS100D_RB_GPIO)); gpio_to_irq(NAS100D_RB_GPIO));
} }
/* The power button on the Iomega NAS100d is on GPIO 14, but
* it cannot handle interrupts on that GPIO line. So we'll
* have to poll it with a kernel timer.
*/
/* Make sure that the power button GPIO is set up as an input */
gpio_line_config(NAS100D_PB_GPIO, IXP4XX_GPIO_IN);
/* Set the initial value for the power button IRQ handler */
power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
mod_timer(&nas100d_power_timer, jiffies + msecs_to_jiffies(500));
/* /*
* Map in a portion of the flash and read the MAC address. * Map in a portion of the flash and read the MAC address.
* Since it is stored in BE in the flash itself, we need to * Since it is stored in BE in the flash itself, we need to
......
...@@ -197,11 +197,8 @@ static void nslu2_power_off(void) ...@@ -197,11 +197,8 @@ static void nslu2_power_off(void)
{ {
/* This causes the box to drop the power and go dead. */ /* This causes the box to drop the power and go dead. */
/* enable the pwr cntl gpio */ /* enable the pwr cntl gpio and assert power off */
gpio_line_config(NSLU2_PO_GPIO, IXP4XX_GPIO_OUT); gpio_direction_output(NSLU2_PO_GPIO, 1);
/* do the deed */
gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
} }
static irqreturn_t nslu2_power_handler(int irq, void *dev_id) static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
...@@ -223,6 +220,16 @@ static irqreturn_t nslu2_reset_handler(int irq, void *dev_id) ...@@ -223,6 +220,16 @@ static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int __init nslu2_gpio_init(void)
{
if (!machine_is_nslu2())
return 0;
/* Request the power off GPIO */
return gpio_request(NSLU2_PO_GPIO, "power off");
}
device_initcall(nslu2_gpio_init);
static void __init nslu2_timer_init(void) static void __init nslu2_timer_init(void)
{ {
/* The xtal on this machine is non-standard. */ /* The xtal on this machine is non-standard. */
......
#ifndef __ASM_MACH_GPIO_H
#define __ASM_MACH_GPIO_H
#include <asm-generic/gpio.h>
#include <mach/cputype.h>
#endif /* __ASM_MACH_GPIO_H */
/*
* arch/arm/mach-pxa/include/mach/gpio.h
*
* PXA GPIO wrappers for arch-neutral GPIO calls
*
* Written by Philipp Zabel <philipp.zabel@gmail.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.
*
* This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __ASM_ARCH_PXA_GPIO_H
#define __ASM_ARCH_PXA_GPIO_H
#include <asm-generic/gpio.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
#endif
/*
* linux/arch/arm/mach-w90p910/include/mach/gpio.h
*
* Generic w90p910 GPIO handling
*
* Wan ZongShun <mcuos.com@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __ASM_ARCH_W90P910_GPIO_H
#define __ASM_ARCH_W90P910_GPIO_H
#include <mach/hardware.h>
#include <asm/irq.h>
static inline int gpio_to_irq(unsigned gpio)
{
return gpio;
}
#define gpio_to_irq gpio_to_irq
static inline int irq_to_gpio(unsigned irq)
{
return irq;
}
#endif
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
obj-y := obj-y :=
# IOP32X # IOP32X
obj-$(CONFIG_ARCH_IOP32X) += gpio.o
obj-$(CONFIG_ARCH_IOP32X) += i2c.o obj-$(CONFIG_ARCH_IOP32X) += i2c.o
obj-$(CONFIG_ARCH_IOP32X) += pci.o obj-$(CONFIG_ARCH_IOP32X) += pci.o
obj-$(CONFIG_ARCH_IOP32X) += setup.o obj-$(CONFIG_ARCH_IOP32X) += setup.o
...@@ -16,7 +15,6 @@ obj-$(CONFIG_ARCH_IOP32X) += pmu.o ...@@ -16,7 +15,6 @@ obj-$(CONFIG_ARCH_IOP32X) += pmu.o
obj-$(CONFIG_ARCH_IOP32X) += restart.o obj-$(CONFIG_ARCH_IOP32X) += restart.o
# IOP33X # IOP33X
obj-$(CONFIG_ARCH_IOP33X) += gpio.o
obj-$(CONFIG_ARCH_IOP33X) += i2c.o obj-$(CONFIG_ARCH_IOP33X) += i2c.o
obj-$(CONFIG_ARCH_IOP33X) += pci.o obj-$(CONFIG_ARCH_IOP33X) += pci.o
obj-$(CONFIG_ARCH_IOP33X) += setup.o obj-$(CONFIG_ARCH_IOP33X) += setup.o
......
...@@ -30,10 +30,6 @@ config ARCH_REQUIRE_GPIOLIB ...@@ -30,10 +30,6 @@ config ARCH_REQUIRE_GPIOLIB
Selecting this from the architecture code will cause the gpiolib Selecting this from the architecture code will cause the gpiolib
code to always get built in. code to always get built in.
config GPIO_DEVRES
def_bool y
depends on HAS_IOMEM
menuconfig GPIOLIB menuconfig GPIOLIB
bool "GPIO Support" bool "GPIO Support"
...@@ -47,6 +43,10 @@ menuconfig GPIOLIB ...@@ -47,6 +43,10 @@ menuconfig GPIOLIB
if GPIOLIB if GPIOLIB
config GPIO_DEVRES
def_bool y
depends on HAS_IOMEM
config OF_GPIO config OF_GPIO
def_bool y def_bool y
depends on OF depends on OF
...@@ -129,7 +129,7 @@ config GPIO_IT8761E ...@@ -129,7 +129,7 @@ config GPIO_IT8761E
config GPIO_EM config GPIO_EM
tristate "Emma Mobile GPIO" tristate "Emma Mobile GPIO"
depends on ARM depends on ARM && OF_GPIO
help help
Say yes here to support GPIO on Renesas Emma Mobile SoCs. Say yes here to support GPIO on Renesas Emma Mobile SoCs.
...@@ -213,7 +213,7 @@ config GPIO_OCTEON ...@@ -213,7 +213,7 @@ config GPIO_OCTEON
config GPIO_PL061 config GPIO_PL061
bool "PrimeCell PL061 GPIO support" bool "PrimeCell PL061 GPIO support"
depends on ARM && ARM_AMBA depends on ARM_AMBA
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
help help
Say yes here to support the PrimeCell PL061 GPIO device Say yes here to support the PrimeCell PL061 GPIO device
...@@ -320,6 +320,15 @@ config GPIO_ICH ...@@ -320,6 +320,15 @@ config GPIO_ICH
If unsure, say N. If unsure, say N.
config GPIO_IOP
tristate "Intel IOP GPIO"
depends on ARM && (ARCH_IOP32X || ARCH_IOP33X)
help
Say yes here to support the GPIO functionality of a number of Intel
IOP32X or IOP33X.
If unsure, say N.
config GPIO_VX855 config GPIO_VX855
tristate "VIA VX855/VX875 GPIO" tristate "VIA VX855/VX875 GPIO"
depends on PCI depends on PCI
...@@ -616,12 +625,12 @@ config GPIO_AMD8111 ...@@ -616,12 +625,12 @@ config GPIO_AMD8111
If unsure, say N If unsure, say N
config GPIO_LANGWELL config GPIO_INTEL_MID
bool "Intel Langwell/Penwell GPIO support" bool "Intel Mid GPIO support"
depends on PCI && X86 depends on PCI && X86
select IRQ_DOMAIN select IRQ_DOMAIN
help help
Say Y here to support Intel Langwell/Penwell GPIO. Say Y here to support Intel Mid GPIO.
config GPIO_PCH config GPIO_PCH
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO"
...@@ -707,7 +716,7 @@ config GPIO_74X164 ...@@ -707,7 +716,7 @@ config GPIO_74X164
comment "AC97 GPIO expanders:" comment "AC97 GPIO expanders:"
config GPIO_UCB1400 config GPIO_UCB1400
bool "Philips UCB1400 GPIO" tristate "Philips UCB1400 GPIO"
depends on UCB1400_CORE depends on UCB1400_CORE
help help
This enables support for the Philips UCB1400 GPIO pins. This enables support for the Philips UCB1400 GPIO pins.
...@@ -763,6 +772,12 @@ config GPIO_MSIC ...@@ -763,6 +772,12 @@ config GPIO_MSIC
Enable support for GPIO on intel MSIC controllers found in Enable support for GPIO on intel MSIC controllers found in
intel MID devices intel MID devices
config GPIO_BCM_KONA
bool "Broadcom Kona GPIO"
depends on OF_GPIO
help
Turn on GPIO support for Broadcom "Kona" chips.
comment "USB GPIO expanders:" comment "USB GPIO expanders:"
config GPIO_VIPERBOARD config GPIO_VIPERBOARD
......
...@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o ...@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
...@@ -28,11 +29,12 @@ obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o ...@@ -28,11 +29,12 @@ obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
......
...@@ -15,10 +15,95 @@ ...@@ -15,10 +15,95 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/gfp.h> #include <linux/gfp.h>
static void devm_gpiod_release(struct device *dev, void *res)
{
struct gpio_desc **desc = res;
gpiod_put(*desc);
}
static int devm_gpiod_match(struct device *dev, void *res, void *data)
{
struct gpio_desc **this = res, **gpio = data;
return *this == *gpio;
}
/**
* devm_gpiod_get - Resource-managed gpiod_get()
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
*
* Managed gpiod_get(). GPIO descriptors returned from this function are
* automatically disposed on driver detach. See gpiod_get() for detailed
* information about behavior and return values.
*/
struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
const char *con_id)
{
return devm_gpiod_get_index(dev, con_id, 0);
}
EXPORT_SYMBOL(devm_gpiod_get);
/**
* devm_gpiod_get_index - Resource-managed gpiod_get_index()
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
* @idx: index of the GPIO to obtain in the consumer
*
* Managed gpiod_get_index(). GPIO descriptors returned from this function are
* automatically disposed on driver detach. See gpiod_get_index() for detailed
* information about behavior and return values.
*/
struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
const char *con_id,
unsigned int idx)
{
struct gpio_desc **dr;
struct gpio_desc *desc;
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *),
GFP_KERNEL);
if (!dr)
return ERR_PTR(-ENOMEM);
desc = gpiod_get_index(dev, con_id, idx);
if (IS_ERR(desc)) {
devres_free(dr);
return desc;
}
*dr = desc;
devres_add(dev, dr);
return desc;
}
EXPORT_SYMBOL(devm_gpiod_get_index);
/**
* devm_gpiod_put - Resource-managed gpiod_put()
* @desc: GPIO descriptor to dispose of
*
* Dispose of a GPIO descriptor obtained with devm_gpiod_get() or
* devm_gpiod_get_index(). Normally this function will not be called as the GPIO
* will be disposed of by the resource management code.
*/
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
{
WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match,
&desc));
}
EXPORT_SYMBOL(devm_gpiod_put);
static void devm_gpio_release(struct device *dev, void *res) static void devm_gpio_release(struct device *dev, void *res)
{ {
unsigned *gpio = res; unsigned *gpio = res;
......
...@@ -176,7 +176,6 @@ static int gen_74x164_probe(struct spi_device *spi) ...@@ -176,7 +176,6 @@ static int gen_74x164_probe(struct spi_device *spi)
return ret; return ret;
exit_destroy: exit_destroy:
spi_set_drvdata(spi, NULL);
mutex_destroy(&chip->lock); mutex_destroy(&chip->lock);
return ret; return ret;
} }
...@@ -190,8 +189,6 @@ static int gen_74x164_remove(struct spi_device *spi) ...@@ -190,8 +189,6 @@ static int gen_74x164_remove(struct spi_device *spi)
if (chip == NULL) if (chip == NULL)
return -ENODEV; return -ENODEV;
spi_set_drvdata(spi, NULL);
ret = gpiochip_remove(&chip->gpio_chip); ret = gpiochip_remove(&chip->gpio_chip);
if (!ret) if (!ret)
mutex_destroy(&chip->lock); mutex_destroy(&chip->lock);
...@@ -212,7 +209,7 @@ static struct spi_driver gen_74x164_driver = { ...@@ -212,7 +209,7 @@ static struct spi_driver gen_74x164_driver = {
.driver = { .driver = {
.name = "74x164", .name = "74x164",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(gen_74x164_dt_ids), .of_match_table = gen_74x164_dt_ids,
}, },
.probe = gen_74x164_probe, .probe = gen_74x164_probe,
.remove = gen_74x164_remove, .remove = gen_74x164_remove,
......
...@@ -325,9 +325,9 @@ static irqreturn_t adnp_irq(int irq, void *data) ...@@ -325,9 +325,9 @@ static irqreturn_t adnp_irq(int irq, void *data)
pending &= isr & ier; pending &= isr & ier;
for_each_set_bit(bit, &pending, 8) { for_each_set_bit(bit, &pending, 8) {
unsigned int virq; unsigned int child_irq;
virq = irq_find_mapping(adnp->domain, base + bit); child_irq = irq_find_mapping(adnp->domain, base + bit);
handle_nested_irq(virq); handle_nested_irq(child_irq);
} }
} }
...@@ -594,7 +594,7 @@ static struct i2c_driver adnp_i2c_driver = { ...@@ -594,7 +594,7 @@ static struct i2c_driver adnp_i2c_driver = {
.driver = { .driver = {
.name = "gpio-adnp", .name = "gpio-adnp",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(adnp_of_match), .of_match_table = adnp_of_match,
}, },
.probe = adnp_i2c_probe, .probe = adnp_i2c_probe,
.remove = adnp_i2c_remove, .remove = adnp_i2c_remove,
......
...@@ -109,10 +109,14 @@ static int arizona_gpio_probe(struct platform_device *pdev) ...@@ -109,10 +109,14 @@ static int arizona_gpio_probe(struct platform_device *pdev)
arizona_gpio->arizona = arizona; arizona_gpio->arizona = arizona;
arizona_gpio->gpio_chip = template_chip; arizona_gpio->gpio_chip = template_chip;
arizona_gpio->gpio_chip.dev = &pdev->dev; arizona_gpio->gpio_chip.dev = &pdev->dev;
#ifdef CONFIG_OF_GPIO
arizona_gpio->gpio_chip.of_node = arizona->dev->of_node;
#endif
switch (arizona->type) { switch (arizona->type) {
case WM5102: case WM5102:
case WM5110: case WM5110:
case WM8997:
arizona_gpio->gpio_chip.ngpio = 5; arizona_gpio->gpio_chip.ngpio = 5;
break; break;
default: default:
......
This diff is collapsed.
...@@ -228,7 +228,6 @@ static int bt8xxgpio_probe(struct pci_dev *dev, ...@@ -228,7 +228,6 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
err_release_mem: err_release_mem:
release_mem_region(pci_resource_start(dev, 0), release_mem_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0)); pci_resource_len(dev, 0));
pci_set_drvdata(dev, NULL);
err_disable: err_disable:
pci_disable_device(dev); pci_disable_device(dev);
err_freebg: err_freebg:
...@@ -252,7 +251,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev) ...@@ -252,7 +251,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev)
pci_resource_len(pdev, 0)); pci_resource_len(pdev, 0));
pci_disable_device(pdev); pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
kfree(bg); kfree(bg);
} }
......
...@@ -87,7 +87,7 @@ static struct platform_driver clps711x_gpio_driver = { ...@@ -87,7 +87,7 @@ static struct platform_driver clps711x_gpio_driver = {
.driver = { .driver = {
.name = "clps711x-gpio", .name = "clps711x-gpio",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(clps711x_gpio_ids), .of_match_table = clps711x_gpio_ids,
}, },
.probe = clps711x_gpio_probe, .probe = clps711x_gpio_probe,
.remove = clps711x_gpio_remove, .remove = clps711x_gpio_remove,
......
...@@ -232,16 +232,16 @@ static void em_gio_free(struct gpio_chip *chip, unsigned offset) ...@@ -232,16 +232,16 @@ static void em_gio_free(struct gpio_chip *chip, unsigned offset)
em_gio_direction_input(chip, offset); em_gio_direction_input(chip, offset);
} }
static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hwirq)
{ {
struct em_gio_priv *p = h->host_data; struct em_gio_priv *p = h->host_data;
pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq); pr_debug("gio: map hw irq = %d, irq = %d\n", (int)hwirq, irq);
irq_set_chip_data(virq, h->host_data); irq_set_chip_data(irq, h->host_data);
irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq);
set_irq_flags(virq, IRQF_VALID); /* kill me now */ set_irq_flags(irq, IRQF_VALID); /* kill me now */
return 0; return 0;
} }
...@@ -319,6 +319,7 @@ static int em_gio_probe(struct platform_device *pdev) ...@@ -319,6 +319,7 @@ static int em_gio_probe(struct platform_device *pdev)
} }
gpio_chip = &p->gpio_chip; gpio_chip = &p->gpio_chip;
gpio_chip->of_node = pdev->dev.of_node;
gpio_chip->direction_input = em_gio_direction_input; gpio_chip->direction_input = em_gio_direction_input;
gpio_chip->get = em_gio_get; gpio_chip->get = em_gio_get;
gpio_chip->direction_output = em_gio_direction_output; gpio_chip->direction_output = em_gio_direction_output;
......
...@@ -51,15 +51,15 @@ static void ep93xx_gpio_update_int_params(unsigned port) ...@@ -51,15 +51,15 @@ static void ep93xx_gpio_update_int_params(unsigned port)
{ {
BUG_ON(port > 2); BUG_ON(port > 2);
__raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
__raw_writeb(gpio_int_type2[port], writeb_relaxed(gpio_int_type2[port],
EP93XX_GPIO_REG(int_type2_register_offset[port])); EP93XX_GPIO_REG(int_type2_register_offset[port]));
__raw_writeb(gpio_int_type1[port], writeb_relaxed(gpio_int_type1[port],
EP93XX_GPIO_REG(int_type1_register_offset[port])); EP93XX_GPIO_REG(int_type1_register_offset[port]));
__raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
EP93XX_GPIO_REG(int_en_register_offset[port])); EP93XX_GPIO_REG(int_en_register_offset[port]));
} }
...@@ -74,7 +74,7 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) ...@@ -74,7 +74,7 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
else else
gpio_int_debounce[port] &= ~port_mask; gpio_int_debounce[port] &= ~port_mask;
__raw_writeb(gpio_int_debounce[port], writeb(gpio_int_debounce[port],
EP93XX_GPIO_REG(int_debounce_register_offset[port])); EP93XX_GPIO_REG(int_debounce_register_offset[port]));
} }
...@@ -83,7 +83,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -83,7 +83,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
unsigned char status; unsigned char status;
int i; int i;
status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); status = readb(EP93XX_GPIO_A_INT_STATUS);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (status & (1 << i)) { if (status & (1 << i)) {
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
...@@ -91,7 +91,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -91,7 +91,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
} }
} }
status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); status = readb(EP93XX_GPIO_B_INT_STATUS);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (status & (1 << i)) { if (status & (1 << i)) {
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
...@@ -124,7 +124,7 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d) ...@@ -124,7 +124,7 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d)
ep93xx_gpio_update_int_params(port); ep93xx_gpio_update_int_params(port);
} }
__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
} }
static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
...@@ -139,7 +139,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) ...@@ -139,7 +139,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
gpio_int_unmasked[port] &= ~port_mask; gpio_int_unmasked[port] &= ~port_mask;
ep93xx_gpio_update_int_params(port); ep93xx_gpio_update_int_params(port);
__raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
} }
static void ep93xx_gpio_irq_mask(struct irq_data *d) static void ep93xx_gpio_irq_mask(struct irq_data *d)
......
...@@ -16,42 +16,61 @@ ...@@ -16,42 +16,61 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/export.h> #include <linux/export.h>
#include <asm/hardware/iop3xx.h> #include <linux/platform_device.h>
#include <mach/gpio.h> #include <linux/bitops.h>
#include <linux/io.h>
void gpio_line_config(int line, int direction) #define IOP3XX_N_GPIOS 8
#define GPIO_IN 0
#define GPIO_OUT 1
#define GPIO_LOW 0
#define GPIO_HIGH 1
/* Memory base offset */
static void __iomem *base;
#define IOP3XX_GPIO_REG(reg) (base + (reg))
#define IOP3XX_GPOE IOP3XX_GPIO_REG(0x0000)
#define IOP3XX_GPID IOP3XX_GPIO_REG(0x0004)
#define IOP3XX_GPOD IOP3XX_GPIO_REG(0x0008)
static void gpio_line_config(int line, int direction)
{ {
unsigned long flags; unsigned long flags;
u32 val;
local_irq_save(flags); local_irq_save(flags);
val = readl(IOP3XX_GPOE);
if (direction == GPIO_IN) { if (direction == GPIO_IN) {
*IOP3XX_GPOE |= 1 << line; val |= BIT(line);
} else if (direction == GPIO_OUT) { } else if (direction == GPIO_OUT) {
*IOP3XX_GPOE &= ~(1 << line); val &= ~BIT(line);
} }
writel(val, IOP3XX_GPOE);
local_irq_restore(flags); local_irq_restore(flags);
} }
EXPORT_SYMBOL(gpio_line_config);
int gpio_line_get(int line) static int gpio_line_get(int line)
{ {
return !!(*IOP3XX_GPID & (1 << line)); return !!(readl(IOP3XX_GPID) & BIT(line));
} }
EXPORT_SYMBOL(gpio_line_get);
void gpio_line_set(int line, int value) static void gpio_line_set(int line, int value)
{ {
unsigned long flags; unsigned long flags;
u32 val;
local_irq_save(flags); local_irq_save(flags);
val = readl(IOP3XX_GPOD);
if (value == GPIO_LOW) { if (value == GPIO_LOW) {
*IOP3XX_GPOD &= ~(1 << line); val &= ~BIT(line);
} else if (value == GPIO_HIGH) { } else if (value == GPIO_HIGH) {
*IOP3XX_GPOD |= 1 << line; val |= BIT(line);
} }
writel(val, IOP3XX_GPOD);
local_irq_restore(flags); local_irq_restore(flags);
} }
EXPORT_SYMBOL(gpio_line_set);
static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{ {
...@@ -86,8 +105,26 @@ static struct gpio_chip iop3xx_chip = { ...@@ -86,8 +105,26 @@ static struct gpio_chip iop3xx_chip = {
.ngpio = IOP3XX_N_GPIOS, .ngpio = IOP3XX_N_GPIOS,
}; };
static int __init iop3xx_gpio_setup(void) static int iop3xx_gpio_probe(struct platform_device *pdev)
{ {
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
return gpiochip_add(&iop3xx_chip); return gpiochip_add(&iop3xx_chip);
} }
arch_initcall(iop3xx_gpio_setup);
static struct platform_driver iop3xx_gpio_driver = {
.driver = {
.name = "gpio-iop",
.owner = THIS_MODULE,
},
.probe = iop3xx_gpio_probe,
};
static int __init iop3xx_gpio_init(void)
{
return platform_driver_register(&iop3xx_gpio_driver);
}
arch_initcall(iop3xx_gpio_init);
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#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.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -242,14 +242,13 @@ static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) ...@@ -242,14 +242,13 @@ static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return irq_create_mapping(lg->domain, offset); return irq_create_mapping(lg->domain, offset);
} }
static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc)
{ {
struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_data *data = irq_desc_get_irq_data(desc);
struct lp_gpio *lg = irq_data_get_irq_handler_data(data); struct lp_gpio *lg = irq_data_get_irq_handler_data(data);
struct irq_chip *chip = irq_data_get_irq_chip(data); struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, pin, mask; u32 base, pin, mask;
unsigned long reg, ena, pending; unsigned long reg, ena, pending;
unsigned virq;
/* check from GPIO controller which pin triggered the interrupt */ /* check from GPIO controller which pin triggered the interrupt */
for (base = 0; base < lg->chip.ngpio; base += 32) { for (base = 0; base < lg->chip.ngpio; base += 32) {
...@@ -257,12 +256,14 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) ...@@ -257,12 +256,14 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
while ((pending = (inl(reg) & inl(ena)))) { while ((pending = (inl(reg) & inl(ena)))) {
unsigned irq;
pin = __ffs(pending); pin = __ffs(pending);
mask = BIT(pin); mask = BIT(pin);
/* Clear before handling so we don't lose an edge */ /* Clear before handling so we don't lose an edge */
outl(mask, reg); outl(mask, reg);
virq = irq_find_mapping(lg->domain, base + pin); irq = irq_find_mapping(lg->domain, base + pin);
generic_handle_irq(virq); generic_handle_irq(irq);
} }
} }
chip->irq_eoi(data); chip->irq_eoi(data);
...@@ -325,15 +326,15 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg) ...@@ -325,15 +326,15 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg)
} }
} }
static int lp_gpio_irq_map(struct irq_domain *d, unsigned int virq, static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hwirq)
{ {
struct lp_gpio *lg = d->host_data; struct lp_gpio *lg = d->host_data;
irq_set_chip_and_handler_name(virq, &lp_irqchip, handle_simple_irq, irq_set_chip_and_handler_name(irq, &lp_irqchip, handle_simple_irq,
"demux"); "demux");
irq_set_chip_data(virq, lg); irq_set_chip_data(irq, lg);
irq_set_irq_type(virq, IRQ_TYPE_NONE); irq_set_irq_type(irq, IRQ_TYPE_NONE);
return 0; return 0;
} }
......
...@@ -142,7 +142,6 @@ static int mc33880_probe(struct spi_device *spi) ...@@ -142,7 +142,6 @@ static int mc33880_probe(struct spi_device *spi)
return ret; return ret;
exit_destroy: exit_destroy:
spi_set_drvdata(spi, NULL);
mutex_destroy(&mc->lock); mutex_destroy(&mc->lock);
return ret; return ret;
} }
...@@ -156,8 +155,6 @@ static int mc33880_remove(struct spi_device *spi) ...@@ -156,8 +155,6 @@ static int mc33880_remove(struct spi_device *spi)
if (mc == NULL) if (mc == NULL)
return -ENODEV; return -ENODEV;
spi_set_drvdata(spi, NULL);
ret = gpiochip_remove(&mc->chip); ret = gpiochip_remove(&mc->chip);
if (!ret) if (!ret)
mutex_destroy(&mc->lock); mutex_destroy(&mc->lock);
......
...@@ -282,16 +282,16 @@ static struct irq_chip mpc8xxx_irq_chip = { ...@@ -282,16 +282,16 @@ static struct irq_chip mpc8xxx_irq_chip = {
.irq_set_type = mpc8xxx_irq_set_type, .irq_set_type = mpc8xxx_irq_set_type,
}; };
static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hwirq)
{ {
struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
if (mpc8xxx_gc->of_dev_id_data) if (mpc8xxx_gc->of_dev_id_data)
mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;
irq_set_chip_data(virq, h->host_data); irq_set_chip_data(irq, h->host_data);
irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq);
return 0; return 0;
} }
......
...@@ -254,7 +254,6 @@ static int mxs_gpio_probe(struct platform_device *pdev) ...@@ -254,7 +254,6 @@ static int mxs_gpio_probe(struct platform_device *pdev)
struct device_node *parent; struct device_node *parent;
static void __iomem *base; static void __iomem *base;
struct mxs_gpio_port *port; struct mxs_gpio_port *port;
struct resource *iores = NULL;
int irq_base; int irq_base;
int err; int err;
...@@ -262,16 +261,10 @@ static int mxs_gpio_probe(struct platform_device *pdev) ...@@ -262,16 +261,10 @@ static int mxs_gpio_probe(struct platform_device *pdev)
if (!port) if (!port)
return -ENOMEM; return -ENOMEM;
if (np) { port->id = of_alias_get_id(np, "gpio");
port->id = of_alias_get_id(np, "gpio"); if (port->id < 0)
if (port->id < 0) return port->id;
return port->id; port->devid = (enum mxs_gpio_id) of_id->data;
port->devid = (enum mxs_gpio_id) of_id->data;
} else {
port->id = pdev->id;
port->devid = pdev->id_entry->driver_data;
}
port->irq = platform_get_irq(pdev, 0); port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0) if (port->irq < 0)
return port->irq; return port->irq;
...@@ -281,18 +274,11 @@ static int mxs_gpio_probe(struct platform_device *pdev) ...@@ -281,18 +274,11 @@ static int mxs_gpio_probe(struct platform_device *pdev)
* share the same one * share the same one
*/ */
if (!base) { if (!base) {
if (np) { parent = of_get_parent(np);
parent = of_get_parent(np); base = of_iomap(parent, 0);
base = of_iomap(parent, 0); of_node_put(parent);
of_node_put(parent); if (!base)
if (!base) return -EADDRNOTAVAIL;
return -EADDRNOTAVAIL;
} else {
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(base))
return PTR_ERR(base);
}
} }
port->base = base; port->base = base;
......
...@@ -514,6 +514,14 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) ...@@ -514,6 +514,14 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
return -EINVAL; return -EINVAL;
} }
retval = gpio_lock_as_irq(&bank->chip, offset);
if (retval) {
dev_err(bank->dev, "unable to lock offset %d for IRQ\n",
offset);
spin_unlock_irqrestore(&bank->lock, flags);
return retval;
}
bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio);
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
...@@ -797,6 +805,7 @@ static void gpio_irq_shutdown(struct irq_data *d) ...@@ -797,6 +805,7 @@ static void gpio_irq_shutdown(struct irq_data *d)
unsigned offset = GPIO_INDEX(bank, gpio); unsigned offset = GPIO_INDEX(bank, gpio);
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
gpio_unlock_as_irq(&bank->chip, offset);
bank->irq_usage &= ~(1 << offset); bank->irq_usage &= ~(1 << offset);
_disable_gpio_module(bank, offset); _disable_gpio_module(bank, offset);
_reset_gpio(bank, gpio); _reset_gpio(bank, gpio);
...@@ -957,22 +966,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) ...@@ -957,22 +966,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
{ {
struct gpio_bank *bank; struct gpio_bank *bank;
unsigned long flags; unsigned long flags;
int retval = 0;
bank = container_of(chip, struct gpio_bank, chip); bank = container_of(chip, struct gpio_bank, chip);
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
if (LINE_USED(bank->irq_usage, offset)) {
retval = -EINVAL;
goto exit;
}
bank->set_dataout(bank, offset, value); bank->set_dataout(bank, offset, value);
_set_gpio_direction(bank, offset, 0); _set_gpio_direction(bank, offset, 0);
exit:
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
return retval; return 0;
} }
static int gpio_debounce(struct gpio_chip *chip, unsigned offset, static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
......
...@@ -31,6 +31,10 @@ struct palmas_gpio { ...@@ -31,6 +31,10 @@ struct palmas_gpio {
struct palmas *palmas; struct palmas *palmas;
}; };
struct palmas_device_data {
int ngpio;
};
static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip) static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
{ {
return container_of(chip, struct palmas_gpio, gpio_chip); return container_of(chip, struct palmas_gpio, gpio_chip);
...@@ -42,23 +46,26 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) ...@@ -42,23 +46,26 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
struct palmas *palmas = pg->palmas; struct palmas *palmas = pg->palmas;
unsigned int val; unsigned int val;
int ret; int ret;
unsigned int reg;
int gpio16 = (offset/8);
offset %= 8;
reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_DIR, &val); ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
if (ret < 0) { if (ret < 0) {
dev_err(gc->dev, "GPIO_DATA_DIR read failed, err = %d\n", ret); dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
return ret; return ret;
} }
if (val & (1 << offset)) { if (val & BIT(offset))
ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT;
PALMAS_GPIO_DATA_OUT, &val); else
} else { reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN;
ret = palmas_read(palmas, PALMAS_GPIO_BASE,
PALMAS_GPIO_DATA_IN, &val); ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
}
if (ret < 0) { if (ret < 0) {
dev_err(gc->dev, "GPIO_DATA_IN/OUT read failed, err = %d\n", dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
ret);
return ret; return ret;
} }
return !!(val & BIT(offset)); return !!(val & BIT(offset));
...@@ -70,17 +77,20 @@ static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset, ...@@ -70,17 +77,20 @@ static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas; struct palmas *palmas = pg->palmas;
int ret; int ret;
unsigned int reg;
int gpio16 = (offset/8);
if (value) offset %= 8;
ret = palmas_write(palmas, PALMAS_GPIO_BASE, if (gpio16)
PALMAS_GPIO_SET_DATA_OUT, BIT(offset)); reg = (value) ?
PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2;
else else
ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg = (value) ?
PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset)); PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT;
ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset));
if (ret < 0) if (ret < 0)
dev_err(gc->dev, "%s write failed, err = %d\n", dev_err(gc->dev, "Reg 0x%02x write failed, %d\n", reg, ret);
(value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT",
ret);
} }
static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
...@@ -89,14 +99,19 @@ static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, ...@@ -89,14 +99,19 @@ static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas; struct palmas *palmas = pg->palmas;
int ret; int ret;
unsigned int reg;
int gpio16 = (offset/8);
offset %= 8;
reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
/* Set the initial value */ /* Set the initial value */
palmas_gpio_set(gc, offset, value); palmas_gpio_set(gc, offset, value);
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg,
PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset)); BIT(offset), BIT(offset));
if (ret < 0) if (ret < 0)
dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
return ret; return ret;
} }
...@@ -105,11 +120,15 @@ static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) ...@@ -105,11 +120,15 @@ static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas_gpio *pg = to_palmas_gpio(gc);
struct palmas *palmas = pg->palmas; struct palmas *palmas = pg->palmas;
int ret; int ret;
unsigned int reg;
int gpio16 = (offset/8);
offset %= 8;
reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);
PALMAS_GPIO_DATA_DIR, BIT(offset), 0);
if (ret < 0) if (ret < 0)
dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
return ret; return ret;
} }
...@@ -121,12 +140,36 @@ static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset) ...@@ -121,12 +140,36 @@ static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset); return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
} }
static const struct palmas_device_data palmas_dev_data = {
.ngpio = 8,
};
static const struct palmas_device_data tps80036_dev_data = {
.ngpio = 16,
};
static struct of_device_id of_palmas_gpio_match[] = {
{ .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,},
{ .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,},
{ .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,},
{ .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,},
{ },
};
MODULE_DEVICE_TABLE(of, of_palmas_gpio_match);
static int palmas_gpio_probe(struct platform_device *pdev) static int palmas_gpio_probe(struct platform_device *pdev)
{ {
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
struct palmas_platform_data *palmas_pdata; struct palmas_platform_data *palmas_pdata;
struct palmas_gpio *palmas_gpio; struct palmas_gpio *palmas_gpio;
int ret; int ret;
const struct of_device_id *match;
const struct palmas_device_data *dev_data;
match = of_match_device(of_palmas_gpio_match, &pdev->dev);
dev_data = match->data;
if (!dev_data)
dev_data = &palmas_dev_data;
palmas_gpio = devm_kzalloc(&pdev->dev, palmas_gpio = devm_kzalloc(&pdev->dev,
sizeof(*palmas_gpio), GFP_KERNEL); sizeof(*palmas_gpio), GFP_KERNEL);
...@@ -138,7 +181,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) ...@@ -138,7 +181,7 @@ static int palmas_gpio_probe(struct platform_device *pdev)
palmas_gpio->palmas = palmas; palmas_gpio->palmas = palmas;
palmas_gpio->gpio_chip.owner = THIS_MODULE; palmas_gpio->gpio_chip.owner = THIS_MODULE;
palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
palmas_gpio->gpio_chip.ngpio = 8; palmas_gpio->gpio_chip.ngpio = dev_data->ngpio;
palmas_gpio->gpio_chip.can_sleep = 1; palmas_gpio->gpio_chip.can_sleep = 1;
palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
...@@ -172,15 +215,6 @@ static int palmas_gpio_remove(struct platform_device *pdev) ...@@ -172,15 +215,6 @@ static int palmas_gpio_remove(struct platform_device *pdev)
return gpiochip_remove(&palmas_gpio->gpio_chip); return gpiochip_remove(&palmas_gpio->gpio_chip);
} }
static struct of_device_id of_palmas_gpio_match[] = {
{ .compatible = "ti,palmas-gpio"},
{ .compatible = "ti,tps65913-gpio"},
{ .compatible = "ti,tps65914-gpio"},
{ .compatible = "ti,tps80036-gpio"},
{ },
};
MODULE_DEVICE_TABLE(of, of_palmas_gpio_match);
static struct platform_driver palmas_gpio_driver = { static struct platform_driver palmas_gpio_driver = {
.driver.name = "palmas-gpio", .driver.name = "palmas-gpio",
.driver.owner = THIS_MODULE, .driver.owner = THIS_MODULE,
......
...@@ -683,17 +683,6 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) ...@@ -683,17 +683,6 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
int ret; int ret;
u8 val[MAX_BANK]; u8 val[MAX_BANK];
/* Let every port in proper state, that could save power */
memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_PUPD, val);
memset(val, 0xFF, NBANK(chip));
pca953x_write_regs(chip, PCA957X_CFG, val);
memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_OUT, val);
ret = pca953x_read_regs(chip, PCA957X_IN, val);
if (ret)
goto out;
ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output); ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
if (ret) if (ret)
goto out; goto out;
......
...@@ -26,9 +26,10 @@ ...@@ -26,9 +26,10 @@
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/workqueue.h>
static const struct i2c_device_id pcf857x_id[] = { static const struct i2c_device_id pcf857x_id[] = {
...@@ -50,6 +51,27 @@ static const struct i2c_device_id pcf857x_id[] = { ...@@ -50,6 +51,27 @@ static const struct i2c_device_id pcf857x_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, pcf857x_id); MODULE_DEVICE_TABLE(i2c, pcf857x_id);
#ifdef CONFIG_OF
static const struct of_device_id pcf857x_of_table[] = {
{ .compatible = "nxp,pcf8574" },
{ .compatible = "nxp,pcf8574a" },
{ .compatible = "nxp,pca8574" },
{ .compatible = "nxp,pca9670" },
{ .compatible = "nxp,pca9672" },
{ .compatible = "nxp,pca9674" },
{ .compatible = "nxp,pcf8575" },
{ .compatible = "nxp,pca8575" },
{ .compatible = "nxp,pca9671" },
{ .compatible = "nxp,pca9673" },
{ .compatible = "nxp,pca9675" },
{ .compatible = "maxim,max7328" },
{ .compatible = "maxim,max7329" },
{ .compatible = "ti,tca9554" },
{ }
};
MODULE_DEVICE_TABLE(of, pcf857x_of_table);
#endif
/* /*
* The pcf857x, pca857x, and pca967x chips only expose one read and one * The pcf857x, pca857x, and pca967x chips only expose one read and one
* write register. Writing a "one" bit (to match the reset state) lets * write register. Writing a "one" bit (to match the reset state) lets
...@@ -66,12 +88,11 @@ struct pcf857x { ...@@ -66,12 +88,11 @@ struct pcf857x {
struct gpio_chip chip; struct gpio_chip chip;
struct i2c_client *client; struct i2c_client *client;
struct mutex lock; /* protect 'out' */ struct mutex lock; /* protect 'out' */
struct work_struct work; /* irq demux work */
struct irq_domain *irq_domain; /* for irq demux */ struct irq_domain *irq_domain; /* for irq demux */
spinlock_t slock; /* protect irq demux */ spinlock_t slock; /* protect irq demux */
unsigned out; /* software latch */ unsigned out; /* software latch */
unsigned status; /* current status */ unsigned status; /* current status */
int irq; /* real irq number */ unsigned irq_mapped; /* mapped gpio irqs */
int (*write)(struct i2c_client *client, unsigned data); int (*write)(struct i2c_client *client, unsigned data);
int (*read)(struct i2c_client *client); int (*read)(struct i2c_client *client);
...@@ -164,48 +185,54 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) ...@@ -164,48 +185,54 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
int ret;
return irq_create_mapping(gpio->irq_domain, offset); ret = irq_create_mapping(gpio->irq_domain, offset);
if (ret > 0)
gpio->irq_mapped |= (1 << offset);
return ret;
} }
static void pcf857x_irq_demux_work(struct work_struct *work) static irqreturn_t pcf857x_irq(int irq, void *data)
{ {
struct pcf857x *gpio = container_of(work, struct pcf857x *gpio = data;
struct pcf857x,
work);
unsigned long change, i, status, flags; unsigned long change, i, status, flags;
status = gpio->read(gpio->client); status = gpio->read(gpio->client);
spin_lock_irqsave(&gpio->slock, flags); spin_lock_irqsave(&gpio->slock, flags);
change = gpio->status ^ status; /*
* call the interrupt handler iff gpio is used as
* interrupt source, just to avoid bad irqs
*/
change = ((gpio->status ^ status) & gpio->irq_mapped);
for_each_set_bit(i, &change, gpio->chip.ngpio) for_each_set_bit(i, &change, gpio->chip.ngpio)
generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); generic_handle_irq(irq_find_mapping(gpio->irq_domain, i));
gpio->status = status; gpio->status = status;
spin_unlock_irqrestore(&gpio->slock, flags); spin_unlock_irqrestore(&gpio->slock, flags);
}
static irqreturn_t pcf857x_irq_demux(int irq, void *data)
{
struct pcf857x *gpio = data;
/*
* pcf857x can't read/write data here,
* since i2c data access might go to sleep.
*/
schedule_work(&gpio->work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq, static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hw)
{ {
irq_set_chip_and_handler(virq, struct pcf857x *gpio = domain->host_data;
irq_set_chip_and_handler(irq,
&dummy_irq_chip, &dummy_irq_chip,
handle_level_irq); handle_level_irq);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
irq_set_noprobe(irq);
#endif
gpio->irq_mapped |= (1 << hw);
return 0; return 0;
} }
...@@ -218,8 +245,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) ...@@ -218,8 +245,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio)
if (gpio->irq_domain) if (gpio->irq_domain)
irq_domain_remove(gpio->irq_domain); irq_domain_remove(gpio->irq_domain);
if (gpio->irq)
free_irq(gpio->irq, gpio);
} }
static int pcf857x_irq_domain_init(struct pcf857x *gpio, static int pcf857x_irq_domain_init(struct pcf857x *gpio,
...@@ -230,20 +255,21 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, ...@@ -230,20 +255,21 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio,
gpio->irq_domain = irq_domain_add_linear(client->dev.of_node, gpio->irq_domain = irq_domain_add_linear(client->dev.of_node,
gpio->chip.ngpio, gpio->chip.ngpio,
&pcf857x_irq_domain_ops, &pcf857x_irq_domain_ops,
NULL); gpio);
if (!gpio->irq_domain) if (!gpio->irq_domain)
goto fail; goto fail;
/* enable real irq */ /* enable real irq */
status = request_irq(client->irq, pcf857x_irq_demux, 0, status = devm_request_threaded_irq(&client->dev, client->irq,
dev_name(&client->dev), gpio); NULL, pcf857x_irq, IRQF_ONESHOT |
IRQF_TRIGGER_FALLING,
dev_name(&client->dev), gpio);
if (status) if (status)
goto fail; goto fail;
/* enable gpio_to_irq() */ /* enable gpio_to_irq() */
INIT_WORK(&gpio->work, pcf857x_irq_demux_work);
gpio->chip.to_irq = pcf857x_to_irq; gpio->chip.to_irq = pcf857x_to_irq;
gpio->irq = client->irq;
return 0; return 0;
...@@ -257,14 +283,18 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, ...@@ -257,14 +283,18 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio,
static int pcf857x_probe(struct i2c_client *client, static int pcf857x_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct pcf857x_platform_data *pdata; struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct pcf857x *gpio; struct pcf857x *gpio;
unsigned int n_latch = 0;
int status; int status;
pdata = dev_get_platdata(&client->dev); if (IS_ENABLED(CONFIG_OF) && np)
if (!pdata) { of_property_read_u32(np, "lines-initial-states", &n_latch);
else if (pdata)
n_latch = pdata->n_latch;
else
dev_dbg(&client->dev, "no platform data\n"); dev_dbg(&client->dev, "no platform data\n");
}
/* Allocate, initialize, and register this gpio_chip. */ /* Allocate, initialize, and register this gpio_chip. */
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
...@@ -357,11 +387,11 @@ static int pcf857x_probe(struct i2c_client *client, ...@@ -357,11 +387,11 @@ static int pcf857x_probe(struct i2c_client *client,
* may cause transient glitching since it can't know the last value * may cause transient glitching since it can't know the last value
* written (some pins may need to be driven low). * written (some pins may need to be driven low).
* *
* Using pdata->n_latch avoids that trouble. When left initialized * Using n_latch avoids that trouble. When left initialized to zero,
* to zero, our software copy of the "latch" then matches the chip's * our software copy of the "latch" then matches the chip's all-ones
* all-ones reset state. Otherwise it flags pins to be driven low. * reset state. Otherwise it flags pins to be driven low.
*/ */
gpio->out = pdata ? ~pdata->n_latch : ~0; gpio->out = ~n_latch;
gpio->status = gpio->out; gpio->status = gpio->out;
status = gpiochip_add(&gpio->chip); status = gpiochip_add(&gpio->chip);
...@@ -423,6 +453,7 @@ static struct i2c_driver pcf857x_driver = { ...@@ -423,6 +453,7 @@ static struct i2c_driver pcf857x_driver = {
.driver = { .driver = {
.name = "pcf857x", .name = "pcf857x",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcf857x_of_table),
}, },
.probe = pcf857x_probe, .probe = pcf857x_probe,
.remove = pcf857x_remove, .remove = pcf857x_remove,
......
...@@ -238,15 +238,15 @@ static struct irq_chip pl061_irqchip = { ...@@ -238,15 +238,15 @@ static struct irq_chip pl061_irqchip = {
.irq_set_type = pl061_irq_type, .irq_set_type = pl061_irq_type,
}; };
static int pl061_irq_map(struct irq_domain *d, unsigned int virq, static int pl061_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hwirq)
{ {
struct pl061_gpio *chip = d->host_data; struct pl061_gpio *chip = d->host_data;
irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq, irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq,
"pl061"); "pl061");
irq_set_chip_data(virq, chip); irq_set_chip_data(irq, chip);
irq_set_irq_type(virq, IRQ_TYPE_NONE); irq_set_irq_type(irq, IRQ_TYPE_NONE);
return 0; return 0;
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_data/gpio-rcar.h> #include <linux/platform_data/gpio-rcar.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -266,16 +267,16 @@ static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset) ...@@ -266,16 +267,16 @@ static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset)
return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
} }
static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int virq, static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq,
irq_hw_number_t hw) irq_hw_number_t hwirq)
{ {
struct gpio_rcar_priv *p = h->host_data; struct gpio_rcar_priv *p = h->host_data;
dev_dbg(&p->pdev->dev, "map hw irq = %d, virq = %d\n", (int)hw, virq); dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq);
irq_set_chip_data(virq, h->host_data); irq_set_chip_data(irq, h->host_data);
irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq);
set_irq_flags(virq, IRQF_VALID); /* kill me now */ set_irq_flags(irq, IRQF_VALID); /* kill me now */
return 0; return 0;
} }
......
...@@ -254,9 +254,10 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) ...@@ -254,9 +254,10 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
while (stat) { while (stat) {
int bit = __ffs(stat); int bit = __ffs(stat);
int line = bank * 8 + bit; int line = bank * 8 + bit;
int virq = irq_find_mapping(stmpe_gpio->domain, line); int child_irq = irq_find_mapping(stmpe_gpio->domain,
line);
handle_nested_irq(virq); handle_nested_irq(child_irq);
stat &= ~(1 << bit); stat &= ~(1 << bit);
} }
...@@ -271,7 +272,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) ...@@ -271,7 +272,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
struct stmpe_gpio *stmpe_gpio = d->host_data; struct stmpe_gpio *stmpe_gpio = d->host_data;
...@@ -279,26 +280,26 @@ static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, ...@@ -279,26 +280,26 @@ static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
if (!stmpe_gpio) if (!stmpe_gpio)
return -EINVAL; return -EINVAL;
irq_set_chip_data(hwirq, stmpe_gpio); irq_set_chip_data(irq, stmpe_gpio);
irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip, irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
handle_simple_irq); handle_simple_irq);
irq_set_nested_thread(hwirq, 1); irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM #ifdef CONFIG_ARM
set_irq_flags(hwirq, IRQF_VALID); set_irq_flags(irq, IRQF_VALID);
#else #else
irq_set_noprobe(hwirq); irq_set_noprobe(irq);
#endif #endif
return 0; return 0;
} }
static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
{ {
#ifdef CONFIG_ARM #ifdef CONFIG_ARM
set_irq_flags(virq, 0); set_irq_flags(irq, 0);
#endif #endif
irq_set_chip_and_handler(virq, NULL, NULL); irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(virq, NULL); irq_set_chip_data(irq, NULL);
} }
static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
......
...@@ -96,27 +96,27 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, ...@@ -96,27 +96,27 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
} }
/** /**
* tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ
* *
* @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on.
* @irq: index of the interrupt requested in the chip IRQs * @irq: index of the hardware interrupt requested in the chip IRQs
* *
* Useful for drivers to request their own IRQs. * Useful for drivers to request their own IRQs.
*/ */
static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio, static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio,
int irq) int hwirq)
{ {
if (!tc3589x_gpio) if (!tc3589x_gpio)
return -EINVAL; return -EINVAL;
return irq_create_mapping(tc3589x_gpio->domain, irq); return irq_create_mapping(tc3589x_gpio->domain, hwirq);
} }
static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{ {
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset); return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset);
} }
static struct gpio_chip template_chip = { static struct gpio_chip template_chip = {
...@@ -242,9 +242,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) ...@@ -242,9 +242,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
while (stat) { while (stat) {
int bit = __ffs(stat); int bit = __ffs(stat);
int line = i * 8 + bit; int line = i * 8 + bit;
int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line); int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line);
handle_nested_irq(virq); handle_nested_irq(irq);
stat &= ~(1 << bit); stat &= ~(1 << bit);
} }
...@@ -254,31 +254,31 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) ...@@ -254,31 +254,31 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq, static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
struct tc3589x *tc3589x_gpio = d->host_data; struct tc3589x *tc3589x_gpio = d->host_data;
irq_set_chip_data(virq, tc3589x_gpio); irq_set_chip_data(irq, tc3589x_gpio);
irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip, irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
handle_simple_irq); handle_simple_irq);
irq_set_nested_thread(virq, 1); irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM #ifdef CONFIG_ARM
set_irq_flags(virq, IRQF_VALID); set_irq_flags(irq, IRQF_VALID);
#else #else
irq_set_noprobe(virq); irq_set_noprobe(irq);
#endif #endif
return 0; return 0;
} }
static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
{ {
#ifdef CONFIG_ARM #ifdef CONFIG_ARM
set_irq_flags(virq, 0); set_irq_flags(irq, 0);
#endif #endif
irq_set_chip_and_handler(virq, NULL, NULL); irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(virq, NULL); irq_set_chip_data(irq, NULL);
} }
static struct irq_domain_ops tc3589x_irq_ops = { static struct irq_domain_ops tc3589x_irq_ops = {
......
...@@ -75,6 +75,7 @@ struct tegra_gpio_bank { ...@@ -75,6 +75,7 @@ struct tegra_gpio_bank {
#endif #endif
}; };
static struct device *dev;
static struct irq_domain *irq_domain; static struct irq_domain *irq_domain;
static void __iomem *regs; static void __iomem *regs;
static u32 tegra_gpio_bank_count; static u32 tegra_gpio_bank_count;
...@@ -205,6 +206,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -205,6 +206,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
int lvl_type; int lvl_type;
int val; int val;
unsigned long flags; unsigned long flags;
int ret;
switch (type & IRQ_TYPE_SENSE_MASK) { switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_RISING:
...@@ -231,6 +233,12 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -231,6 +233,12 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL; return -EINVAL;
} }
ret = gpio_lock_as_irq(&tegra_gpio_chip, gpio);
if (ret) {
dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio);
return ret;
}
spin_lock_irqsave(&bank->lvl_lock[port], flags); spin_lock_irqsave(&bank->lvl_lock[port], flags);
val = tegra_gpio_readl(GPIO_INT_LVL(gpio)); val = tegra_gpio_readl(GPIO_INT_LVL(gpio));
...@@ -251,6 +259,13 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -251,6 +259,13 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return 0; return 0;
} }
static void tegra_gpio_irq_shutdown(struct irq_data *d)
{
int gpio = d->hwirq;
gpio_unlock_as_irq(&tegra_gpio_chip, gpio);
}
static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{ {
struct tegra_gpio_bank *bank; struct tegra_gpio_bank *bank;
...@@ -368,6 +383,7 @@ static struct irq_chip tegra_gpio_irq_chip = { ...@@ -368,6 +383,7 @@ static struct irq_chip tegra_gpio_irq_chip = {
.irq_mask = tegra_gpio_irq_mask, .irq_mask = tegra_gpio_irq_mask,
.irq_unmask = tegra_gpio_irq_unmask, .irq_unmask = tegra_gpio_irq_unmask,
.irq_set_type = tegra_gpio_irq_set_type, .irq_set_type = tegra_gpio_irq_set_type,
.irq_shutdown = tegra_gpio_irq_shutdown,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.irq_set_wake = tegra_gpio_irq_set_wake, .irq_set_wake = tegra_gpio_irq_set_wake,
#endif #endif
...@@ -413,6 +429,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) ...@@ -413,6 +429,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
int i; int i;
int j; int j;
dev = &pdev->dev;
match = of_match_device(tegra_gpio_of_match, &pdev->dev); match = of_match_device(tegra_gpio_of_match, &pdev->dev);
if (!match) { if (!match) {
dev_err(&pdev->dev, "Error: No device match found\n"); dev_err(&pdev->dev, "Error: No device match found\n");
......
...@@ -594,7 +594,7 @@ static struct platform_driver gpio_twl4030_driver = { ...@@ -594,7 +594,7 @@ static struct platform_driver gpio_twl4030_driver = {
.driver = { .driver = {
.name = "twl4030_gpio", .name = "twl4030_gpio",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(twl_gpio_match), .of_match_table = twl_gpio_match,
}, },
.probe = gpio_twl4030_probe, .probe = gpio_twl4030_probe,
.remove = gpio_twl4030_remove, .remove = gpio_twl4030_remove,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio.h> #include <linux/gpio/consumer.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/acpi_gpio.h> #include <linux/acpi_gpio.h>
#include <linux/acpi.h> #include <linux/acpi.h>
...@@ -33,14 +33,15 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) ...@@ -33,14 +33,15 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
} }
/** /**
* acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
* @pin: ACPI GPIO pin number (0-based, controller-relative) * @pin: ACPI GPIO pin number (0-based, controller-relative)
* *
* Returns GPIO number to use with Linux generic GPIO API, or errno error value * Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
* error value
*/ */
int acpi_get_gpio(char *path, int pin) static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
acpi_handle handle; acpi_handle handle;
...@@ -48,18 +49,17 @@ int acpi_get_gpio(char *path, int pin) ...@@ -48,18 +49,17 @@ int acpi_get_gpio(char *path, int pin)
status = acpi_get_handle(NULL, path, &handle); status = acpi_get_handle(NULL, path, &handle);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -ENODEV; return ERR_PTR(-ENODEV);
chip = gpiochip_find(handle, acpi_gpiochip_find); chip = gpiochip_find(handle, acpi_gpiochip_find);
if (!chip) if (!chip)
return -ENODEV; return ERR_PTR(-ENODEV);
if (!gpio_is_valid(chip->base + pin)) if (pin < 0 || pin > chip->ngpio)
return -EINVAL; return ERR_PTR(-EINVAL);
return chip->base + pin; return gpio_to_desc(chip->base + pin);
} }
EXPORT_SYMBOL_GPL(acpi_get_gpio);
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{ {
...@@ -73,15 +73,8 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) ...@@ -73,15 +73,8 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
{ {
struct acpi_gpio_evt_pin *evt_pin = data; struct acpi_gpio_evt_pin *evt_pin = data;
struct acpi_object_list args;
union acpi_object arg;
arg.type = ACPI_TYPE_INTEGER; acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin);
arg.integer.value = evt_pin->pin;
args.count = 1;
args.pointer = &arg;
acpi_evaluate_object(evt_pin->evt_handle, NULL, &args, NULL);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -201,10 +194,48 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) ...@@ -201,10 +194,48 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
} }
EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); EXPORT_SYMBOL(acpi_gpiochip_request_interrupts);
/**
* acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts.
* @chip: gpio chip
*
* Free interrupts associated with the _EVT method for the given GPIO chip.
*
* The remaining ACPI event interrupts associated with the chip are freed
* automatically.
*/
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
{
acpi_handle handle;
acpi_status status;
struct list_head *evt_pins;
struct acpi_gpio_evt_pin *evt_pin, *ep;
if (!chip->dev || !chip->to_irq)
return;
handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;
status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins);
if (ACPI_FAILURE(status))
return;
list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) {
devm_free_irq(chip->dev, evt_pin->irq, evt_pin);
list_del(&evt_pin->node);
kfree(evt_pin);
}
acpi_detach_data(handle, acpi_gpio_evt_dh);
kfree(evt_pins);
}
EXPORT_SYMBOL(acpi_gpiochip_free_interrupts);
struct acpi_gpio_lookup { struct acpi_gpio_lookup {
struct acpi_gpio_info info; struct acpi_gpio_info info;
int index; int index;
int gpio; struct gpio_desc *desc;
int n; int n;
}; };
...@@ -215,37 +246,39 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data) ...@@ -215,37 +246,39 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
if (ares->type != ACPI_RESOURCE_TYPE_GPIO) if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
return 1; return 1;
if (lookup->n++ == lookup->index && lookup->gpio < 0) { if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio; const struct acpi_resource_gpio *agpio = &ares->data.gpio;
lookup->gpio = acpi_get_gpio(agpio->resource_source.string_ptr, lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
agpio->pin_table[0]); agpio->pin_table[0]);
lookup->info.gpioint = lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
lookup->info.active_low =
agpio->polarity == ACPI_ACTIVE_LOW;
} }
return 1; return 1;
} }
/** /**
* acpi_get_gpio_by_index() - get a GPIO number from device resources * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
* @dev: pointer to a device to get GPIO from * @dev: pointer to a device to get GPIO from
* @index: index of GpioIo/GpioInt resource (starting from %0) * @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional) * @info: info pointer to fill in (optional)
* *
* Function goes through ACPI resources for @dev and based on @index looks * Function goes through ACPI resources for @dev and based on @index looks
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO number, * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* and returns it. @index matches GpioIo/GpioInt resources only so if there * and returns it. @index matches GpioIo/GpioInt resources only so if there
* are total %3 GPIO resources, the index goes from %0 to %2. * are total %3 GPIO resources, the index goes from %0 to %2.
* *
* If the GPIO cannot be translated or there is an error, negative errno is * If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned. * returned.
* *
* Note: if the GPIO resource has multiple entries in the pin list, this * Note: if the GPIO resource has multiple entries in the pin list, this
* function only returns the first. * function only returns the first.
*/ */
int acpi_get_gpio_by_index(struct device *dev, int index, struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
struct acpi_gpio_info *info) struct acpi_gpio_info *info)
{ {
struct acpi_gpio_lookup lookup; struct acpi_gpio_lookup lookup;
struct list_head resource_list; struct list_head resource_list;
...@@ -254,65 +287,26 @@ int acpi_get_gpio_by_index(struct device *dev, int index, ...@@ -254,65 +287,26 @@ int acpi_get_gpio_by_index(struct device *dev, int index,
int ret; int ret;
if (!dev) if (!dev)
return -EINVAL; return ERR_PTR(-EINVAL);
handle = ACPI_HANDLE(dev); handle = ACPI_HANDLE(dev);
if (!handle || acpi_bus_get_device(handle, &adev)) if (!handle || acpi_bus_get_device(handle, &adev))
return -ENODEV; return ERR_PTR(-ENODEV);
memset(&lookup, 0, sizeof(lookup)); memset(&lookup, 0, sizeof(lookup));
lookup.index = index; lookup.index = index;
lookup.gpio = -ENODEV;
INIT_LIST_HEAD(&resource_list); INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup); &lookup);
if (ret < 0) if (ret < 0)
return ret; return ERR_PTR(ret);
acpi_dev_free_resource_list(&resource_list); acpi_dev_free_resource_list(&resource_list);
if (lookup.gpio >= 0 && info) if (lookup.desc && info)
*info = lookup.info; *info = lookup.info;
return lookup.gpio; return lookup.desc ? lookup.desc : ERR_PTR(-ENODEV);
} }
EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index); EXPORT_SYMBOL_GPL(acpi_get_gpiod_by_index);
/**
* acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts.
* @chip: gpio chip
*
* Free interrupts associated with the _EVT method for the given GPIO chip.
*
* The remaining ACPI event interrupts associated with the chip are freed
* automatically.
*/
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
{
acpi_handle handle;
acpi_status status;
struct list_head *evt_pins;
struct acpi_gpio_evt_pin *evt_pin, *ep;
if (!chip->dev || !chip->to_irq)
return;
handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;
status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins);
if (ACPI_FAILURE(status))
return;
list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) {
devm_free_irq(chip->dev, evt_pin->irq, evt_pin);
list_del(&evt_pin->node);
kfree(evt_pin);
}
acpi_detach_data(handle, acpi_gpio_evt_dh);
kfree(evt_pins);
}
EXPORT_SYMBOL(acpi_gpiochip_free_interrupts);
...@@ -15,19 +15,21 @@ ...@@ -15,19 +15,21 @@
#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/gpio/consumer.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/pinctrl/pinctrl.h> #include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h> #include <linux/slab.h>
struct gpio_desc;
/* Private data structure for of_gpiochip_find_and_xlate */ /* Private data structure for of_gpiochip_find_and_xlate */
struct gg_data { struct gg_data {
enum of_gpio_flags *flags; enum of_gpio_flags *flags;
struct of_phandle_args gpiospec; struct of_phandle_args gpiospec;
int out_gpio; struct gpio_desc *out_gpio;
}; };
/* Private function for resolving node pointer to gpio_chip */ /* Private function for resolving node pointer to gpio_chip */
...@@ -45,28 +47,31 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) ...@@ -45,28 +47,31 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
if (ret < 0) if (ret < 0)
return false; return false;
gg_data->out_gpio = ret + gc->base; gg_data->out_gpio = gpio_to_desc(ret + gc->base);
return true; return true;
} }
/** /**
* of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API
* @np: device node to get GPIO from * @np: device node to get GPIO from
* @propname: property name containing gpio specifier(s) * @propname: property name containing gpio specifier(s)
* @index: index of the GPIO * @index: index of the GPIO
* @flags: a flags pointer to fill in * @flags: a flags pointer to fill in
* *
* Returns GPIO number to use with Linux generic GPIO API, or one of the errno * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
* value on the error condition. If @flags is not NULL the function also fills * value on the error condition. If @flags is not NULL the function also fills
* in flags for the GPIO. * in flags for the GPIO.
*/ */
int of_get_named_gpio_flags(struct device_node *np, const char *propname, struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
int index, enum of_gpio_flags *flags) const char *propname, int index, enum of_gpio_flags *flags)
{ {
/* Return -EPROBE_DEFER to support probe() functions to be called /* Return -EPROBE_DEFER to support probe() functions to be called
* later when the GPIO actually becomes available * later when the GPIO actually becomes available
*/ */
struct gg_data gg_data = { .flags = flags, .out_gpio = -EPROBE_DEFER }; struct gg_data gg_data = {
.flags = flags,
.out_gpio = ERR_PTR(-EPROBE_DEFER)
};
int ret; int ret;
/* .of_xlate might decide to not fill in the flags, so clear it. */ /* .of_xlate might decide to not fill in the flags, so clear it. */
...@@ -78,16 +83,17 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, ...@@ -78,16 +83,17 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
if (ret) { if (ret) {
pr_debug("%s: can't parse gpios property of node '%s[%d]'\n", pr_debug("%s: can't parse gpios property of node '%s[%d]'\n",
__func__, np->full_name, index); __func__, np->full_name, index);
return ret; return ERR_PTR(ret);
} }
gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
of_node_put(gg_data.gpiospec.np); of_node_put(gg_data.gpiospec.np);
pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio); pr_debug("%s exited with status %d\n", __func__,
PTR_RET(gg_data.out_gpio));
return gg_data.out_gpio; return gg_data.out_gpio;
} }
EXPORT_SYMBOL(of_get_named_gpio_flags); EXPORT_SYMBOL(of_get_named_gpiod_flags);
/** /**
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
......
This diff is collapsed.
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/gpio.h>
#include <mach/hardware.h> #include <mach/hardware.h>
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
...@@ -35,15 +36,12 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count) ...@@ -35,15 +36,12 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
spin_lock_irqsave(&beep_lock, flags); spin_lock_irqsave(&beep_lock, flags);
if (count) { if (count) {
gpio_line_config(pin, IXP4XX_GPIO_OUT); gpio_direction_output(pin, 0);
gpio_line_set(pin, IXP4XX_GPIO_LOW);
*IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE; *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
} else { } else {
gpio_line_config(pin, IXP4XX_GPIO_IN); gpio_direction_output(pin, 1);
gpio_line_set(pin, IXP4XX_GPIO_HIGH); gpio_direction_input(pin);
*IXP4XX_OSRT2 = 0; *IXP4XX_OSRT2 = 0;
} }
...@@ -78,11 +76,13 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned ...@@ -78,11 +76,13 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned
static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id) static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
{ {
unsigned int pin = (unsigned int) dev_id;
/* clear interrupt */ /* clear interrupt */
*IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND; *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
/* flip the beeper output */ /* flip the beeper output */
*IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id); gpio_set_value(pin, !gpio_get_value(pin));
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -110,11 +110,15 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) ...@@ -110,11 +110,15 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
input_dev->event = ixp4xx_spkr_event; input_dev->event = ixp4xx_spkr_event;
err = gpio_request(dev->id, "ixp4-beeper");
if (err)
goto err_free_device;
err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt, err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
IRQF_NO_SUSPEND, "ixp4xx-beeper", IRQF_NO_SUSPEND, "ixp4xx-beeper",
(void *) dev->id); (void *) dev->id);
if (err) if (err)
goto err_free_device; goto err_free_gpio;
err = input_register_device(input_dev); err = input_register_device(input_dev);
if (err) if (err)
...@@ -126,6 +130,8 @@ static int ixp4xx_spkr_probe(struct platform_device *dev) ...@@ -126,6 +130,8 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)
err_free_irq: err_free_irq:
free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
err_free_gpio:
gpio_free(dev->id);
err_free_device: err_free_device:
input_free_device(input_dev); input_free_device(input_dev);
...@@ -144,6 +150,7 @@ static int ixp4xx_spkr_remove(struct platform_device *dev) ...@@ -144,6 +150,7 @@ static int ixp4xx_spkr_remove(struct platform_device *dev)
ixp4xx_spkr_control(pin, 0); ixp4xx_spkr_control(pin, 0);
free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id); free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
gpio_free(dev->id);
return 0; return 0;
} }
......
...@@ -529,6 +529,10 @@ static void u300_gpio_irq_enable(struct irq_data *d) ...@@ -529,6 +529,10 @@ static void u300_gpio_irq_enable(struct irq_data *d)
dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
d->hwirq, port->name, offset); d->hwirq, port->name, offset);
if (gpio_lock_as_irq(&gpio->chip, d->hwirq))
dev_err(gpio->dev,
"unable to lock HW IRQ %lu for IRQ\n",
d->hwirq);
local_irq_save(flags); local_irq_save(flags);
val = readl(U300_PIN_REG(offset, ien)); val = readl(U300_PIN_REG(offset, ien));
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
...@@ -547,6 +551,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) ...@@ -547,6 +551,7 @@ static void u300_gpio_irq_disable(struct irq_data *d)
val = readl(U300_PIN_REG(offset, ien)); val = readl(U300_PIN_REG(offset, ien));
writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
local_irq_restore(flags); local_irq_restore(flags);
gpio_unlock_as_irq(&gpio->chip, d->hwirq);
} }
static struct irq_chip u300_gpio_irqchip = { static struct irq_chip u300_gpio_irqchip = {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment