1
0
Fork 0

This is the big bulk of GPIO changes queued for the v4.2

kernel series:
 
 - A big set of cleanups to the aged sysfs interface from
   Johan Hovold. To get these in, v4.1-rc3 was merged into
   the tree as the first patch in that series had to go
   into stable. This makes the locking much more fine-grained
   (get rid of the "big GPIO lock(s)" and store states in the
   GPIO descriptors.
 
 - Rename gpiod_[g|s]et_array() to gpiod_[g|s]et_array_value()
   to avoid confusions.
 
 - New drivers for:
   - NXP LPC18xx (currently LPC1850)
   - NetLogic XLP
   - Broadcom STB SoC's
   - Axis ETRAXFS
   - Zynq Ultrascale+ (subdriver)
 
 - ACPI:
   - Make it possible to retrieve GpioInt resources from
     a GPIO device using acpi_dev_gpio_irq_get()
   - Merge some dependent I2C changes exploiting this.
   - Support the ARM X-Gene GPIO standby driver.
 
 - Make it possible for the generic GPIO driver to read
   back the value set registers to reflect current
   status.
 
 - Loads of OMAP IRQ handling fixes.
 
 - Incremental improvements to Kona, max732x, OMAP, MXC, RCAR,
   PCA953x, STP-XWAY, PCF857x, Crystalcove, TB10x.
 
 - Janitorial (contification, checkpatch cleanups)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVh76DAAoJEEEQszewGV1zYFsP/AnyCHs4M67k5Eegxtiwoomc
 OTqkVtOcob9kfqMkbZ1dsjZe2ZYIDiyWeQ1xuV+dD9nx/iAu6inUxb0dXhxKXonr
 +7mQglg32+zWTepLOJosoftoIqOb06lsMfgjL+tJcY5Od7/rewpdEplfEcjmq1O0
 0OdaV2FCXIhHDt52iYHT4tYI1GCky9K4Au9NlPCbKAsGneb3fQahF9o3JpYXl1Oq
 YhIFzUEhM+Zi2IoRsloGdK/eGEHni59IDekhZDf4PnYgA4Dkx2/e1A2Q0h5oT+QI
 j2yfRbI9t1gA5UK7JR/rVJF+5+E8uZ06TZgTo8tU00U4ZvppNgHt8O4KZkJMFBce
 KZzD9rkVVGp0NIDVwmOWjnfwkVVcQzMg/Wf17oM+qdaPO4GHEXNaQaInk1zmwqZq
 tQiTk47zA4rrEaYq3YZjt4xQjl8+ExDlOzFjnfLYAm27gbIl6EFWbX2ON981MC8g
 Nap8MLZINbGTlyDHtuqUlnqN+oXoP8niFuuDixYR+pM1P1bgwIVF+VopRJBFJRJP
 IeR6VdsI9KS99Kg8ICf4ds6WdKAGU3Htj+26udgMhIlOWrkCbvvexIxq9oBkwIB1
 VZofnSZLqnlKvo9Z140atvJWkFti7mqhItVjohmZyvyImLtmQBMq3kSGurXEqWms
 /NGZ0txPd1lMHx5o6ZPK
 =vKYs
 -----END PGP SIGNATURE-----

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

Pull gpio updates from Linus Walleij:
 "This is the big bulk of GPIO changes queued for the v4.2 kernel
  series:

   - a big set of cleanups to the aged sysfs interface from Johan
     Hovold.  To get these in, v4.1-rc3 was merged into the tree as the
     first patch in that series had to go into stable.  This makes the
     locking much more fine-grained (get rid of the "big GPIO lock(s)"
     and store states in the GPIO descriptors.

   - rename gpiod_[g|s]et_array() to gpiod_[g|s]et_array_value() to
     avoid confusions.

   - New drivers for:
      * NXP LPC18xx (currently LPC1850)
      * NetLogic XLP
      * Broadcom STB SoC's
      * Axis ETRAXFS
      * Zynq Ultrascale+ (subdriver)

   - ACPI:
      * make it possible to retrieve GpioInt resources from a GPIO
        device using acpi_dev_gpio_irq_get()
      * merge some dependent I2C changes exploiting this.
      * support the ARM X-Gene GPIO standby driver.

   - make it possible for the generic GPIO driver to read back the value
     set registers to reflect current status.

   - loads of OMAP IRQ handling fixes.

   - incremental improvements to Kona, max732x, OMAP, MXC, RCAR,
     PCA953x, STP-XWAY, PCF857x, Crystalcove, TB10x.

   - janitorial (constification, checkpatch cleanups)"

* tag 'gpio-v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (71 commits)
  gpio: Fix checkpatch.pl issues
  gpio: pcf857x: handle only enabled irqs
  gpio / ACPI: Return -EPROBE_DEFER if the gpiochip was not found
  GPIO / ACPI: export acpi_gpiochip_request(free)_interrupts for module use
  gpio: improve error reporting on own descriptors
  gpio: promote own request failure to pr_err()
  gpio: Added support to Zynq Ultrascale+ MPSoC
  gpio: add ETRAXFS GPIO driver
  fix documentation after renaming gpiod_set_array to gpiod_set_array_value
  gpio: Add GPIO support for Broadcom STB SoCs
  gpio: xgene: add ACPI support for APM X-Gene GPIO standby driver
  gpio: tb10x: Drop unneeded free_irq() call
  gpio: crystalcove: set IRQCHIP_SKIP_SET_WAKE for the irqchip
  gpio: stp-xway: Use the of_property_read_u32 helper
  gpio: pcf857x: Check for irq_set_irq_wake() failures
  gpio-stp-xway: Fix enabling the highest bit of the PHY LEDs
  gpio: Prevent an integer overflow in the pca953x driver
  gpio: omap: rework omap_gpio_irq_startup to handle current pin state properly
  gpio: omap: rework omap_gpio_request to touch only gpio specific registers
  gpio: omap: rework omap_x_irq_shutdown to touch only irqs specific registers
  ...
hifive-unleashed-5.1
Linus Torvalds 2015-06-23 13:34:02 -07:00
commit 10b4b096d0
54 changed files with 2054 additions and 652 deletions

View File

@ -0,0 +1,65 @@
Broadcom STB "UPG GIO" GPIO controller
The controller's registers are organized as sets of eight 32-bit
registers with each set controlling a bank of up to 32 pins. A single
interrupt is shared for all of the banks handled by the controller.
Required properties:
- compatible:
Must be "brcm,brcmstb-gpio"
- reg:
Define the base and range of the I/O address space containing
the brcmstb GPIO controller registers
- #gpio-cells:
Should be <2>. The first cell is the pin number (within the controller's
pin space), and the second is used for the following:
bit[0]: polarity (0 for active-high, 1 for active-low)
- gpio-controller:
Specifies that the node is a GPIO controller.
- brcm,gpio-bank-widths:
Number of GPIO lines for each bank. Number of elements must
correspond to number of banks suggested by the 'reg' property.
Optional properties:
- interrupts:
The interrupt shared by all GPIO lines for this controller.
- interrupt-parent:
phandle of the parent interrupt controller
- #interrupt-cells:
Should be <2>. The first cell is the GPIO number, the second should specify
flags. The following subset of flags is supported:
- bits[3:0] trigger type and level flags
1 = low-to-high edge triggered
2 = high-to-low edge triggered
4 = active high level-sensitive
8 = active low level-sensitive
Valid combinations are 1, 2, 3, 4, 8.
See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- interrupt-controller:
Marks the device node as an interrupt controller
- interrupt-names:
The name of the IRQ resource used by this controller
Example:
upg_gio: gpio@f040a700 {
#gpio-cells = <0x2>;
#interrupt-cells = <0x2>;
compatible = "brcm,bcm7445-gpio", "brcm,brcmstb-gpio";
gpio-controller;
interrupt-controller;
reg = <0xf040a700 0x80>;
interrupt-parent = <0xf>;
interrupts = <0x6>;
interrupt-names = "upg_gio";
brcm,gpio-bank-widths = <0x20 0x20 0x20 0x18>;
};

View File

@ -0,0 +1,21 @@
Axis ETRAX FS General I/O controller bindings
Required properties:
- compatible:
- "axis,etraxfs-gio"
- reg: Physical base address and length of the controller's registers.
- #gpio-cells: Should be 3
- The first cell is the gpio offset number.
- The second cell is reserved and is currently unused.
- The third cell is the port number (hex).
- gpio-controller: Marks the device node as a GPIO controller.
Example:
gio: gpio@b001a000 {
compatible = "axis,etraxfs-gio";
reg = <0xb001a000 0x1000>;
gpio-controller;
#gpio-cells = <3>;
};

View File

@ -0,0 +1,47 @@
Netlogic XLP Family GPIO
========================
This GPIO driver is used for following Netlogic XLP SoCs:
XLP832, XLP316, XLP208, XLP980, XLP532
Required properties:
-------------------
- compatible: Should be one of the following:
- "netlogic,xlp832-gpio": For Netlogic XLP832
- "netlogic,xlp316-gpio": For Netlogic XLP316
- "netlogic,xlp208-gpio": For Netlogic XLP208
- "netlogic,xlp980-gpio": For Netlogic XLP980
- "netlogic,xlp532-gpio": For Netlogic XLP532
- reg: Physical base address and length of the controller's registers.
- #gpio-cells: Should be two. The first cell is the pin number and the second
cell is used to specify optional parameters (currently unused).
- gpio-controller: Marks the device node as a GPIO controller.
- nr-gpios: Number of GPIO pins supported by the controller.
- interrupt-cells: Should be two. The first cell is the GPIO Number. The
second cell is used to specify flags. The following subset of flags is
supported:
- trigger type:
1 = low to high edge triggered.
2 = high to low edge triggered.
4 = active high level-sensitive.
8 = active low level-sensitive.
- interrupts: Interrupt number for this device.
- interrupt-parent: phandle of the parent interrupt controller.
- interrupt-controller: Identifies the node as an interrupt controller.
Example:
gpio: xlp_gpio@34000 {
compatible = "netlogic,xlp316-gpio";
reg = <0 0x34100 0x1000
0 0x35100 0x1000>;
#gpio-cells = <2>;
gpio-controller;
nr-gpios = <57>;
#interrupt-cells = <2>;
interrupt-parent = <&pic>;
interrupts = <39>;
interrupt-controller;
};

View File

@ -6,7 +6,7 @@ Required properties:
- First cell is the GPIO line number
- Second cell is used to specify optional
parameters (unused)
- compatible : Should be "xlnx,zynq-gpio-1.0"
- compatible : Should be "xlnx,zynq-gpio-1.0" or "xlnx,zynqmp-gpio-1.0"
- clocks : Clock specifier (see clock bindings for details)
- gpio-controller : Marks the device node as a GPIO controller.
- interrupts : Interrupt specifier (see interrupt bindings for

View File

@ -0,0 +1,39 @@
NXP LPC18xx/43xx GPIO controller Device Tree Bindings
-----------------------------------------------------
Required properties:
- compatible : Should be "nxp,lpc1850-gpio"
- reg : Address and length of the register set for the device
- clocks : Clock specifier (see clock bindings for details)
- gpio-controller : Marks the device node as a GPIO controller.
- #gpio-cells : Should be two
- First cell is the GPIO line number
- Second cell is used to specify polarity
Optional properties:
- gpio-ranges : Mapping between GPIO and pinctrl
Example:
#define LPC_GPIO(port, pin) (port * 32 + pin)
#define LPC_PIN(port, pin) (0x##port * 32 + pin)
gpio: gpio@400f4000 {
compatible = "nxp,lpc1850-gpio";
reg = <0x400f4000 0x4000>;
clocks = <&ccu1 CLK_CPU_GPIO>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl LPC_GPIO(0,0) LPC_PIN(0,0) 2>,
...
<&pinctrl LPC_GPIO(7,19) LPC_PIN(f,5) 7>;
};
gpio_joystick {
compatible = "gpio-keys-polled";
...
button@0 {
...
gpios = <&gpio LPC_GPIO(4,8) GPIO_ACTIVE_LOW>;
};
};

View File

@ -241,18 +241,18 @@ Set multiple GPIO outputs with a single function call
-----------------------------------------------------
The following functions set the output values of an array of GPIOs:
void gpiod_set_array(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
The array can be an arbitrary set of GPIOs. The functions will try to set
GPIOs belonging to the same bank or chip simultaneously if supported by the
@ -271,8 +271,8 @@ matches the desired group of GPIOs, those GPIOs can be set by simply using
the struct gpio_descs returned by gpiod_get_array():
struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
gpiod_set_array(my_gpio_descs->ndescs, my_gpio_descs->desc,
my_gpio_values);
gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
my_gpio_values);
It is also possible to set a completely arbitrary array of descriptors. The
descriptors may be obtained using any combination of gpiod_get() and

View File

@ -751,9 +751,6 @@ requested using gpio_request():
int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
/* change the polarity of a GPIO node in sysfs */
int gpio_sysfs_set_active_low(unsigned gpio, int value);
After a kernel driver requests a GPIO, it may only be made available in
the sysfs interface by gpio_export(). The driver can control whether the
signal direction may change. This helps drivers prevent userspace code
@ -767,9 +764,3 @@ After the GPIO has been exported, gpio_export_link() allows creating
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
use this to provide the interface under their own device in sysfs with
a descriptive name.
Drivers can use gpio_sysfs_set_active_low() to hide GPIO line polarity
differences between boards from user space. This only affects the
sysfs interface. Polarity change can be done both before and after
gpio_export(), and previously enabled poll(2) support for either
rising or falling edge will be reconfigured to follow this setting.

View File

@ -132,9 +132,6 @@ requested using gpio_request():
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
/* change the polarity of a GPIO node in sysfs */
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
After a kernel driver requests a GPIO, it may only be made available in
the sysfs interface by gpiod_export(). The driver can control whether the
signal direction may change. This helps drivers prevent userspace code
@ -148,8 +145,3 @@ After the GPIO has been exported, gpiod_export_link() allows creating
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
use this to provide the interface under their own device in sysfs with
a descriptive name.
Drivers can use gpiod_sysfs_set_active_low() to hide GPIO line polarity
differences between boards from user space. Polarity change can be done both
before and after gpiod_export(), and previously enabled poll(2) support for
either rising or falling edge will be reconfigured to follow this setting.

View File

@ -638,9 +638,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
/* 改变 sysfs 中的一个 GPIO 节点的极性 */
int gpio_sysfs_set_active_low(unsigned gpio, int value);
在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs
接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间
破坏重要的系统状态。
@ -651,8 +648,3 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
在 GPIO 被导出之后gpio_export_link()允许在 sysfs 文件系统的任何地方
创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
驱动可以使用 gpio_sysfs_set_active_low() 来在用户空间隐藏电路板之间
GPIO 线的极性差异。这个仅对 sysfs 接口起作用。极性的改变可以在 gpio_export()
前后进行,且之前使能的轮询操作(poll(2))支持(上升或下降沿)将会被重新配置来遵循
这个设置。

View File

@ -2250,6 +2250,13 @@ N: bcm9583*
N: bcm583*
N: bcm113*
BROADCOM BRCMSTB GPIO DRIVER
M: Gregory Fong <gregory.0xf0@gmail.com>
L: bcm-kernel-feedback-list@broadcom.com>
S: Supported
F: drivers/gpio/gpio-brcmstb.c
F: Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
BROADCOM KONA GPIO DRIVER
M: Ray Jui <rjui@broadcom.com>
L: bcm-kernel-feedback-list@broadcom.com

View File

@ -126,6 +126,14 @@ config GPIO_BCM_KONA
help
Turn on GPIO support for Broadcom "Kona" chips.
config GPIO_BRCMSTB
tristate "BRCMSTB GPIO support"
default y if ARCH_BRCMSTB
depends on OF_GPIO && (ARCH_BRCMSTB || COMPILE_TEST)
select GPIO_GENERIC
help
Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
config GPIO_CLPS711X
tristate "CLPS711X GPIO support"
depends on ARCH_CLPS711X || COMPILE_TEST
@ -159,6 +167,14 @@ config GPIO_EP93XX
depends on ARCH_EP93XX
select GPIO_GENERIC
config GPIO_ETRAXFS
bool "Axis ETRAX FS General I/O"
depends on CRIS || COMPILE_TEST
depends on OF
select GPIO_GENERIC
help
Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
config GPIO_F7188X
tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
depends on X86
@ -230,6 +246,14 @@ config GPIO_LOONGSON
help
driver for GPIO functionality on Loongson-2F/3A/3B processors.
config GPIO_LPC18XX
bool "NXP LPC18XX/43XX GPIO support"
default y if ARCH_LPC18XX
depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)
help
Select this option to enable GPIO driver for
NXP LPC18XX/43XX devices.
config GPIO_LYNXPOINT
tristate "Intel Lynxpoint GPIO support"
depends on ACPI && X86
@ -308,7 +332,7 @@ config GPIO_OCTEON
family of SOCs.
config GPIO_OMAP
bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS
tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST
default y if ARCH_OMAP
depends on ARM
select GENERIC_IRQ_CHIP
@ -488,6 +512,17 @@ config GPIO_XILINX
help
Say yes here to support the Xilinx FPGA GPIO device
config GPIO_XLP
tristate "Netlogic XLP GPIO support"
depends on CPU_XLP
select GPIOLIB_IRQCHIP
help
This driver provides support for GPIO interface on Netlogic XLP MIPS64
SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX,
XLP9XX and XLP5XX.
If unsure, say N.
config GPIO_XTENSA
bool "Xtensa GPIO32 support"
depends on XTENSA
@ -505,7 +540,7 @@ config GPIO_ZEVIO
config GPIO_ZYNQ
tristate "Xilinx Zynq GPIO support"
depends on ARCH_ZYNQ
depends on ARCH_ZYNQ || ARCH_ZYNQMP
select GPIOLIB_IRQCHIP
help
Say yes here to support Xilinx Zynq GPIO controller.

View File

@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
@ -32,6 +33,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
@ -44,6 +46,7 @@ obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
@ -109,6 +112,7 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o

View File

@ -107,7 +107,8 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
return -EINVAL;
}
static unsigned int altera_gpio_irq_startup(struct irq_data *d) {
static unsigned int altera_gpio_irq_startup(struct irq_data *d)
{
altera_gpio_irq_unmask(d);
return 0;

View File

@ -122,6 +122,16 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
spin_unlock_irqrestore(&kona_gpio->lock, flags);
}
static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
{
struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
void __iomem *reg_base = kona_gpio->reg_base;
u32 val;
val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK;
return val ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
}
static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{
struct bcm_kona_gpio *kona_gpio;
@ -135,12 +145,8 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
/* determine the GPIO pin direction */
val = readl(reg_base + GPIO_CONTROL(gpio));
val &= GPIO_GPCTR0_IOTR_MASK;
/* this function only applies to output pin */
if (GPIO_GPCTR0_IOTR_CMD_INPUT == val)
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
goto out;
reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
@ -166,13 +172,12 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags);
/* determine the GPIO pin direction */
val = readl(reg_base + GPIO_CONTROL(gpio));
val &= GPIO_GPCTR0_IOTR_MASK;
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
reg_offset = GPIO_IN_STATUS(bank_id);
else
reg_offset = GPIO_OUT_STATUS(bank_id);
/* read the GPIO bank status */
reg_offset = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ?
GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
val = readl(reg_base + reg_offset);
spin_unlock_irqrestore(&kona_gpio->lock, flags);
@ -310,6 +315,7 @@ static struct gpio_chip template_chip = {
.owner = THIS_MODULE,
.request = bcm_kona_gpio_request,
.free = bcm_kona_gpio_free,
.get_direction = bcm_kona_gpio_get_dir,
.direction_input = bcm_kona_gpio_direction_input,
.get = bcm_kona_gpio_get,
.direction_output = bcm_kona_gpio_direction_output,

View File

@ -0,0 +1,252 @@
/*
* Copyright (C) 2015 Broadcom Corporation
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/module.h>
#include <linux/basic_mmio_gpio.h>
#define GIO_BANK_SIZE 0x20
#define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00)
#define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04)
#define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08)
#define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c)
#define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10)
#define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14)
#define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18)
#define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c)
struct brcmstb_gpio_bank {
struct list_head node;
int id;
struct bgpio_chip bgc;
struct brcmstb_gpio_priv *parent_priv;
u32 width;
};
struct brcmstb_gpio_priv {
struct list_head bank_list;
void __iomem *reg_base;
int num_banks;
struct platform_device *pdev;
int gpio_base;
};
#define MAX_GPIO_PER_BANK 32
#define GPIO_BANK(gpio) ((gpio) >> 5)
/* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
#define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1))
static inline struct brcmstb_gpio_bank *
brcmstb_gpio_gc_to_bank(struct gpio_chip *gc)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
return container_of(bgc, struct brcmstb_gpio_bank, bgc);
}
static inline struct brcmstb_gpio_priv *
brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
{
struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
return bank->parent_priv;
}
/* Make sure that the number of banks matches up between properties */
static int brcmstb_gpio_sanity_check_banks(struct device *dev,
struct device_node *np, struct resource *res)
{
int res_num_banks = resource_size(res) / GIO_BANK_SIZE;
int num_banks =
of_property_count_u32_elems(np, "brcm,gpio-bank-widths");
if (res_num_banks != num_banks) {
dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n",
res_num_banks, num_banks);
return -EINVAL;
} else {
return 0;
}
}
static int brcmstb_gpio_remove(struct platform_device *pdev)
{
struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
struct list_head *pos;
struct brcmstb_gpio_bank *bank;
int ret = 0;
list_for_each(pos, &priv->bank_list) {
bank = list_entry(pos, struct brcmstb_gpio_bank, node);
ret = bgpio_remove(&bank->bgc);
if (ret)
dev_err(&pdev->dev, "gpiochip_remove fail in cleanup");
}
return ret;
}
static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags)
{
struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
int offset;
if (gc->of_gpio_n_cells != 2) {
WARN_ON(1);
return -EINVAL;
}
if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
return -EINVAL;
offset = gpiospec->args[0] - (gc->base - priv->gpio_base);
if (offset >= gc->ngpio)
return -EINVAL;
if (unlikely(offset >= bank->width)) {
dev_warn_ratelimited(&priv->pdev->dev,
"Received request for invalid GPIO offset %d\n",
gpiospec->args[0]);
}
if (flags)
*flags = gpiospec->args[1];
return offset;
}
static int brcmstb_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
void __iomem *reg_base;
struct brcmstb_gpio_priv *priv;
struct resource *res;
struct property *prop;
const __be32 *p;
u32 bank_width;
int err;
static int gpio_base;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg_base = devm_ioremap_resource(dev, res);
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
priv->gpio_base = gpio_base;
priv->reg_base = reg_base;
priv->pdev = pdev;
INIT_LIST_HEAD(&priv->bank_list);
if (brcmstb_gpio_sanity_check_banks(dev, np, res))
return -EINVAL;
of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p,
bank_width) {
struct brcmstb_gpio_bank *bank;
struct bgpio_chip *bgc;
struct gpio_chip *gc;
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
if (!bank) {
err = -ENOMEM;
goto fail;
}
bank->parent_priv = priv;
bank->id = priv->num_banks;
if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) {
dev_err(dev, "Invalid bank width %d\n", bank_width);
goto fail;
} else {
bank->width = bank_width;
}
/*
* Regs are 4 bytes wide, have data reg, no set/clear regs,
* and direction bits have 0 = output and 1 = input
*/
bgc = &bank->bgc;
err = bgpio_init(bgc, dev, 4,
reg_base + GIO_DATA(bank->id),
NULL, NULL, NULL,
reg_base + GIO_IODIR(bank->id), 0);
if (err) {
dev_err(dev, "bgpio_init() failed\n");
goto fail;
}
gc = &bgc->gc;
gc->of_node = np;
gc->owner = THIS_MODULE;
gc->label = np->full_name;
gc->base = gpio_base;
gc->of_gpio_n_cells = 2;
gc->of_xlate = brcmstb_gpio_of_xlate;
/* not all ngpio lines are valid, will use bank width later */
gc->ngpio = MAX_GPIO_PER_BANK;
err = gpiochip_add(gc);
if (err) {
dev_err(dev, "Could not add gpiochip for bank %d\n",
bank->id);
goto fail;
}
gpio_base += gc->ngpio;
dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id,
gc->base, gc->ngpio, bank->width);
/* Everything looks good, so add bank to list */
list_add(&bank->node, &priv->bank_list);
priv->num_banks++;
}
dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
priv->num_banks, priv->gpio_base, gpio_base - 1);
platform_set_drvdata(pdev, priv);
return 0;
fail:
(void) brcmstb_gpio_remove(pdev);
return err;
}
static const struct of_device_id brcmstb_gpio_of_match[] = {
{ .compatible = "brcm,brcmstb-gpio" },
{},
};
MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match);
static struct platform_driver brcmstb_gpio_driver = {
.driver = {
.name = "brcmstb-gpio",
.of_match_table = brcmstb_gpio_of_match,
},
.probe = brcmstb_gpio_probe,
.remove = brcmstb_gpio_remove,
};
module_platform_driver(brcmstb_gpio_driver);
MODULE_AUTHOR("Gregory Fong");
MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO");
MODULE_LICENSE("GPL v2");

