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