View File

@ -16,6 +16,7 @@
*/
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/seq_file.h>
@ -94,9 +95,8 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
{
int reg;
if (gpio == 94) {
if (gpio == 94)
return GPIOPANELCTL;
}
if (reg_type == CTRL_IN) {
if (gpio < 8)
@ -255,6 +255,7 @@ static struct irq_chip crystalcove_irqchip = {
.irq_set_type = crystalcove_irq_type,
.irq_bus_lock = crystalcove_bus_lock,
.irq_bus_sync_unlock = crystalcove_bus_sync_unlock,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)

View File

@ -466,7 +466,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2->gpio.owner = THIS_MODULE;
dln2->gpio.base = -1;
dln2->gpio.ngpio = pins;
dln2->gpio.exported = true;
dln2->gpio.can_sleep = true;
dln2->gpio.irq_not_threaded = true;
dln2->gpio.set = dln2_gpio_set;

View File

@ -0,0 +1,176 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/basic_mmio_gpio.h>
#define ETRAX_FS_rw_pa_dout 0
#define ETRAX_FS_r_pa_din 4
#define ETRAX_FS_rw_pa_oe 8
#define ETRAX_FS_rw_intr_cfg 12
#define ETRAX_FS_rw_intr_mask 16
#define ETRAX_FS_rw_ack_intr 20
#define ETRAX_FS_r_intr 24
#define ETRAX_FS_rw_pb_dout 32
#define ETRAX_FS_r_pb_din 36
#define ETRAX_FS_rw_pb_oe 40
#define ETRAX_FS_rw_pc_dout 48
#define ETRAX_FS_r_pc_din 52
#define ETRAX_FS_rw_pc_oe 56
#define ETRAX_FS_rw_pd_dout 64
#define ETRAX_FS_r_pd_din 68
#define ETRAX_FS_rw_pd_oe 72
#define ETRAX_FS_rw_pe_dout 80
#define ETRAX_FS_r_pe_din 84
#define ETRAX_FS_rw_pe_oe 88
struct etraxfs_gpio_port {
const char *label;
unsigned int oe;
unsigned int dout;
unsigned int din;
unsigned int ngpio;
};
struct etraxfs_gpio_info {
unsigned int num_ports;
const struct etraxfs_gpio_port *ports;
};
static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = {
{
.label = "A",
.ngpio = 8,
.oe = ETRAX_FS_rw_pa_oe,
.dout = ETRAX_FS_rw_pa_dout,
.din = ETRAX_FS_r_pa_din,
},
{
.label = "B",
.ngpio = 18,
.oe = ETRAX_FS_rw_pb_oe,
.dout = ETRAX_FS_rw_pb_dout,
.din = ETRAX_FS_r_pb_din,
},
{
.label = "C",
.ngpio = 18,
.oe = ETRAX_FS_rw_pc_oe,
.dout = ETRAX_FS_rw_pc_dout,
.din = ETRAX_FS_r_pc_din,
},
{
.label = "D",
.ngpio = 18,
.oe = ETRAX_FS_rw_pd_oe,
.dout = ETRAX_FS_rw_pd_dout,
.din = ETRAX_FS_r_pd_din,
},
{
.label = "E",
.ngpio = 18,
.oe = ETRAX_FS_rw_pe_oe,
.dout = ETRAX_FS_rw_pe_dout,
.din = ETRAX_FS_r_pe_din,
},
};
static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = {
.num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports),
.ports = etraxfs_gpio_etraxfs_ports,
};
static int etraxfs_gpio_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec,
u32 *flags)
{
/*
* Port numbers are A to E, and the properties are integers, so we
* specify them as 0xA - 0xE.
*/
if (gc->label[0] - 'A' + 0xA != gpiospec->args[2])
return -EINVAL;
return of_gpio_simple_xlate(gc, gpiospec, flags);
}
static const struct of_device_id etraxfs_gpio_of_table[] = {
{
.compatible = "axis,etraxfs-gio",
.data = &etraxfs_gpio_etraxfs,
},
{},
};
static int etraxfs_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct etraxfs_gpio_info *info;
const struct of_device_id *match;
struct bgpio_chip *chips;
struct resource *res;
void __iomem *regs;
int ret;
int i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
if (!regs)
return -ENOMEM;
match = of_match_node(etraxfs_gpio_of_table, dev->of_node);
if (!match)
return -EINVAL;
info = match->data;
chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL);
if (!chips)
return -ENOMEM;
for (i = 0; i < info->num_ports; i++) {
struct bgpio_chip *bgc = &chips[i];
const struct etraxfs_gpio_port *port = &info->ports[i];
ret = bgpio_init(bgc, dev, 4,
regs + port->din, /* dat */
regs + port->dout, /* set */
NULL, /* clr */
regs + port->oe, /* dirout */
NULL, /* dirin */
BGPIOF_UNREADABLE_REG_SET);
if (ret)
return ret;
bgc->gc.ngpio = port->ngpio;
bgc->gc.label = port->label;
bgc->gc.of_node = dev->of_node;
bgc->gc.of_gpio_n_cells = 3;
bgc->gc.of_xlate = etraxfs_gpio_of_xlate;
ret = gpiochip_add(&bgc->gc);
if (ret)
dev_err(dev, "Unable to register port %s\n",
bgc->gc.label);
}
return 0;
}
static struct platform_driver etraxfs_gpio_driver = {
.driver = {
.name = "etraxfs-gpio",
.of_match_table = of_match_ptr(etraxfs_gpio_of_table),
},
.probe = etraxfs_gpio_probe,
};
static int __init etraxfs_gpio_init(void)
{
return platform_driver_register(&etraxfs_gpio_driver);
}
device_initcall(etraxfs_gpio_init);

View File

@ -172,7 +172,7 @@ static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
};
static struct f7188x_gpio_bank f71882_gpio_bank[] = {
F7188X_GPIO_BANK(0 , 8, 0xF0),
F7188X_GPIO_BANK(0, 8, 0xF0),
F7188X_GPIO_BANK(10, 8, 0xE0),
F7188X_GPIO_BANK(20, 8, 0xD0),
F7188X_GPIO_BANK(30, 4, 0xC0),
@ -180,7 +180,7 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = {
};
static struct f7188x_gpio_bank f71889_gpio_bank[] = {
F7188X_GPIO_BANK(0 , 7, 0xF0),
F7188X_GPIO_BANK(0, 7, 0xF0),
F7188X_GPIO_BANK(10, 7, 0xE0),
F7188X_GPIO_BANK(20, 8, 0xD0),
F7188X_GPIO_BANK(30, 8, 0xC0),

View File

@ -135,6 +135,17 @@ static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
return 1 << (bgc->bits - 1 - pin);
}
static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
unsigned long pinmask = bgc->pin2mask(bgc, gpio);
if (bgc->dir & pinmask)
return bgc->read_reg(bgc->reg_set) & pinmask;
else
return bgc->read_reg(bgc->reg_dat) & pinmask;
}
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
@ -416,7 +427,8 @@ static int bgpio_setup_accessors(struct device *dev,
static int bgpio_setup_io(struct bgpio_chip *bgc,
void __iomem *dat,
void __iomem *set,
void __iomem *clr)
void __iomem *clr,
unsigned long flags)
{
bgc->reg_dat = dat;
@ -437,7 +449,11 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
bgc->gc.set_multiple = bgpio_set_multiple;
}
bgc->gc.get = bgpio_get;
if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
(flags & BGPIOF_READ_OUTPUT_REG_SET))
bgc->gc.get = bgpio_get_set;
else
bgc->gc.get = bgpio_get;
return 0;
}
@ -500,7 +516,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
bgc->gc.ngpio = bgc->bits;
bgc->gc.request = bgpio_request;
ret = bgpio_setup_io(bgc, dat, set, clr);
ret = bgpio_setup_io(bgc, dat, set, clr, flags);
if (ret)
return ret;

View File

@ -123,7 +123,7 @@ static void it8761e_gpio_set(struct gpio_chip *gc,
curr_vals = inb(reg);
if (val)
outb(curr_vals | (1 << bit) , reg);
outb(curr_vals | (1 << bit), reg);
else
outb(curr_vals & ~(1 << bit), reg);

View File

@ -0,0 +1,180 @@
/*
* GPIO driver for NXP LPC18xx/43xx.
*
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
/* LPC18xx GPIO register offsets */
#define LPC18XX_REG_DIR(n) (0x2000 + n * sizeof(u32))
#define LPC18XX_MAX_PORTS 8
#define LPC18XX_PINS_PER_PORT 32
struct lpc18xx_gpio_chip {
struct gpio_chip gpio;
void __iomem *base;
struct clk *clk;
spinlock_t lock;
};
static inline struct lpc18xx_gpio_chip *to_lpc18xx_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct lpc18xx_gpio_chip, gpio);
}
static int lpc18xx_gpio_request(struct gpio_chip *chip, unsigned offset)
{
return pinctrl_request_gpio(offset);
}
static void lpc18xx_gpio_free(struct gpio_chip *chip, unsigned offset)
{
pinctrl_free_gpio(offset);
}
static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
writeb(value ? 1 : 0, gc->base + offset);
}
static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
return !!readb(gc->base + offset);
}
static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset,
bool out)
{
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
unsigned long flags;
u32 port, pin, dir;
port = offset / LPC18XX_PINS_PER_PORT;
pin = offset % LPC18XX_PINS_PER_PORT;
spin_lock_irqsave(&gc->lock, flags);
dir = readl(gc->base + LPC18XX_REG_DIR(port));
if (out)
dir |= BIT(pin);
else
dir &= ~BIT(pin);
writel(dir, gc->base + LPC18XX_REG_DIR(port));
spin_unlock_irqrestore(&gc->lock, flags);
return 0;
}
static int lpc18xx_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
return lpc18xx_gpio_direction(chip, offset, false);
}
static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
lpc18xx_gpio_set(chip, offset, value);
return lpc18xx_gpio_direction(chip, offset, true);
}
static struct gpio_chip lpc18xx_chip = {
.label = "lpc18xx/43xx-gpio",
.request = lpc18xx_gpio_request,
.free = lpc18xx_gpio_free,
.direction_input = lpc18xx_gpio_direction_input,
.direction_output = lpc18xx_gpio_direction_output,
.set = lpc18xx_gpio_set,
.get = lpc18xx_gpio_get,
.ngpio = LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT,
.owner = THIS_MODULE,
};
static int lpc18xx_gpio_probe(struct platform_device *pdev)
{
struct lpc18xx_gpio_chip *gc;
struct resource *res;
int ret;
gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
gc->gpio = lpc18xx_chip;
platform_set_drvdata(pdev, gc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gc->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gc->base))
return PTR_ERR(gc->base);
gc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(gc->clk)) {
dev_err(&pdev->dev, "input clock not found\n");
return PTR_ERR(gc->clk);
}
ret = clk_prepare_enable(gc->clk);
if (ret) {
dev_err(&pdev->dev, "unable to enable clock\n");
return ret;
}
spin_lock_init(&gc->lock);
gc->gpio.dev = &pdev->dev;
ret = gpiochip_add(&gc->gpio);
if (ret) {
dev_err(&pdev->dev, "failed to add gpio chip\n");
clk_disable_unprepare(gc->clk);
return ret;
}
return 0;
}
static int lpc18xx_gpio_remove(struct platform_device *pdev)
{
struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
gpiochip_remove(&gc->gpio);
clk_disable_unprepare(gc->clk);
return 0;
}
static const struct of_device_id lpc18xx_gpio_match[] = {
{ .compatible = "nxp,lpc1850-gpio" },
{ }
};
MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match);
static struct platform_driver lpc18xx_gpio_driver = {
.probe = lpc18xx_gpio_probe,
.remove = lpc18xx_gpio_remove,
.driver = {
.name = "lpc18xx-gpio",
.of_match_table = lpc18xx_gpio_match,
},
};
module_platform_driver(lpc18xx_gpio_driver);
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
MODULE_LICENSE("GPL v2");

View File

@ -72,7 +72,7 @@ struct lp_gpio {
*
* per gpio specific registers consist of two 32bit registers per gpio
* (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of
* 188 config registes.
* 188 config registers.
*
* A simplified view of the register layout look like this:
*

View File

@ -429,6 +429,14 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
return 0;
}
static int max732x_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct max732x_chip *chip = irq_data_get_irq_chip_data(data);
irq_set_irq_wake(chip->client->irq, on);
return 0;
}
static struct irq_chip max732x_irq_chip = {
.name = "max732x",
.irq_mask = max732x_irq_mask,
@ -436,6 +444,7 @@ static struct irq_chip max732x_irq_chip = {
.irq_bus_lock = max732x_irq_bus_lock,
.irq_bus_sync_unlock = max732x_irq_bus_sync_unlock,
.irq_set_type = max732x_irq_set_type,
.irq_set_wake = max732x_irq_set_wake,
};
static uint8_t max732x_irq_pending(struct max732x_chip *chip)
@ -507,12 +516,10 @@ static int max732x_irq_setup(struct max732x_chip *chip,
chip->irq_features = has_irq;
mutex_init(&chip->irq_lock);
ret = devm_request_threaded_irq(&client->dev,
client->irq,
NULL,
max732x_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(&client->dev), chip);
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, max732x_irq_handler, IRQF_ONESHOT |
IRQF_TRIGGER_FALLING | IRQF_SHARED,
dev_name(&client->dev), chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
@ -521,7 +528,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
ret = gpiochip_irqchip_add(&chip->gpio_chip,
&max732x_irq_chip,
irq_base,
handle_edge_irq,
handle_simple_irq,
IRQ_TYPE_NONE);
if (ret) {
dev_err(&client->dev,

View File

@ -39,17 +39,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
pinctrl_free_gpio(offset);
}
static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct bgpio_chip *bgc = to_bgpio_chip(chip);
u32 ret = bgc->read_reg(bgc->reg_dir);
if (ret & BIT(offset))
return !!(bgc->read_reg(bgc->reg_set) & BIT(offset));
else
return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset));
}
static int moxart_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -68,8 +57,9 @@ static int moxart_gpio_probe(struct platform_device *pdev)
return PTR_ERR(base);
ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN,
base + GPIO_DATA_OUT, NULL,
base + GPIO_PIN_DIRECTION, NULL, 0);
base + GPIO_DATA_OUT, NULL,
base + GPIO_PIN_DIRECTION, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
if (ret) {
dev_err(&pdev->dev, "bgpio_init failed\n");
return ret;
@ -78,7 +68,6 @@ static int moxart_gpio_probe(struct platform_device *pdev)
bgc->gc.label = "moxart-gpio";
bgc->gc.request = moxart_gpio_request;
bgc->gc.free = moxart_gpio_free;
bgc->gc.get = moxart_gpio_get;
bgc->data = bgc->read_reg(bgc->reg_set);
bgc->gc.base = 0;
bgc->gc.ngpio = 32;

View File

@ -131,7 +131,7 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata;
#define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge)
#define GPIO_INT_BOTH_EDGES 0x4
static struct platform_device_id mxc_gpio_devtype[] = {
static const struct platform_device_id mxc_gpio_devtype[] = {
{
.name = "imx1-gpio",
.driver_data = IMX1_GPIO,
@ -449,7 +449,8 @@ static int 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, 0);
port->base + GPIO_GDIR, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
if (err)
goto out_bgio;

View File

@ -239,7 +239,7 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
return !(dir & mask);
}
static struct platform_device_id mxs_gpio_ids[] = {
static const struct platform_device_id mxs_gpio_ids[] = {
{
.name = "imx23-gpio",
.driver_data = IMX23_GPIO,

View File

@ -488,9 +488,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
unsigned long flags;
unsigned offset = d->hwirq;
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
@ -498,12 +495,18 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL;
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
retval = omap_set_gpio_triggering(bank, offset, type);
if (retval)
goto error;
omap_gpio_init_irq(bank, offset);
if (!omap_gpio_is_input(bank, offset)) {
spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL;
retval = -EINVAL;
goto error;
}
spin_unlock_irqrestore(&bank->lock, flags);
@ -512,6 +515,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
__irq_set_handler_locked(d->irq, handle_edge_irq);
return 0;
error:
if (!BANK_USED(bank))
pm_runtime_put(bank->dev);
return retval;
}
@ -638,15 +646,6 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
return 0;
}
static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset)
{
omap_set_gpio_direction(bank, offset, 1);
omap_set_gpio_irqenable(bank, offset, 0);
omap_clear_gpio_irqstatus(bank, offset);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
omap_clear_gpio_debounce(bank, offset);
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
@ -669,14 +668,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
/* Set trigger to none. You need to enable the desired trigger with
* request_irq() or set_irq_type(). Only do this if the IRQ line has
* not already been requested.
*/
if (!LINE_USED(bank->irq_usage, offset)) {
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
omap_enable_gpio_module(bank, offset);
}
omap_enable_gpio_module(bank, offset);
bank->mod_usage |= BIT(offset);
spin_unlock_irqrestore(&bank->lock, flags);
@ -690,8 +682,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
spin_lock_irqsave(&bank->lock, flags);
bank->mod_usage &= ~(BIT(offset));
if (!LINE_USED(bank->irq_usage, offset)) {
omap_set_gpio_direction(bank, offset, 1);
omap_clear_gpio_debounce(bank, offset);
}
omap_disable_gpio_module(bank, offset);
omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@ -795,11 +790,23 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
omap_gpio_init_irq(bank, offset);
if (!LINE_USED(bank->mod_usage, offset))
omap_set_gpio_direction(bank, offset, 1);
else if (!omap_gpio_is_input(bank, offset))
goto err;
omap_enable_gpio_module(bank, offset);
bank->irq_usage |= BIT(offset);
spin_unlock_irqrestore(&bank->lock, flags);
omap_gpio_unmask_irq(d);
return 0;
err:
spin_unlock_irqrestore(&bank->lock, flags);
if (!BANK_USED(bank))
pm_runtime_put(bank->dev);
return -EINVAL;
}
static void omap_gpio_irq_shutdown(struct irq_data *d)
@ -810,8 +817,12 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
spin_lock_irqsave(&bank->lock, flags);
bank->irq_usage &= ~(BIT(offset));
omap_set_gpio_irqenable(bank, offset, 0);
omap_clear_gpio_irqstatus(bank, offset);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
if (!LINE_USED(bank->mod_usage, offset))
omap_clear_gpio_debounce(bank, offset);
omap_disable_gpio_module(bank, offset);
omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@ -1233,6 +1244,17 @@ static int omap_gpio_probe(struct platform_device *pdev)
return 0;
}
static int omap_gpio_remove(struct platform_device *pdev)
{
struct gpio_bank *bank = platform_get_drvdata(pdev);
list_del(&bank->node);
gpiochip_remove(&bank->chip);
pm_runtime_disable(bank->dev);
return 0;
}
#ifdef CONFIG_ARCH_OMAP2PLUS
#if defined(CONFIG_PM)
@ -1418,6 +1440,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
}
#endif /* CONFIG_PM */
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
void omap2_gpio_prepare_for_idle(int pwr_mode)
{
struct gpio_bank *bank;
@ -1443,6 +1466,7 @@ void omap2_gpio_resume_after_idle(void)
pm_runtime_get_sync(bank->dev);
}
}
#endif
#if defined(CONFIG_PM)
static void omap_gpio_init_context(struct gpio_bank *p)
@ -1598,6 +1622,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match);
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
.remove = omap_gpio_remove,
.driver = {
.name = "omap_gpio",
.pm = &gpio_pm_ops,
@ -1615,3 +1640,13 @@ static int __init omap_gpio_drv_reg(void)
return platform_driver_register(&omap_gpio_driver);
}
postcore_initcall(omap_gpio_drv_reg);
static void __exit omap_gpio_exit(void)
{
platform_driver_unregister(&omap_gpio_driver);
}
module_exit(omap_gpio_exit);
MODULE_DESCRIPTION("omap gpio driver");
MODULE_ALIAS("platform:gpio-omap");
MODULE_LICENSE("GPL v2");

View File

@ -443,12 +443,13 @@ static struct irq_chip pca953x_irq_chip = {
.irq_set_type = pca953x_irq_set_type,
};
static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
{
u8 cur_stat[MAX_BANK];
u8 old_stat[MAX_BANK];
u8 pendings = 0;
u8 trigger[MAX_BANK], triggers = 0;
bool pending_seen = false;
bool trigger_seen = false;
u8 trigger[MAX_BANK];
int ret, i, offset = 0;
switch (chip->chip_type) {
@ -461,7 +462,7 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
}
ret = pca953x_read_regs(chip, offset, cur_stat);
if (ret)
return 0;
return false;
/* Remove output pins from the equation */
for (i = 0; i < NBANK(chip); i++)
@ -471,11 +472,12 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
for (i = 0; i < NBANK(chip); i++) {
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
triggers += trigger[i];
if (trigger[i])
trigger_seen = true;
}
if (!triggers)
return 0;
if (!trigger_seen)
return false;
memcpy(chip->irq_stat, cur_stat, NBANK(chip));
@ -483,10 +485,11 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
(cur_stat[i] & chip->irq_trig_raise[i]);
pending[i] &= trigger[i];
pendings += pending[i];
if (pending[i])
pending_seen = true;
}
return pendings;
return pending_seen;
}
static irqreturn_t pca953x_irq_handler(int irq, void *devid)
@ -630,7 +633,7 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_INVRT, val);
/* To enable register 6, 7 to controll pull up and pull down */
/* To enable register 6, 7 to control pull up and pull down */
memset(val, 0x02, NBANK(chip));
pca953x_write_regs(chip, PCA957X_BKEN, val);

View File

@ -91,6 +91,8 @@ struct pcf857x {
spinlock_t slock; /* protect irq demux */
unsigned out; /* software latch */
unsigned status; /* current status */
unsigned int irq_parent;
unsigned irq_enabled; /* enabled irqs */
int (*write)(struct i2c_client *client, unsigned data);
int (*read)(struct i2c_client *client);
@ -194,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
* interrupt source, just to avoid bad irqs
*/
change = (gpio->status ^ status);
change = (gpio->status ^ status) & gpio->irq_enabled;
for_each_set_bit(i, &change, gpio->chip.ngpio)
handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
gpio->status = status;
@ -209,29 +211,62 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
*/
static void noop(struct irq_data *data) { }
static unsigned int noop_ret(struct irq_data *data)
{
return 0;
}
static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
irq_set_irq_wake(gpio->client->irq, on);
return 0;
int error = 0;
if (gpio->irq_parent) {
error = irq_set_irq_wake(gpio->irq_parent, on);
if (error) {
dev_dbg(&gpio->client->dev,
"irq %u doesn't support irq_set_wake\n",
gpio->irq_parent);
gpio->irq_parent = 0;
}
}
return error;
}
static void pcf857x_irq_enable(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
gpio->irq_enabled |= (1 << data->hwirq);
}
static void pcf857x_irq_disable(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
gpio->irq_enabled &= ~(1 << data->hwirq);
}
static void pcf857x_irq_bus_lock(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
mutex_lock(&gpio->lock);
}
static void pcf857x_irq_bus_sync_unlock(struct irq_data *data)
{
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
mutex_unlock(&gpio->lock);
}
static struct irq_chip pcf857x_irq_chip = {
.name = "pcf857x",
.irq_startup = noop_ret,
.irq_shutdown = noop,
.irq_enable = noop,
.irq_disable = noop,
.irq_enable = pcf857x_irq_enable,
.irq_disable = pcf857x_irq_disable,
.irq_ack = noop,
.irq_mask = noop,
.irq_unmask = noop,
.irq_set_wake = pcf857x_irq_set_wake,
.irq_bus_lock = pcf857x_irq_bus_lock,
.irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock,
};
/*-------------------------------------------------------------------------*/
@ -364,6 +399,7 @@ static int pcf857x_probe(struct i2c_client *client,
gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip,
client->irq, NULL);
gpio->irq_parent = client->irq;
}
/* Let platform code set up the GPIOs and their users.

View File

@ -177,8 +177,17 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
gpio_chip);
int error;
irq_set_irq_wake(p->irq_parent, on);
if (p->irq_parent) {
error = irq_set_irq_wake(p->irq_parent, on);
if (error) {
dev_dbg(&p->pdev->dev,
"irq %u doesn't support irq_set_wake\n",
p->irq_parent);
p->irq_parent = 0;
}
}
if (!p->clk)
return 0;

View File

@ -58,7 +58,7 @@
#define XWAY_STP_ADSL_MASK 0x3
/* 2 groups of 3 bits can be driven by the phys */
#define XWAY_STP_PHY_MASK 0x3
#define XWAY_STP_PHY_MASK 0x7
#define XWAY_STP_PHY1_SHIFT 27
#define XWAY_STP_PHY2_SHIFT 15
@ -200,7 +200,7 @@ static int xway_stp_hw_init(struct xway_stp *chip)
static int xway_stp_probe(struct platform_device *pdev)
{
struct resource *res;
const __be32 *shadow, *groups, *dsl, *phy;
u32 shadow, groups, dsl, phy;
struct xway_stp *chip;
struct clk *clk;
int ret = 0;
@ -223,33 +223,28 @@ static int xway_stp_probe(struct platform_device *pdev)
chip->gc.owner = THIS_MODULE;
/* store the shadow value if one was passed by the devicetree */
shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL);
if (shadow)
chip->shadow = be32_to_cpu(*shadow);
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
chip->shadow = shadow;
/* find out which gpio groups should be enabled */
groups = of_get_property(pdev->dev.of_node, "lantiq,groups", NULL);
if (groups)
chip->groups = be32_to_cpu(*groups) & XWAY_STP_GROUP_MASK;
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,groups", &groups))
chip->groups = groups & XWAY_STP_GROUP_MASK;
else
chip->groups = XWAY_STP_GROUP0;
chip->gc.ngpio = fls(chip->groups) * 8;
/* find out which gpios are controlled by the dsl core */
dsl = of_get_property(pdev->dev.of_node, "lantiq,dsl", NULL);
if (dsl)
chip->dsl = be32_to_cpu(*dsl) & XWAY_STP_ADSL_MASK;
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,dsl", &dsl))
chip->dsl = dsl & XWAY_STP_ADSL_MASK;
/* find out which gpios are controlled by the phys */
if (of_machine_is_compatible("lantiq,ar9") ||
of_machine_is_compatible("lantiq,gr9") ||
of_machine_is_compatible("lantiq,vr9")) {
phy = of_get_property(pdev->dev.of_node, "lantiq,phy1", NULL);
if (phy)
chip->phy1 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK;
phy = of_get_property(pdev->dev.of_node, "lantiq,phy2", NULL);
if (phy)
chip->phy2 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK;
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy1", &phy))
chip->phy1 = phy & XWAY_STP_PHY_MASK;
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy2", &phy))
chip->phy2 = phy & XWAY_STP_PHY_MASK;
}
/* check which edge trigger we should use, default to a falling edge */

View File

@ -292,7 +292,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev)
BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0);
kfree(tb10x_gpio->domain->gc);
irq_domain_remove(tb10x_gpio->domain);
free_irq(tb10x_gpio->irq, tb10x_gpio);
}
gpiochip_remove(&tb10x_gpio->gc);

View File

@ -288,7 +288,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
/* if gpio is edge triggered, clear condition
* before executing the hander so that we don't
* before executing the handler so that we don't
* miss edges
*/
if (lvl & (0x100 << pin)) {

View File

@ -440,7 +440,7 @@ static int ts5500_dio_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id ts5500_dio_ids[] = {
static const struct platform_device_id ts5500_dio_ids[] = {
{ "ts5500-dio1", TS5500_DIO1 },
{ "ts5500-dio2", TS5500_DIO2 },
{ "ts5500-dio-lcd", TS5500_LCD },

View File

@ -25,8 +25,11 @@
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/acpi.h>
#include <linux/basic_mmio_gpio.h>
#include "gpiolib.h"
#define XGENE_MAX_GPIO_DS 22
#define XGENE_MAX_GPIO_DS_IRQ 6
@ -112,7 +115,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!priv->irq)
return -ENOMEM;
memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS);
for (i = 0; i < priv->nirq; i++) {
priv->irq[default_lines[i]] = platform_get_irq(pdev, i);
@ -129,6 +131,11 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
else
dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n");
if (priv->nirq > 0) {
/* Register interrupt handlers for gpio signaled acpi events */
acpi_gpiochip_request_interrupts(&priv->bgc.gc);
}
return ret;
}
@ -136,6 +143,10 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)
{
struct xgene_gpio_sb *priv = platform_get_drvdata(pdev);
if (priv->nirq > 0) {
acpi_gpiochip_free_interrupts(&priv->bgc.gc);
}
return bgpio_remove(&priv->bgc);
}
@ -145,10 +156,19 @@ static const struct of_device_id xgene_gpio_sb_of_match[] = {
};
MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_gpio_sb_acpi_match[] = {
{"APMC0D15", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, xgene_gpio_sb_acpi_match);
#endif
static struct platform_driver xgene_gpio_sb_driver = {
.driver = {
.name = "xgene-gpio-sb",
.of_match_table = xgene_gpio_sb_of_match,
.acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match),
},
.probe = xgene_gpio_sb_probe,
.remove = xgene_gpio_sb_remove,

View File

@ -41,10 +41,10 @@
/**
* struct xgpio_instance - Stores information about GPIO device
* @mmchip: OF GPIO chip for memory mapped banks
* @gpio_width: GPIO width for every channel
* @gpio_state: GPIO state shadow register
* @gpio_dir: GPIO direction shadow register
* @gpio_lock: Lock used for synchronization
* @inited: True if the port has been inited
*/
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
@ -231,6 +231,8 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
* @pdev: pointer to the platform device
*
* This function remove gpiochips and frees all the allocated resources.
*
* Return: 0 always
*/
static int xgpio_remove(struct platform_device *pdev)
{

View File

@ -0,0 +1,427 @@
/*
* Copyright (C) 2003-2015 Broadcom Corporation
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
/*
* XLP GPIO has multiple 32 bit registers for each feature where each register
* controls 32 pins. So, pins up to 64 require 2 32-bit registers and up to 96
* require 3 32-bit registers for each feature.
* Here we only define offset of the first register for each feature. Offset of
* the registers for pins greater than 32 can be calculated as following(Use
* GPIO_INT_STAT as example):
*
* offset = (gpio / XLP_GPIO_REGSZ) * 4;
* reg_addr = addr + offset;
*
* where addr is base address of the that feature register and gpio is the pin.
*/
#define GPIO_OUTPUT_EN 0x00
#define GPIO_PADDRV 0x08
#define GPIO_INT_EN00 0x18
#define GPIO_INT_EN10 0x20
#define GPIO_INT_EN20 0x28
#define GPIO_INT_EN30 0x30
#define GPIO_INT_POL 0x38
#define GPIO_INT_TYPE 0x40
#define GPIO_INT_STAT 0x48
#define GPIO_9XX_BYTESWAP 0X00
#define GPIO_9XX_CTRL 0X04
#define GPIO_9XX_OUTPUT_EN 0x14
#define GPIO_9XX_PADDRV 0x24
/*
* Only for 4 interrupt enable reg are defined for now,
* total reg available are 12.
*/
#define GPIO_9XX_INT_EN00 0x44
#define GPIO_9XX_INT_EN10 0x54
#define GPIO_9XX_INT_EN20 0x64
#define GPIO_9XX_INT_EN30 0x74
#define GPIO_9XX_INT_POL 0x104
#define GPIO_9XX_INT_TYPE 0x114
#define GPIO_9XX_INT_STAT 0x124
#define GPIO_3XX_INT_EN00 0x18
#define GPIO_3XX_INT_EN10 0x20
#define GPIO_3XX_INT_EN20 0x28
#define GPIO_3XX_INT_EN30 0x30
#define GPIO_3XX_INT_POL 0x78
#define GPIO_3XX_INT_TYPE 0x80
#define GPIO_3XX_INT_STAT 0x88
/* Interrupt type register mask */
#define XLP_GPIO_IRQ_TYPE_LVL 0x0
#define XLP_GPIO_IRQ_TYPE_EDGE 0x1
/* Interrupt polarity register mask */
#define XLP_GPIO_IRQ_POL_HIGH 0x0
#define XLP_GPIO_IRQ_POL_LOW 0x1
#define XLP_GPIO_REGSZ 32
#define XLP_GPIO_IRQ_BASE 768
#define XLP_MAX_NR_GPIO 96
/* XLP variants supported by this driver */
enum {
XLP_GPIO_VARIANT_XLP832 = 1,
XLP_GPIO_VARIANT_XLP316,
XLP_GPIO_VARIANT_XLP208,
XLP_GPIO_VARIANT_XLP980,
XLP_GPIO_VARIANT_XLP532
};
struct xlp_gpio_priv {
struct gpio_chip chip;
DECLARE_BITMAP(gpio_enabled_mask, XLP_MAX_NR_GPIO);
void __iomem *gpio_intr_en; /* pointer to first intr enable reg */
void __iomem *gpio_intr_stat; /* pointer to first intr status reg */
void __iomem *gpio_intr_type; /* pointer to first intr type reg */
void __iomem *gpio_intr_pol; /* pointer to first intr polarity reg */
void __iomem *gpio_out_en; /* pointer to first output enable reg */
void __iomem *gpio_paddrv; /* pointer to first pad drive reg */
spinlock_t lock;
};
static struct xlp_gpio_priv *gpio_chip_to_xlp_priv(struct gpio_chip *gc)
{
return container_of(gc, struct xlp_gpio_priv, chip);
}
static int xlp_gpio_get_reg(void __iomem *addr, unsigned gpio)
{
u32 pos, regset;
pos = gpio % XLP_GPIO_REGSZ;
regset = (gpio / XLP_GPIO_REGSZ) * 4;
return !!(readl(addr + regset) & BIT(pos));
}
static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state)
{
u32 value, pos, regset;
pos = gpio % XLP_GPIO_REGSZ;
regset = (gpio / XLP_GPIO_REGSZ) * 4;
value = readl(addr + regset);
if (state)
value |= BIT(pos);
else
value &= ~BIT(pos);
writel(value, addr + regset);
}
static void xlp_gpio_irq_disable(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
__clear_bit(d->hwirq, priv->gpio_enabled_mask);
spin_unlock_irqrestore(&priv->lock, flags);
}
static void xlp_gpio_irq_mask_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
xlp_gpio_set_reg(priv->gpio_intr_stat, d->hwirq, 0x1);
__clear_bit(d->hwirq, priv->gpio_enabled_mask);
spin_unlock_irqrestore(&priv->lock, flags);
}
static void xlp_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x1);
__set_bit(d->hwirq, priv->gpio_enabled_mask);
spin_unlock_irqrestore(&priv->lock, flags);
}
static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
int pol, irq_type;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
pol = XLP_GPIO_IRQ_POL_HIGH;
break;
case IRQ_TYPE_EDGE_FALLING:
irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
pol = XLP_GPIO_IRQ_POL_LOW;
break;
case IRQ_TYPE_LEVEL_HIGH:
irq_type = XLP_GPIO_IRQ_TYPE_LVL;
pol = XLP_GPIO_IRQ_POL_HIGH;
break;
case IRQ_TYPE_LEVEL_LOW:
irq_type = XLP_GPIO_IRQ_TYPE_LVL;
pol = XLP_GPIO_IRQ_POL_LOW;
break;
default:
return -EINVAL;
}
xlp_gpio_set_reg(priv->gpio_intr_type, d->hwirq, irq_type);
xlp_gpio_set_reg(priv->gpio_intr_pol, d->hwirq, pol);
return 0;
}
static struct irq_chip xlp_gpio_irq_chip = {
.name = "XLP-GPIO",
.irq_mask_ack = xlp_gpio_irq_mask_ack,
.irq_disable = xlp_gpio_irq_disable,
.irq_set_type = xlp_gpio_set_irq_type,
.irq_unmask = xlp_gpio_irq_unmask,
.flags = IRQCHIP_ONESHOT_SAFE,
};
static irqreturn_t xlp_gpio_generic_handler(int irq, void *data)
{
struct xlp_gpio_priv *priv = data;
int gpio, regoff;
u32 gpio_stat;
regoff = -1;
gpio_stat = 0;
for_each_set_bit(gpio, priv->gpio_enabled_mask, XLP_MAX_NR_GPIO) {
if (regoff != gpio / XLP_GPIO_REGSZ) {
regoff = gpio / XLP_GPIO_REGSZ;
gpio_stat = readl(priv->gpio_intr_stat + regoff * 4);
}
if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
generic_handle_irq(irq_find_mapping(
priv->chip.irqdomain, gpio));
}
return IRQ_HANDLED;
}
static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
{
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
BUG_ON(gpio >= gc->ngpio);
xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x1);
return 0;
}
static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio)
{
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
BUG_ON(gpio >= gc->ngpio);
xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x0);
return 0;
}
static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio)
{
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
BUG_ON(gpio >= gc->ngpio);
return xlp_gpio_get_reg(priv->gpio_paddrv, gpio);
}
static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state)
{
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
BUG_ON(gpio >= gc->ngpio);
xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state);
}
static const struct of_device_id xlp_gpio_of_ids[] = {
{
.compatible = "netlogic,xlp832-gpio",
.data = (void *)XLP_GPIO_VARIANT_XLP832,
},
{
.compatible = "netlogic,xlp316-gpio",
.data = (void *)XLP_GPIO_VARIANT_XLP316,
},
{
.compatible = "netlogic,xlp208-gpio",
.data = (void *)XLP_GPIO_VARIANT_XLP208,
},
{
.compatible = "netlogic,xlp980-gpio",
.data = (void *)XLP_GPIO_VARIANT_XLP980,
},
{
.compatible = "netlogic,xlp532-gpio",
.data = (void *)XLP_GPIO_VARIANT_XLP532,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
static int xlp_gpio_probe(struct platform_device *pdev)
{
struct gpio_chip *gc;
struct resource *iores;
struct xlp_gpio_priv *priv;
const struct of_device_id *of_id;
void __iomem *gpio_base;
int irq_base, irq, err;
int ngpio;
u32 soc_type;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iores)
return -ENODEV;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
gpio_base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(gpio_base))
return PTR_ERR(gpio_base);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev);
if (!of_id) {
dev_err(&pdev->dev, "Failed to get soc type!\n");
return -ENODEV;
}
soc_type = (uintptr_t) of_id->data;
switch (soc_type) {
case XLP_GPIO_VARIANT_XLP832:
priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
priv->gpio_intr_stat = gpio_base + GPIO_INT_STAT;
priv->gpio_intr_type = gpio_base + GPIO_INT_TYPE;
priv->gpio_intr_pol = gpio_base + GPIO_INT_POL;
priv->gpio_intr_en = gpio_base + GPIO_INT_EN00;
ngpio = 41;
break;
case XLP_GPIO_VARIANT_XLP208:
case XLP_GPIO_VARIANT_XLP316:
priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
priv->gpio_intr_stat = gpio_base + GPIO_3XX_INT_STAT;
priv->gpio_intr_type = gpio_base + GPIO_3XX_INT_TYPE;
priv->gpio_intr_pol = gpio_base + GPIO_3XX_INT_POL;
priv->gpio_intr_en = gpio_base + GPIO_3XX_INT_EN00;
ngpio = (soc_type == XLP_GPIO_VARIANT_XLP208) ? 42 : 57;
break;
case XLP_GPIO_VARIANT_XLP980:
case XLP_GPIO_VARIANT_XLP532:
priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN;
priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV;
priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT;
priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE;
priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL;
priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00;
ngpio = (soc_type == XLP_GPIO_VARIANT_XLP980) ? 66 : 67;
break;
default:
dev_err(&pdev->dev, "Unknown Processor type!\n");
return -ENODEV;
}
bitmap_zero(priv->gpio_enabled_mask, XLP_MAX_NR_GPIO);
gc = &priv->chip;
gc->owner = THIS_MODULE;
gc->label = dev_name(&pdev->dev);
gc->base = 0;
gc->dev = &pdev->dev;
gc->ngpio = ngpio;
gc->of_node = pdev->dev.of_node;
gc->direction_output = xlp_gpio_dir_output;
gc->direction_input = xlp_gpio_dir_input;
gc->set = xlp_gpio_set;
gc->get = xlp_gpio_get;
spin_lock_init(&priv->lock);
err = devm_request_irq(&pdev->dev, irq, xlp_gpio_generic_handler,
IRQ_TYPE_NONE, pdev->name, priv);
if (err)
return err;
irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
if (irq_base < 0) {
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
return err;
}
err = gpiochip_add(gc);
if (err < 0)
goto out_free_desc;
err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base,
handle_level_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n");
goto out_gpio_remove;
}
dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
return 0;
out_gpio_remove:
gpiochip_remove(gc);
out_free_desc:
irq_free_descs(irq_base, gc->ngpio);
return err;
}
static struct platform_driver xlp_gpio_driver = {
.driver = {
.name = "xlp-gpio",
.of_match_table = xlp_gpio_of_ids,
},
.probe = xlp_gpio_probe,
};
module_platform_driver(xlp_gpio_driver);
MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@broadcom.com>");
MODULE_DESCRIPTION("Netlogic XLP GPIO Driver");
MODULE_LICENSE("GPL v2");

View File

@ -18,34 +18,47 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#define DRIVER_NAME "zynq-gpio"
/* Maximum banks */
#define ZYNQ_GPIO_MAX_BANK 4
#define ZYNQMP_GPIO_MAX_BANK 6
#define ZYNQ_GPIO_BANK0_NGPIO 32
#define ZYNQ_GPIO_BANK1_NGPIO 22
#define ZYNQ_GPIO_BANK2_NGPIO 32
#define ZYNQ_GPIO_BANK3_NGPIO 32
#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \
ZYNQ_GPIO_BANK1_NGPIO + \
ZYNQ_GPIO_BANK2_NGPIO + \
ZYNQ_GPIO_BANK3_NGPIO)
#define ZYNQMP_GPIO_BANK0_NGPIO 26
#define ZYNQMP_GPIO_BANK1_NGPIO 26
#define ZYNQMP_GPIO_BANK2_NGPIO 26
#define ZYNQMP_GPIO_BANK3_NGPIO 32
#define ZYNQMP_GPIO_BANK4_NGPIO 32
#define ZYNQMP_GPIO_BANK5_NGPIO 32
#define ZYNQ_GPIO_BANK0_PIN_MIN 0
#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \
ZYNQ_GPIO_BANK0_NGPIO - 1)
#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1)
#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \
ZYNQ_GPIO_BANK1_NGPIO - 1)
#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1)
#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \
ZYNQ_GPIO_BANK2_NGPIO - 1)
#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1)
#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \
ZYNQ_GPIO_BANK3_NGPIO - 1)
#define ZYNQ_GPIO_NR_GPIOS 118
#define ZYNQMP_GPIO_NR_GPIOS 174
#define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0
#define ZYNQ_GPIO_BANK0_PIN_MAX(str) (ZYNQ_GPIO_BANK0_PIN_MIN(str) + \
ZYNQ##str##_GPIO_BANK0_NGPIO - 1)
#define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1)
#define ZYNQ_GPIO_BANK1_PIN_MAX(str) (ZYNQ_GPIO_BANK1_PIN_MIN(str) + \
ZYNQ##str##_GPIO_BANK1_NGPIO - 1)
#define ZYNQ_GPIO_BANK2_PIN_MIN(str) (ZYNQ_GPIO_BANK1_PIN_MAX(str) + 1)
#define ZYNQ_GPIO_BANK2_PIN_MAX(str) (ZYNQ_GPIO_BANK2_PIN_MIN(str) + \
ZYNQ##str##_GPIO_BANK2_NGPIO - 1)
#define ZYNQ_GPIO_BANK3_PIN_MIN(str) (ZYNQ_GPIO_BANK2_PIN_MAX(str) + 1)
#define ZYNQ_GPIO_BANK3_PIN_MAX(str) (ZYNQ_GPIO_BANK3_PIN_MIN(str) + \
ZYNQ##str##_GPIO_BANK3_NGPIO - 1)
#define ZYNQ_GPIO_BANK4_PIN_MIN(str) (ZYNQ_GPIO_BANK3_PIN_MAX(str) + 1)
#define ZYNQ_GPIO_BANK4_PIN_MAX(str) (ZYNQ_GPIO_BANK4_PIN_MIN(str) + \
ZYNQ##str##_GPIO_BANK4_NGPIO - 1)
#define ZYNQ_GPIO_BANK5_PIN_MIN(str) (ZYNQ_GPIO_BANK4_PIN_MAX(str) + 1)
#define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \
ZYNQ##str##_GPIO_BANK5_NGPIO - 1)
/* Register offsets for the GPIO device */
@ -89,12 +102,30 @@
* @base_addr: base address of the GPIO device
* @clk: clock resource for this controller
* @irq: interrupt for the GPIO device
* @p_data: pointer to platform data
*/
struct zynq_gpio {
struct gpio_chip chip;
void __iomem *base_addr;
struct clk *clk;
int irq;
const struct zynq_platform_data *p_data;
};
/**
* struct zynq_platform_data - zynq gpio platform data structure
* @label: string to store in gpio->label
* @ngpio: max number of gpio pins
* @max_bank: maximum number of gpio banks
* @bank_min: this array represents bank's min pin
* @bank_max: this array represents bank's max pin
*/
struct zynq_platform_data {
const char *label;
u16 ngpio;
int max_bank;
int bank_min[ZYNQMP_GPIO_MAX_BANK];
int bank_max[ZYNQMP_GPIO_MAX_BANK];
};
static struct irq_chip zynq_gpio_level_irqchip;
@ -112,39 +143,26 @@ static struct irq_chip zynq_gpio_edge_irqchip;
*/
static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
unsigned int *bank_num,
unsigned int *bank_pin_num)
unsigned int *bank_pin_num,
struct zynq_gpio *gpio)
{
switch (pin_num) {
case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX:
*bank_num = 0;
*bank_pin_num = pin_num;
break;
case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX:
*bank_num = 1;
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN;
break;
case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX:
*bank_num = 2;
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN;
break;
case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX:
*bank_num = 3;
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN;
break;
default:
WARN(true, "invalid GPIO pin number: %u", pin_num);
*bank_num = 0;
*bank_pin_num = 0;
break;
}
}
int bank;
static const unsigned int zynq_gpio_bank_offset[] = {
ZYNQ_GPIO_BANK0_PIN_MIN,
ZYNQ_GPIO_BANK1_PIN_MIN,
ZYNQ_GPIO_BANK2_PIN_MIN,
ZYNQ_GPIO_BANK3_PIN_MIN,
};
for (bank = 0; bank < gpio->p_data->max_bank; bank++) {
if ((pin_num >= gpio->p_data->bank_min[bank]) &&
(pin_num <= gpio->p_data->bank_max[bank])) {
*bank_num = bank;
*bank_pin_num = pin_num -
gpio->p_data->bank_min[bank];
return;
}
}
/* default */
WARN(true, "invalid GPIO pin number: %u", pin_num);
*bank_num = 0;
*bank_pin_num = 0;
}
/**
* zynq_gpio_get_value - Get the state of the specified pin of GPIO device
@ -161,7 +179,7 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
data = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
@ -185,7 +203,7 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
unsigned int reg_offset, bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
/* only 16 data bits in bit maskable reg */
@ -222,7 +240,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
/* bank 0 pins 7 and 8 are special and cannot be used as inputs */
if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
@ -255,7 +273,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
/* set the GPIO pin as output */
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
@ -286,7 +304,7 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data)
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
}
@ -306,7 +324,7 @@ static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num));
}
@ -325,7 +343,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data)
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
}
@ -335,7 +353,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data)
* @irq_data: irq data containing irq number of gpio pin for the interrupt
* to enable
*
* Clears the INTSTS bit and unmasks the given interrrupt.
* Clears the INTSTS bit and unmasks the given interrupt.
*/
static void zynq_gpio_irq_enable(struct irq_data *irq_data)
{
@ -375,7 +393,7 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq;
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
int_type = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
@ -470,7 +488,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
unsigned int bank_num,
unsigned long pending)
{
unsigned int bank_offset = zynq_gpio_bank_offset[bank_num];
unsigned int bank_offset = gpio->p_data->bank_min[bank_num];
struct irq_domain *irqdomain = gpio->chip.irqdomain;
int offset;
@ -505,7 +523,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
chained_irq_enter(irqchip, desc);
for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) {
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) {
int_sts = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
int_enb = readl_relaxed(gpio->base_addr +
@ -582,6 +600,46 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
zynq_gpio_runtime_resume, NULL)
};
static const struct zynq_platform_data zynqmp_gpio_def = {
.label = "zynqmp_gpio",
.ngpio = ZYNQMP_GPIO_NR_GPIOS,
.max_bank = ZYNQMP_GPIO_MAX_BANK,
.bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP),
.bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(MP),
.bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(MP),
.bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(MP),
.bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(MP),
.bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(MP),
.bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(MP),
.bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(MP),
.bank_min[4] = ZYNQ_GPIO_BANK4_PIN_MIN(MP),
.bank_max[4] = ZYNQ_GPIO_BANK4_PIN_MAX(MP),
.bank_min[5] = ZYNQ_GPIO_BANK5_PIN_MIN(MP),
.bank_max[5] = ZYNQ_GPIO_BANK5_PIN_MAX(MP),
};
static const struct zynq_platform_data zynq_gpio_def = {
.label = "zynq_gpio",
.ngpio = ZYNQ_GPIO_NR_GPIOS,
.max_bank = ZYNQ_GPIO_MAX_BANK,
.bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
.bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(),
.bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(),
.bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(),
.bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(),
.bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(),
.bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(),
.bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(),
};
static const struct of_device_id zynq_gpio_of_match[] = {
{ .compatible = "xlnx,zynq-gpio-1.0", .data = (void *)&zynq_gpio_def },
{ .compatible = "xlnx,zynqmp-gpio-1.0",
.data = (void *)&zynqmp_gpio_def },
{ /* end of table */ }
};
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
/**
* zynq_gpio_probe - Initialization method for a zynq_gpio device
* @pdev: platform device instance
@ -599,11 +657,18 @@ static int zynq_gpio_probe(struct platform_device *pdev)
struct zynq_gpio *gpio;
struct gpio_chip *chip;
struct resource *res;
const struct of_device_id *match;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
if (!match) {
dev_err(&pdev->dev, "of_match_node() failed\n");
return -EINVAL;
}
gpio->p_data = match->data;
platform_set_drvdata(pdev, gpio);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -619,7 +684,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
/* configure the gpio chip */
chip = &gpio->chip;
chip->label = "zynq_gpio";
chip->label = gpio->p_data->label;
chip->owner = THIS_MODULE;
chip->dev = &pdev->dev;
chip->get = zynq_gpio_get_value;
@ -629,7 +694,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
chip->direction_input = zynq_gpio_dir_in;
chip->direction_output = zynq_gpio_dir_out;
chip->base = -1;
chip->ngpio = ZYNQ_GPIO_NR_GPIOS;
chip->ngpio = gpio->p_data->ngpio;
/* Enable GPIO clock */
gpio->clk = devm_clk_get(&pdev->dev, NULL);
@ -651,7 +716,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
}
/* disable interrupts for all banks */
for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++)
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
@ -695,12 +760,6 @@ static int zynq_gpio_remove(struct platform_device *pdev)
return 0;
}
static struct of_device_id zynq_gpio_of_match[] = {
{ .compatible = "xlnx,zynq-gpio-1.0", },
{ /* end of table */ }
};
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
static struct platform_driver zynq_gpio_driver = {
.driver = {
.name = DRIVER_NAME,

View File

@ -114,10 +114,11 @@ static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip,
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
* @pin: ACPI GPIO pin number (0-based, controller-relative)
*
* Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
* error value
* Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
* error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO
* controller does not have gpiochip registered at the moment. This is to
* support probe deferral.
*/
static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
{
struct gpio_chip *chip;
@ -131,7 +132,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
chip = gpiochip_find(handle, acpi_gpiochip_find);
if (!chip)
return ERR_PTR(-ENODEV);
return ERR_PTR(-EPROBE_DEFER);
offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
if (offset < 0)
@ -307,6 +308,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
acpi_walk_resources(handle, "_AEI",
acpi_gpiochip_request_interrupt, acpi_gpio);
}
EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
/**
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
@ -346,6 +348,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
kfree(event);
}
}
EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts);
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios)
@ -514,6 +517,35 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
/**
* acpi_dev_gpio_irq_get() - Find GpioInt and translate it to Linux IRQ number
* @adev: pointer to a ACPI device to get IRQ from
* @index: index of GpioInt resource (starting from %0)
*
* If the device has one or more GpioInt resources, this function can be
* used to translate from the GPIO offset in the resource to the Linux IRQ
* number.
*
* Return: Linux IRQ number (>%0) on success, negative errno on failure.
*/
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
{
int idx, i;
for (i = 0, idx = 0; idx <= index; i++) {
struct acpi_gpio_info info;
struct gpio_desc *desc;
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
if (IS_ERR(desc))
break;
if (info.gpioint && idx++ == index)
return gpiod_to_irq(desc);
}
return -ENOENT;
}
EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
static acpi_status
acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
u32 bits, u64 *value, void *handler_context,

View File

@ -242,7 +242,7 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
{
/*
* We're discouraging gpio_cells < 2, since that way you'll have to
* write your own xlate function (that will have to retrive the GPIO
* write your own xlate function (that will have to retrieve the GPIO
* number and the flags from a single gpio cell -- this is possible,
* but not recommended).
*/

View File

@ -6,14 +6,29 @@
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include <linux/slab.h>
#include "gpiolib.h"
static DEFINE_IDR(dirent_idr);
#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
#define GPIO_IRQF_TRIGGER_RISING BIT(1)
#define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \
GPIO_IRQF_TRIGGER_RISING)
struct gpiod_data {
struct gpio_desc *desc;
/* lock protects against unexport_gpio() being called while
* sysfs files are active.
struct mutex mutex;
struct kernfs_node *value_kn;
int irq;
unsigned char irq_flags;
bool direction_can_change;
};
/*
* Lock to serialise gpiod export and unexport, and prevent re-export of
* gpiod whose chip is being unregistered.
*/
static DEFINE_MUTEX(sysfs_lock);
@ -38,38 +53,35 @@ static DEFINE_MUTEX(sysfs_lock);
* /edge configuration
*/
static ssize_t gpio_direction_show(struct device *dev,
static ssize_t direction_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gpio_desc *desc = dev_get_drvdata(dev);
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
ssize_t status;
mutex_lock(&sysfs_lock);
mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) {
status = -EIO;
} else {
gpiod_get_direction(desc);
status = sprintf(buf, "%s\n",
gpiod_get_direction(desc);
status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in");
}
mutex_unlock(&sysfs_lock);
mutex_unlock(&data->mutex);
return status;
}
static ssize_t gpio_direction_store(struct device *dev,
static ssize_t direction_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct gpio_desc *desc = dev_get_drvdata(dev);
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
ssize_t status;
mutex_lock(&sysfs_lock);
mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else if (sysfs_streq(buf, "high"))
if (sysfs_streq(buf, "high"))
status = gpiod_direction_output_raw(desc, 1);
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
status = gpiod_direction_output_raw(desc, 0);
@ -78,43 +90,40 @@ static ssize_t gpio_direction_store(struct device *dev,
else
status = -EINVAL;
mutex_unlock(&sysfs_lock);
mutex_unlock(&data->mutex);
return status ? : size;
}
static DEVICE_ATTR_RW(direction);
static /* const */ DEVICE_ATTR(direction, 0644,
gpio_direction_show, gpio_direction_store);
static ssize_t gpio_value_show(struct device *dev,
static ssize_t value_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gpio_desc *desc = dev_get_drvdata(dev);
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
ssize_t status;
mutex_lock(&sysfs_lock);
mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else
status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
mutex_unlock(&data->mutex);
mutex_unlock(&sysfs_lock);
return status;
}
static ssize_t gpio_value_store(struct device *dev,
static ssize_t value_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct gpio_desc *desc = dev_get_drvdata(dev);
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
ssize_t status;
mutex_lock(&sysfs_lock);
mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else if (!test_bit(FLAG_IS_OUT, &desc->flags))
if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
status = -EPERM;
else {
} else {
long value;
status = kstrtol(buf, 0, &value);
@ -124,172 +133,168 @@ static ssize_t gpio_value_store(struct device *dev,
}
}
mutex_unlock(&sysfs_lock);
mutex_unlock(&data->mutex);
return status;
}
static DEVICE_ATTR(value, 0644,
gpio_value_show, gpio_value_store);
static DEVICE_ATTR_RW(value);
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
{
struct kernfs_node *value_sd = priv;
struct gpiod_data *data = priv;
sysfs_notify_dirent(data->value_kn);
sysfs_notify_dirent(value_sd);
return IRQ_HANDLED;
}
static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
unsigned long gpio_flags)
/* Caller holds gpiod-data mutex. */
static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
{
struct kernfs_node *value_sd;
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
unsigned long irq_flags;
int ret, irq, id;
int ret;
if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
return 0;
irq = gpiod_to_irq(desc);
if (irq < 0)
data->irq = gpiod_to_irq(desc);
if (data->irq < 0)
return -EIO;
id = desc->flags >> ID_SHIFT;
value_sd = idr_find(&dirent_idr, id);
if (value_sd)
free_irq(irq, value_sd);
desc->flags &= ~GPIO_TRIGGER_MASK;
if (!gpio_flags) {
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
ret = 0;
goto free_id;
}
data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value");
if (!data->value_kn)
return -ENODEV;
irq_flags = IRQF_SHARED;
if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
if (flags & GPIO_IRQF_TRIGGER_FALLING)
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
if (flags & GPIO_IRQF_TRIGGER_RISING)
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
if (!value_sd) {
value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
if (!value_sd) {
ret = -ENODEV;
goto err_out;
}
ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
if (ret < 0)
goto free_sd;
id = ret;
desc->flags &= GPIO_FLAGS_MASK;
desc->flags |= (unsigned long)id << ID_SHIFT;
if (desc->flags >> ID_SHIFT != id) {
ret = -ERANGE;
goto free_id;
}
}
ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
"gpiolib", value_sd);
if (ret < 0)
goto free_id;
/*
* FIXME: This should be done in the irq_request_resources callback
* when the irq is requested, but a few drivers currently fail
* to do so.
*
* Remove this redundant call (along with the corresponding
* unlock) when those drivers have been fixed.
*/
ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
if (ret < 0) {
gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
goto free_id;
}
if (ret < 0)
goto err_put_kn;
ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags,
"gpiolib", data);
if (ret < 0)
goto err_unlock;
data->irq_flags = flags;
desc->flags |= gpio_flags;
return 0;
free_id:
idr_remove(&dirent_idr, id);
desc->flags &= GPIO_FLAGS_MASK;
free_sd:
if (value_sd)
sysfs_put(value_sd);
err_out:
err_unlock:
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
err_put_kn:
sysfs_put(data->value_kn);
return ret;
}
/*
* Caller holds gpiod-data mutex (unless called after class-device
* deregistration).
*/
static void gpio_sysfs_free_irq(struct device *dev)
{
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
data->irq_flags = 0;
free_irq(data->irq, data);
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
sysfs_put(data->value_kn);
}
static const struct {
const char *name;
unsigned long flags;
unsigned char flags;
} trigger_types[] = {
{ "none", 0 },
{ "falling", BIT(FLAG_TRIG_FALL) },
{ "rising", BIT(FLAG_TRIG_RISE) },
{ "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) },
{ "falling", GPIO_IRQF_TRIGGER_FALLING },
{ "rising", GPIO_IRQF_TRIGGER_RISING },
{ "both", GPIO_IRQF_TRIGGER_BOTH },
};
static ssize_t gpio_edge_show(struct device *dev,
static ssize_t edge_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_desc *desc = dev_get_drvdata(dev);
ssize_t status;
struct gpiod_data *data = dev_get_drvdata(dev);
ssize_t status = 0;
int i;
mutex_lock(&sysfs_lock);
mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else {
int i;
status = 0;
for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
if ((desc->flags & GPIO_TRIGGER_MASK)
== trigger_types[i].flags) {
status = sprintf(buf, "%s\n",
trigger_types[i].name);
break;
}
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
if (data->irq_flags == trigger_types[i].flags) {
status = sprintf(buf, "%s\n", trigger_types[i].name);
break;
}
}
mutex_unlock(&sysfs_lock);
mutex_unlock(&data->mutex);
return status;
}
static ssize_t gpio_edge_store(struct device *dev,
static ssize_t edge_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct gpio_desc *desc = dev_get_drvdata(dev);
ssize_t status;
int i;
struct gpiod_data *data = dev_get_drvdata(dev);
unsigned char flags;
ssize_t status = size;
int i;
for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
if (sysfs_streq(trigger_types[i].name, buf))
goto found;
return -EINVAL;
break;
}
found:
mutex_lock(&sysfs_lock);
if (i == ARRAY_SIZE(trigger_types))
return -EINVAL;
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else {
status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
flags = trigger_types[i].flags;
mutex_lock(&data->mutex);
if (flags == data->irq_flags) {
status = size;
goto out_unlock;
}
if (data->irq_flags)
gpio_sysfs_free_irq(dev);
if (flags) {
status = gpio_sysfs_request_irq(dev, flags);
if (!status)
status = size;
}
mutex_unlock(&sysfs_lock);
out_unlock:
mutex_unlock(&data->mutex);
return status;
}
static DEVICE_ATTR_RW(edge);
static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
int value)
/* Caller holds gpiod-data mutex. */
static int gpio_sysfs_set_active_low(struct device *dev, int value)
{
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
int status = 0;
unsigned int flags = data->irq_flags;
if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
return 0;
@ -300,69 +305,59 @@ static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
/* reconfigure poll(2) support if enabled on one edge only */
if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
!!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
gpio_setup_irq(desc, dev, 0);
status = gpio_setup_irq(desc, dev, trigger_flags);
if (flags == GPIO_IRQF_TRIGGER_FALLING ||
flags == GPIO_IRQF_TRIGGER_RISING) {
gpio_sysfs_free_irq(dev);
status = gpio_sysfs_request_irq(dev, flags);
}
return status;
}
static ssize_t gpio_active_low_show(struct device *dev,
static ssize_t active_low_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_desc *desc = dev_get_drvdata(dev);
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
ssize_t status;
mutex_lock(&sysfs_lock);
mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else
status = sprintf(buf, "%d\n",
status = sprintf(buf, "%d\n",
!!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
mutex_unlock(&sysfs_lock);
mutex_unlock(&data->mutex);
return status;
}
static ssize_t gpio_active_low_store(struct device *dev,
static ssize_t active_low_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct gpio_desc *desc = dev_get_drvdata(dev);
struct gpiod_data *data = dev_get_drvdata(dev);
ssize_t status;
long value;
mutex_lock(&sysfs_lock);
mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) {
status = -EIO;
} else {
long value;
status = kstrtol(buf, 0, &value);
if (status == 0)
status = gpio_sysfs_set_active_low(dev, value);
status = kstrtol(buf, 0, &value);
if (status == 0)
status = sysfs_set_active_low(desc, dev, value != 0);
}
mutex_unlock(&sysfs_lock);
mutex_unlock(&data->mutex);
return status ? : size;
}
static DEVICE_ATTR(active_low, 0644,
gpio_active_low_show, gpio_active_low_store);
static DEVICE_ATTR_RW(active_low);
static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct gpio_desc *desc = dev_get_drvdata(dev);
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
umode_t mode = attr->mode;
bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
bool show_direction = data->direction_can_change;
if (attr == &dev_attr_direction.attr) {
if (!show_direction)
@ -402,32 +397,32 @@ static const struct attribute_group *gpio_groups[] = {
* /ngpio ... matching gpio_chip.ngpio
*/
static ssize_t chip_base_show(struct device *dev,
static ssize_t base_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", chip->base);
}
static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
static DEVICE_ATTR_RO(base);
static ssize_t chip_label_show(struct device *dev,
static ssize_t label_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", chip->label ? : "");
}
static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
static DEVICE_ATTR_RO(label);
static ssize_t chip_ngpio_show(struct device *dev,
static ssize_t ngpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", chip->ngpio);
}
static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
static DEVICE_ATTR_RO(ngpio);
static struct attribute *gpiochip_attrs[] = {
&dev_attr_base.attr,
@ -552,6 +547,7 @@ static struct class gpio_class = {
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
struct gpio_chip *chip;
struct gpiod_data *data;
unsigned long flags;
int status;
const char *ioname = NULL;
@ -574,9 +570,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
mutex_lock(&sysfs_lock);
/* check if chip is being removed */
if (!chip || !chip->exported) {
if (!chip || !chip->cdev) {
status = -ENODEV;
goto fail_unlock;
goto err_unlock;
}
spin_lock_irqsave(&gpio_lock, flags);
@ -588,43 +584,54 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
test_bit(FLAG_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags));
status = -EPERM;
goto fail_unlock;
goto err_unlock;
}
if (desc->chip->direction_input && desc->chip->direction_output &&
direction_may_change) {
set_bit(FLAG_SYSFS_DIR, &desc->flags);
}
spin_unlock_irqrestore(&gpio_lock, flags);
offset = gpio_chip_hwgpio(desc);
if (desc->chip->names && desc->chip->names[offset])
ioname = desc->chip->names[offset];
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
status = -ENOMEM;
goto err_unlock;
}
dev = device_create_with_groups(&gpio_class, desc->chip->dev,
MKDEV(0, 0), desc, gpio_groups,
data->desc = desc;
mutex_init(&data->mutex);
if (chip->direction_input && chip->direction_output)
data->direction_can_change = direction_may_change;
else
data->direction_can_change = false;
offset = gpio_chip_hwgpio(desc);
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
dev = device_create_with_groups(&gpio_class, chip->dev,
MKDEV(0, 0), data, gpio_groups,
ioname ? ioname : "gpio%u",
desc_to_gpio(desc));
if (IS_ERR(dev)) {
status = PTR_ERR(dev);
goto fail_unlock;
goto err_free_data;
}
set_bit(FLAG_EXPORT, &desc->flags);
mutex_unlock(&sysfs_lock);
return 0;
fail_unlock:
err_free_data:
kfree(data);
err_unlock:
mutex_unlock(&sysfs_lock);
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
EXPORT_SYMBOL_GPL(gpiod_export);
static int match_export(struct device *dev, const void *data)
static int match_export(struct device *dev, const void *desc)
{
return dev_get_drvdata(dev) == data;
struct gpiod_data *data = dev_get_drvdata(dev);
return data->desc == desc;
}
/**
@ -641,81 +648,25 @@ static int match_export(struct device *dev, const void *data)
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc)
{
int status = -EINVAL;
struct device *cdev;
int ret;
if (!desc) {
pr_warn("%s: invalid GPIO\n", __func__);
return -EINVAL;
}
mutex_lock(&sysfs_lock);
cdev = class_find_device(&gpio_class, NULL, desc, match_export);
if (!cdev)
return -ENODEV;
if (test_bit(FLAG_EXPORT, &desc->flags)) {
struct device *tdev;
ret = sysfs_create_link(&dev->kobj, &cdev->kobj, name);
put_device(cdev);
tdev = class_find_device(&gpio_class, NULL, desc, match_export);
if (tdev != NULL) {
status = sysfs_create_link(&dev->kobj, &tdev->kobj,
name);
put_device(tdev);
} else {
status = -ENODEV;
}
}
mutex_unlock(&sysfs_lock);
if (status)
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
return ret;
}
EXPORT_SYMBOL_GPL(gpiod_export_link);
/**
* gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
* @gpio: gpio to change
* @value: non-zero to use active low, i.e. inverted values
*
* Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
* The GPIO does not have to be exported yet. If poll(2) support has
* been enabled for either rising or falling edge, it will be
* reconfigured to follow the new polarity.
*
* Returns zero on success, else an error.
*/
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
{
struct device *dev = NULL;
int status = -EINVAL;
if (!desc) {
pr_warn("%s: invalid GPIO\n", __func__);
return -EINVAL;
}
mutex_lock(&sysfs_lock);
if (test_bit(FLAG_EXPORT, &desc->flags)) {
dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev == NULL) {
status = -ENODEV;
goto unlock;
}
}
status = sysfs_set_active_low(desc, dev, value);
put_device(dev);
unlock:
mutex_unlock(&sysfs_lock);
if (status)
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
/**
* gpiod_unexport - reverse effect of gpio_export()
* @gpio: gpio to make unavailable
@ -724,8 +675,8 @@ EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
*/
void gpiod_unexport(struct gpio_desc *desc)
{
int status = 0;
struct device *dev = NULL;
struct gpiod_data *data;
struct device *dev;
if (!desc) {
pr_warn("%s: invalid GPIO\n", __func__);
@ -734,81 +685,78 @@ void gpiod_unexport(struct gpio_desc *desc)
mutex_lock(&sysfs_lock);
if (test_bit(FLAG_EXPORT, &desc->flags)) {
if (!test_bit(FLAG_EXPORT, &desc->flags))
goto err_unlock;
dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev) {
gpio_setup_irq(desc, dev, 0);
clear_bit(FLAG_SYSFS_DIR, &desc->flags);
clear_bit(FLAG_EXPORT, &desc->flags);
} else
status = -ENODEV;
}
dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (!dev)
goto err_unlock;
data = dev_get_drvdata(dev);
clear_bit(FLAG_EXPORT, &desc->flags);
device_unregister(dev);
/*
* Release irq after deregistration to prevent race with edge_store.
*/
if (data->irq_flags)
gpio_sysfs_free_irq(dev);
mutex_unlock(&sysfs_lock);
if (dev) {
device_unregister(dev);
put_device(dev);
}
put_device(dev);
kfree(data);
if (status)
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return;
err_unlock:
mutex_unlock(&sysfs_lock);
}
EXPORT_SYMBOL_GPL(gpiod_unexport);
int gpiochip_export(struct gpio_chip *chip)
int gpiochip_sysfs_register(struct gpio_chip *chip)
{
int status;
struct device *dev;
/* Many systems register gpio chips for SOC support very early,
/*
* Many systems add gpio chips for SOC support very early,
* before driver model support is available. In those cases we
* export this later, in gpiolib_sysfs_init() ... here we just
* register later, in gpiolib_sysfs_init() ... here we just
* verify that _some_ field of gpio_class got initialized.
*/
if (!gpio_class.p)
return 0;
/* use chip->base for the ID; it's already known to be unique */
mutex_lock(&sysfs_lock);
dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
chip, gpiochip_groups,
"gpiochip%d", chip->base);
if (IS_ERR(dev))
status = PTR_ERR(dev);
else
status = 0;
chip->exported = (status == 0);
return PTR_ERR(dev);
mutex_lock(&sysfs_lock);
chip->cdev = dev;
mutex_unlock(&sysfs_lock);
if (status)
chip_dbg(chip, "%s: status %d\n", __func__, status);
return status;
return 0;
}
void gpiochip_unexport(struct gpio_chip *chip)
void gpiochip_sysfs_unregister(struct gpio_chip *chip)
{
int status;
struct device *dev;
struct gpio_desc *desc;
unsigned int i;
mutex_lock(&sysfs_lock);
dev = class_find_device(&gpio_class, NULL, chip, match_export);
if (dev) {
put_device(dev);
device_unregister(dev);
/* prevent further gpiod exports */
chip->exported = false;
status = 0;
} else
status = -ENODEV;
mutex_unlock(&sysfs_lock);
if (!chip->cdev)
return;
if (status)
chip_dbg(chip, "%s: status %d\n", __func__, status);
device_unregister(chip->cdev);
/* prevent further gpiod exports */
mutex_lock(&sysfs_lock);
chip->cdev = NULL;
mutex_unlock(&sysfs_lock);
/* unregister gpiod class devices owned by sysfs */
for (i = 0; i < chip->ngpio; i++) {
@ -836,19 +784,20 @@ static int __init gpiolib_sysfs_init(void)
*/
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) {
if (chip->exported)
if (chip->cdev)
continue;
/*
* TODO we yield gpio_lock here because gpiochip_export()
* acquires a mutex. This is unsafe and needs to be fixed.
* TODO we yield gpio_lock here because
* gpiochip_sysfs_register() acquires a mutex. This is unsafe
* and needs to be fixed.
*
* Also it would be nice to use gpiochip_find() here so we
* can keep gpio_chips local to gpiolib.c, but the yield of
* gpio_lock prevents us from doing this.
*/
spin_unlock_irqrestore(&gpio_lock, flags);
status = gpiochip_export(chip);
status = gpiochip_sysfs_register(chip);
spin_lock_irqsave(&gpio_lock, flags);
}
spin_unlock_irqrestore(&gpio_lock, flags);

View File

@ -290,7 +290,7 @@ int gpiochip_add(struct gpio_chip *chip)
of_gpiochip_add(chip);
acpi_gpiochip_add(chip);
status = gpiochip_export(chip);
status = gpiochip_sysfs_register(chip);
if (status)
goto err_remove_chip;
@ -327,10 +327,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add);
*/
void gpiochip_remove(struct gpio_chip *chip)
{
struct gpio_desc *desc;
unsigned long flags;
unsigned id;
bool requested = false;
gpiochip_unexport(chip);
gpiochip_sysfs_unregister(chip);
gpiochip_irqchip_remove(chip);
@ -341,15 +343,17 @@ void gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags);
for (id = 0; id < chip->ngpio; id++) {
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
desc = &chip->desc[id];
desc->chip = NULL;
if (test_bit(FLAG_REQUESTED, &desc->flags))
requested = true;
}
for (id = 0; id < chip->ngpio; id++)
chip->desc[id].chip = NULL;
list_del(&chip->list);
spin_unlock_irqrestore(&gpio_lock, flags);
if (requested)
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
kfree(chip->desc);
chip->desc = NULL;
}
@ -441,6 +445,8 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
*/
irq_set_handler_data(parent_irq, gpiochip);
irq_set_chained_handler(parent_irq, parent_handler);
gpiochip->irq_parent = parent_irq;
}
/* Set the parent IRQ for all affected IRQs */
@ -549,6 +555,11 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
acpi_gpiochip_free_interrupts(gpiochip);
if (gpiochip->irq_parent) {
irq_set_chained_handler(gpiochip->irq_parent, NULL);
irq_set_handler_data(gpiochip->irq_parent, NULL);
}
/* Remove all IRQ mappings and delete the domain */
if (gpiochip->irqdomain) {
for (offset = 0; offset < gpiochip->ngpio; offset++)
@ -608,7 +619,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
of_node = gpiochip->dev->of_node;
#ifdef CONFIG_OF_GPIO
/*
* If the gpiochip has an assigned OF node this takes precendence
* If the gpiochip has an assigned OF node this takes precedence
* FIXME: get rid of this and use gpiochip->dev->of_node everywhere
*/
if (gpiochip->of_node)
@ -1211,7 +1222,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
/*
* _gpio_set_open_drain_value() - Set the open drain gpio's value.
* @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
*/
static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
{
@ -1238,7 +1249,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
/*
* _gpio_set_open_source_value() - Set the open source gpio's value.
* @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
*/
static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
{
@ -1300,17 +1311,16 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
continue;
}
/* set outputs if the corresponding mask bit is set */
if (__test_and_clear_bit(i, mask)) {
if (__test_and_clear_bit(i, mask))
chip->set(chip, i, test_bit(i, bits));
}
}
}
}
static void gpiod_set_array_priv(bool raw, bool can_sleep,
unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
{
int i = 0;
@ -1320,9 +1330,9 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
int count = 0;
if (!can_sleep) {
if (!can_sleep)
WARN_ON(chip->can_sleep);
}
memset(mask, 0, sizeof(mask));
do {
struct gpio_desc *desc = desc_array[i];
@ -1337,24 +1347,22 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
* open drain and open source outputs are set individually
*/
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
_gpio_set_open_drain_value(desc,value);
_gpio_set_open_drain_value(desc, value);
} else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
_gpio_set_open_source_value(desc, value);
} else {
__set_bit(hwgpio, mask);
if (value) {
if (value)
__set_bit(hwgpio, bits);
} else {
else
__clear_bit(hwgpio, bits);
}
count++;
}
i++;
} while ((i < array_size) && (desc_array[i]->chip == chip));
/* push collected bits to outputs */
if (count != 0) {
if (count != 0)
gpio_chip_set_multiple(chip, mask, bits);
}
}
}
@ -1403,7 +1411,7 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
EXPORT_SYMBOL_GPL(gpiod_set_value);
/**
* gpiod_set_raw_array() - assign values to an array of GPIOs
* gpiod_set_raw_array_value() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@ -1414,17 +1422,18 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
void gpiod_set_raw_array(unsigned int array_size,
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array)
{
if (!desc_array)
return;
gpiod_set_array_priv(true, false, array_size, desc_array, value_array);
gpiod_set_array_value_priv(true, false, array_size, desc_array,
value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
/**
* gpiod_set_array() - assign values to an array of GPIOs
* gpiod_set_array_value() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@ -1435,14 +1444,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
* This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep.
*/
void gpiod_set_array(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array)
void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array)
{
if (!desc_array)
return;
gpiod_set_array_priv(false, false, array_size, desc_array, value_array);
gpiod_set_array_value_priv(false, false, array_size, desc_array,
value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_array);
EXPORT_SYMBOL_GPL(gpiod_set_array_value);
/**
* gpiod_cansleep() - report whether gpio value access may sleep
@ -1604,7 +1614,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
/**
* gpiod_set_raw_array_cansleep() - assign values to an array of GPIOs
* gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@ -1614,19 +1624,20 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
*
* This function is to be called from contexts that can sleep.
*/
void gpiod_set_raw_array_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
{
might_sleep_if(extra_checks);
if (!desc_array)
return;
gpiod_set_array_priv(true, true, array_size, desc_array, value_array);
gpiod_set_array_value_priv(true, true, array_size, desc_array,
value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
/**
* gpiod_set_array_cansleep() - assign values to an array of GPIOs
* gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
* @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign
@ -1636,16 +1647,17 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
*
* This function is to be called from contexts that can sleep.
*/
void gpiod_set_array_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
{
might_sleep_if(extra_checks);
if (!desc_array)
return;
gpiod_set_array_priv(false, true, array_size, desc_array, value_array);
gpiod_set_array_value_priv(false, true, array_size, desc_array,
value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_array_cansleep);
EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
/**
* gpiod_add_lookup_table() - register GPIO device consumers
@ -1880,7 +1892,7 @@ EXPORT_SYMBOL_GPL(gpiod_count);
*
* Return the GPIO descriptor corresponding to the function con_id of device
* dev, -ENOENT if no GPIO has been assigned to the requested function, or
* another IS_ERR() code if an error occured while trying to acquire the GPIO.
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
*/
struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id,
enum gpiod_flags flags)
@ -1960,7 +1972,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
*
* Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the
* requested function and/or index, or another IS_ERR() code if an error
* occured while trying to acquire the GPIO.
* occurred while trying to acquire the GPIO.
*/
struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
const char *con_id,
@ -2118,13 +2130,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
local_desc = gpiochip_request_own_desc(chip, hwnum, name);
if (IS_ERR(local_desc)) {
pr_debug("requesting own GPIO %s failed\n", name);
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
name, chip->label, hwnum);
return PTR_ERR(local_desc);
}
status = gpiod_configure_flags(desc, name, lflags, dflags);
if (status < 0) {
pr_debug("setup of GPIO %s failed\n", name);
pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
name, chip->label, hwnum);
gpiochip_free_own_desc(desc);
return status;
}

View File

@ -83,20 +83,12 @@ struct gpio_desc {
#define FLAG_IS_OUT 1
#define FLAG_EXPORT 2 /* protected by sysfs_lock */
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 6 /* value has active low */
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
#define ID_SHIFT 16 /* add new flags before this one */
#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
const char *label;
};
@ -151,17 +143,17 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
#ifdef CONFIG_GPIO_SYSFS
int gpiochip_export(struct gpio_chip *chip);
void gpiochip_unexport(struct gpio_chip *chip);
int gpiochip_sysfs_register(struct gpio_chip *chip);
void gpiochip_sysfs_unregister(struct gpio_chip *chip);
#else
static inline int gpiochip_export(struct gpio_chip *chip)
static inline int gpiochip_sysfs_register(struct gpio_chip *chip)
{
return 0;
}
static inline void gpiochip_unexport(struct gpio_chip *chip)
static inline void gpiochip_sysfs_unregister(struct gpio_chip *chip)
{
}

View File

@ -107,7 +107,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN;
}
} else if (info->irq < 0) {
} else if (!info->irq) {
struct resource r;
if (acpi_dev_resource_interrupt(ares, 0, &r))
@ -134,7 +134,6 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
memset(&info, 0, sizeof(info));
info.fwnode = acpi_fwnode_handle(adev);
info.irq = -1;
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
@ -632,8 +631,13 @@ static int i2c_device_probe(struct device *dev)
if (!client)
return 0;
if (!client->irq && dev->of_node) {
int irq = of_irq_get(dev->of_node, 0);
if (!client->irq) {
int irq = -ENOENT;
if (dev->of_node)
irq = of_irq_get(dev->of_node, 0);
else if (ACPI_COMPANION(dev))
irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
if (irq == -EPROBE_DEFER)
return irq;

View File

@ -35,7 +35,8 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
for (n = 0; n < s->gpios->ndescs; n++)
values[n] = (desired_child >> n) & 1;
gpiod_set_array_cansleep(s->gpios->ndescs, s->gpios->desc, values);
gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc,
values);
return 0;
}

View File

@ -55,7 +55,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
count++;
}
gpiod_set_array(count, desc_array, value_array);
gpiod_set_array_value(count, desc_array, value_array);
}
EXPORT_SYMBOL_GPL(mctrl_gpio_set);

View File

@ -128,11 +128,6 @@ static inline int gpio_export_link(struct device *dev, const char *name,
return gpiod_export_link(dev, name, gpio_to_desc(gpio));
}
static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
{
return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value);
}
static inline void gpio_unexport(unsigned gpio)
{
gpiod_unexport(gpio_to_desc(gpio));

View File

@ -721,6 +721,8 @@ static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
if (adev)
adev->driver_gpios = NULL;
}
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
#else
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios)
@ -728,6 +730,11 @@ static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
return -ENXIO;
}
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
{
return -ENXIO;
}
#endif
/* Device properties */

View File

@ -74,5 +74,6 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
#define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */
#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */
#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3)
#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
#endif /* __BASIC_MMIO_GPIO_H */

View File

@ -196,13 +196,6 @@ static inline int gpio_export_link(struct device *dev, const char *name,
return -EINVAL;
}
static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
{
/* GPIO can never have been requested */
WARN_ON(1);
return -EINVAL;
}
static inline void gpio_unexport(unsigned gpio)
{
/* GPIO can never have been exported */

View File

@ -100,24 +100,25 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
/* Value get/set from non-sleeping context */
int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value);
void gpiod_set_array(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array);
void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array);
int gpiod_get_raw_value(const struct gpio_desc *desc);
void gpiod_set_raw_value(struct gpio_desc *desc, int value);
void gpiod_set_raw_array(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array);
void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
/* Value get/set from sleeping context */
int gpiod_get_value_cansleep(const struct gpio_desc *desc);
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_array_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_raw_array_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
@ -304,9 +305,9 @@ static inline void gpiod_set_value(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */
WARN_ON(1);
}
static inline void gpiod_set_array(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
static inline void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
{
/* GPIO can never have been requested */
WARN_ON(1);
@ -322,9 +323,9 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */
WARN_ON(1);
}
static inline void gpiod_set_raw_array(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
static inline void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
{
/* GPIO can never have been requested */
WARN_ON(1);
@ -341,7 +342,7 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */
WARN_ON(1);
}
static inline void gpiod_set_array_cansleep(unsigned int array_size,
static inline void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
{
@ -360,7 +361,7 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
/* GPIO can never have been requested */
WARN_ON(1);
}
static inline void gpiod_set_raw_array_cansleep(unsigned int array_size,
static inline void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array,
int *value_array)
{
@ -449,7 +450,6 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
void gpiod_unexport(struct gpio_desc *desc);
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
@ -466,11 +466,6 @@ static inline int gpiod_export_link(struct device *dev, const char *name,
return -ENOSYS;
}
static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
{
return -ENOSYS;
}
static inline void gpiod_unexport(struct gpio_desc *desc)
{
}

View File

@ -20,6 +20,7 @@ struct seq_file;
* struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics
* @dev: optional device providing the GPIOs
* @cdev: class device used by sysfs interface (may be NULL)
* @owner: helps prevent removal of modules exporting active GPIOs
* @list: links gpio_chips together for traversal
* @request: optional hook for chip-specific activation, such as
@ -41,8 +42,12 @@ struct seq_file;
* @dbg_show: optional routine to show contents in debugfs; default code
* will be used when this is omitted, but custom code can show extra
* state (such as pullup/pulldown configuration).
* @base: identifies the first GPIO number handled by this chip; or, if
* negative during registration, requests dynamic ID allocation.
* @base: identifies the first GPIO number handled by this chip;
* or, if negative during registration, requests dynamic ID allocation.
* DEPRECATION: providing anything non-negative and nailing the base
* base offset of GPIO chips is deprecated. Please pass -1 as base to
* let gpiolib select the chip base in all possible cases. We want to
* get rid of the static GPIO number space in the long run.
* @ngpio: the number of GPIOs handled by this controller; the last GPIO
* handled is (base + ngpio - 1).
* @desc: array of ngpio descriptors. Private.
@ -57,7 +62,6 @@ struct seq_file;
* implies that if the chip supports IRQs, these IRQs need to be threaded
* as the chip access may sleep when e.g. reading out the IRQ status
* registers.
* @exported: flags if the gpiochip is exported for use from sysfs. Private.
* @irq_not_threaded: flag must be set if @can_sleep is set but the
* IRQs don't need to be threaded
*
@ -74,6 +78,7 @@ struct seq_file;
struct gpio_chip {
const char *label;
struct device *dev;
struct device *cdev;
struct module *owner;
struct list_head list;
@ -109,7 +114,6 @@ struct gpio_chip {
const char *const *names;
bool can_sleep;
bool irq_not_threaded;
bool exported;
#ifdef CONFIG_GPIOLIB_IRQCHIP
/*
@ -121,6 +125,7 @@ struct gpio_chip {
unsigned int irq_base;
irq_flow_handler_t irq_handler;
unsigned int irq_default_type;
int irq_parent;
#endif
#if defined(CONFIG_OF_GPIO)

View File

@ -208,9 +208,17 @@ struct omap_gpio_platform_data {
int (*get_context_loss_count)(struct device *dev);
};
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
extern void omap2_gpio_prepare_for_idle(int off_mode);
extern void omap2_gpio_resume_after_idle(void);
extern void omap_set_gpio_debounce(int gpio, int enable);
extern void omap_set_gpio_debounce_time(int gpio, int enable);
#else
static inline void omap2_gpio_prepare_for_idle(int off_mode)
{
}
static inline void omap2_gpio_resume_after_idle(void)
{
}
#endif
#endif