Commit 10b4b096 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents c70c5fb2 38e003f4
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>;
};
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>;
};
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;
};
...@@ -6,7 +6,7 @@ Required properties: ...@@ -6,7 +6,7 @@ Required properties:
- First cell is the GPIO line number - First cell is the GPIO line number
- Second cell is used to specify optional - Second cell is used to specify optional
parameters (unused) 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) - clocks : Clock specifier (see clock bindings for details)
- gpio-controller : Marks the device node as a GPIO controller. - gpio-controller : Marks the device node as a GPIO controller.
- interrupts : Interrupt specifier (see interrupt bindings for - interrupts : Interrupt specifier (see interrupt bindings for
......
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>;
};
};
...@@ -241,18 +241,18 @@ Set multiple GPIO outputs with a single function call ...@@ -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: The following functions set the output values of an array of GPIOs:
void gpiod_set_array(unsigned int array_size, void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
void gpiod_set_raw_array(unsigned int array_size, void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
void gpiod_set_array_cansleep(unsigned int array_size, void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
void gpiod_set_raw_array_cansleep(unsigned int array_size, void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
The array can be an arbitrary set of GPIOs. The functions will try to set 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 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 ...@@ -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(): the struct gpio_descs returned by gpiod_get_array():
struct gpio_descs *my_gpio_descs = gpiod_get_array(...); struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
gpiod_set_array(my_gpio_descs->ndescs, my_gpio_descs->desc, gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
my_gpio_values); my_gpio_values);
It is also possible to set a completely arbitrary array of descriptors. The It is also possible to set a completely arbitrary array of descriptors. The
descriptors may be obtained using any combination of gpiod_get() and descriptors may be obtained using any combination of gpiod_get() and
......
...@@ -751,9 +751,6 @@ requested using gpio_request(): ...@@ -751,9 +751,6 @@ requested using gpio_request():
int gpio_export_link(struct device *dev, const char *name, int gpio_export_link(struct device *dev, const char *name,
unsigned gpio) 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 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 the sysfs interface by gpio_export(). The driver can control whether the
signal direction may change. This helps drivers prevent userspace code 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 ...@@ -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 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 use this to provide the interface under their own device in sysfs with
a descriptive name. 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.
...@@ -132,9 +132,6 @@ requested using gpio_request(): ...@@ -132,9 +132,6 @@ requested using gpio_request():
int gpiod_export_link(struct device *dev, const char *name, int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc); 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 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 the sysfs interface by gpiod_export(). The driver can control whether the
signal direction may change. This helps drivers prevent userspace code 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 ...@@ -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 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 use this to provide the interface under their own device in sysfs with
a descriptive name. 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.
...@@ -638,9 +638,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO ...@@ -638,9 +638,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
int gpio_export_link(struct device *dev, const char *name, int gpio_export_link(struct device *dev, const char *name,
unsigned gpio) unsigned gpio)
/* 改变 sysfs 中的一个 GPIO 节点的极性 */
int gpio_sysfs_set_active_low(unsigned gpio, int value);
在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs 在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs
接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间 接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间
破坏重要的系统状态。 破坏重要的系统状态。
...@@ -651,8 +648,3 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO ...@@ -651,8 +648,3 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方 在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方
创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的 创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。 名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
驱动可以使用 gpio_sysfs_set_active_low() 来在用户空间隐藏电路板之间
GPIO 线的极性差异。这个仅对 sysfs 接口起作用。极性的改变可以在 gpio_export()
前后进行,且之前使能的轮询操作(poll(2))支持(上升或下降沿)将会被重新配置来遵循
这个设置。
...@@ -2250,6 +2250,13 @@ N: bcm9583* ...@@ -2250,6 +2250,13 @@ N: bcm9583*
N: bcm583* N: bcm583*
N: bcm113* 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 BROADCOM KONA GPIO DRIVER
M: Ray Jui <rjui@broadcom.com> M: Ray Jui <rjui@broadcom.com>
L: bcm-kernel-feedback-list@broadcom.com L: bcm-kernel-feedback-list@broadcom.com
......
...@@ -126,6 +126,14 @@ config GPIO_BCM_KONA ...@@ -126,6 +126,14 @@ config GPIO_BCM_KONA
help help
Turn on GPIO support for Broadcom "Kona" chips. 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 config GPIO_CLPS711X
tristate "CLPS711X GPIO support" tristate "CLPS711X GPIO support"
depends on ARCH_CLPS711X || COMPILE_TEST depends on ARCH_CLPS711X || COMPILE_TEST
...@@ -159,6 +167,14 @@ config GPIO_EP93XX ...@@ -159,6 +167,14 @@ config GPIO_EP93XX
depends on ARCH_EP93XX depends on ARCH_EP93XX
select GPIO_GENERIC 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 config GPIO_F7188X
tristate "F71869, F71869A, F71882FG and F71889F GPIO support" tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
depends on X86 depends on X86
...@@ -230,6 +246,14 @@ config GPIO_LOONGSON ...@@ -230,6 +246,14 @@ config GPIO_LOONGSON
help help
driver for GPIO functionality on Loongson-2F/3A/3B processors. 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 config GPIO_LYNXPOINT
tristate "Intel Lynxpoint GPIO support" tristate "Intel Lynxpoint GPIO support"
depends on ACPI && X86 depends on ACPI && X86
...@@ -308,7 +332,7 @@ config GPIO_OCTEON ...@@ -308,7 +332,7 @@ config GPIO_OCTEON
family of SOCs. family of SOCs.
config GPIO_OMAP 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 default y if ARCH_OMAP
depends on ARM depends on ARM
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
...@@ -488,6 +512,17 @@ config GPIO_XILINX ...@@ -488,6 +512,17 @@ config GPIO_XILINX
help help
Say yes here to support the Xilinx FPGA GPIO device 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 config GPIO_XTENSA
bool "Xtensa GPIO32 support" bool "Xtensa GPIO32 support"
depends on XTENSA depends on XTENSA
...@@ -505,7 +540,7 @@ config GPIO_ZEVIO ...@@ -505,7 +540,7 @@ config GPIO_ZEVIO
config GPIO_ZYNQ config GPIO_ZYNQ
tristate "Xilinx Zynq GPIO support" tristate "Xilinx Zynq GPIO support"
depends on ARCH_ZYNQ depends on ARCH_ZYNQ || ARCH_ZYNQMP
select GPIOLIB_IRQCHIP select GPIOLIB_IRQCHIP
help help
Say yes here to support Xilinx Zynq GPIO controller. Say yes here to support Xilinx Zynq GPIO controller.
......
...@@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o ...@@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
...@@ -32,6 +33,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o ...@@ -32,6 +33,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.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_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
...@@ -44,6 +46,7 @@ obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o ...@@ -44,6 +46,7 @@ obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
...@@ -109,6 +112,7 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o ...@@ -109,6 +112,7 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.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_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
...@@ -107,7 +107,8 @@ static int altera_gpio_irq_set_type(struct irq_data *d, ...@@ -107,7 +107,8 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
return -EINVAL; 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); altera_gpio_irq_unmask(d);
return 0; return 0;
......
...@@ -122,6 +122,16 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, ...@@ -122,6 +122,16 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
spin_unlock_irqrestore(&kona_gpio->lock, flags); 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) static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
{ {
struct bcm_kona_gpio *kona_gpio; struct bcm_kona_gpio *kona_gpio;
...@@ -135,12 +145,8 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) ...@@ -135,12 +145,8 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
reg_base = kona_gpio->reg_base; reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags); 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 */ /* 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; goto out;
reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); 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) ...@@ -166,13 +172,12 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
reg_base = kona_gpio->reg_base; reg_base = kona_gpio->reg_base;
spin_lock_irqsave(&kona_gpio->lock, flags); spin_lock_irqsave(&kona_gpio->lock, flags);
/* determine the GPIO pin direction */ if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
val = readl(reg_base + GPIO_CONTROL(gpio)); reg_offset = GPIO_IN_STATUS(bank_id);
val &= GPIO_GPCTR0_IOTR_MASK; else
reg_offset = GPIO_OUT_STATUS(bank_id);
/* read the GPIO bank status */ /* 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); val = readl(reg_base + reg_offset);
spin_unlock_irqrestore(&kona_gpio->lock, flags); spin_unlock_irqrestore(&kona_gpio->lock, flags);
...@@ -310,6 +315,7 @@ static struct gpio_chip template_chip = { ...@@ -310,6 +315,7 @@ static struct gpio_chip template_chip = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.request = bcm_kona_gpio_request, .request = bcm_kona_gpio_request,
.free = bcm_kona_gpio_free, .free = bcm_kona_gpio_free,
.get_direction = bcm_kona_gpio_get_dir,
.direction_input = bcm_kona_gpio_direction_input, .direction_input = bcm_kona_gpio_direction_input,
.get = bcm_kona_gpio_get, .get = bcm_kona_gpio_get,
.direction_output = bcm_kona_gpio_direction_output, .direction_output = bcm_kona_gpio_direction_output,
......
/*
* 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");
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
*/ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
...@@ -94,9 +95,8 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) ...@@ -94,9 +95,8 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
{ {
int reg; int reg;
if (gpio == 94) { if (gpio == 94)
return GPIOPANELCTL; return GPIOPANELCTL;
}
if (reg_type == CTRL_IN) { if (reg_type == CTRL_IN) {
if (gpio < 8) if (gpio < 8)
...@@ -255,6 +255,7 @@ static struct irq_chip crystalcove_irqchip = { ...@@ -255,6 +255,7 @@ static struct irq_chip crystalcove_irqchip = {
.irq_set_type = crystalcove_irq_type, .irq_set_type = crystalcove_irq_type,
.irq_bus_lock = crystalcove_bus_lock, .irq_bus_lock = crystalcove_bus_lock,
.irq_bus_sync_unlock = crystalcove_bus_sync_unlock, .irq_bus_sync_unlock = crystalcove_bus_sync_unlock,
.flags = IRQCHIP_SKIP_SET_WAKE,
}; };
static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data) static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
......
...@@ -466,7 +466,6 @@ static int dln2_gpio_probe(struct platform_device *pdev) ...@@ -466,7 +466,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2->gpio.owner = THIS_MODULE; dln2->gpio.owner = THIS_MODULE;
dln2->gpio.base = -1; dln2->gpio.base = -1;
dln2->gpio.ngpio = pins; dln2->gpio.ngpio = pins;
dln2->gpio.exported = true;
dln2->gpio.can_sleep = true; dln2->gpio.can_sleep = true;
dln2->gpio.irq_not_threaded = true; dln2->gpio.irq_not_threaded = true;
dln2->gpio.set = dln2_gpio_set; dln2->gpio.set = dln2_gpio_set;
......
#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);
...@@ -172,7 +172,7 @@ static struct f7188x_gpio_bank f71869a_gpio_bank[] = { ...@@ -172,7 +172,7 @@ static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
}; };
static struct f7188x_gpio_bank f71882_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(10, 8, 0xE0),
F7188X_GPIO_BANK(20, 8, 0xD0), F7188X_GPIO_BANK(20, 8, 0xD0),
F7188X_GPIO_BANK(30, 4, 0xC0), F7188X_GPIO_BANK(30, 4, 0xC0),
...@@ -180,7 +180,7 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = { ...@@ -180,7 +180,7 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = {
}; };
static struct f7188x_gpio_bank f71889_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(10, 7, 0xE0),
F7188X_GPIO_BANK(20, 8, 0xD0), F7188X_GPIO_BANK(20, 8, 0xD0),
F7188X_GPIO_BANK(30, 8, 0xC0), F7188X_GPIO_BANK(30, 8, 0xC0),
......
...@@ -135,6 +135,17 @@ static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc, ...@@ -135,6 +135,17 @@ static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
return 1 << (bgc->bits - 1 - pin); 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) static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{ {
struct bgpio_chip *bgc = to_bgpio_chip(gc); struct bgpio_chip *bgc = to_bgpio_chip(gc);
...@@ -416,7 +427,8 @@ static int bgpio_setup_accessors(struct device *dev, ...@@ -416,7 +427,8 @@ static int bgpio_setup_accessors(struct device *dev,
static int bgpio_setup_io(struct bgpio_chip *bgc, static int bgpio_setup_io(struct bgpio_chip *bgc,
void __iomem *dat, void __iomem *dat,
void __iomem *set, void __iomem *set,
void __iomem *clr) void __iomem *clr,
unsigned long flags)
{ {
bgc->reg_dat = dat; bgc->reg_dat = dat;
...@@ -437,7 +449,11 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, ...@@ -437,7 +449,11 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
bgc->gc.set_multiple = bgpio_set_multiple; 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; return 0;
} }
...@@ -500,7 +516,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, ...@@ -500,7 +516,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
bgc->gc.ngpio = bgc->bits; bgc->gc.ngpio = bgc->bits;
bgc->gc.request = bgpio_request; bgc->gc.request = bgpio_request;
ret = bgpio_setup_io(bgc, dat, set, clr); ret = bgpio_setup_io(bgc, dat, set, clr, flags);
if (ret) if (ret)
return ret; return ret;
......
...@@ -123,7 +123,7 @@ static void it8761e_gpio_set(struct gpio_chip *gc, ...@@ -123,7 +123,7 @@ static void it8761e_gpio_set(struct gpio_chip *gc,
curr_vals = inb(reg); curr_vals = inb(reg);
if (val) if (val)
outb(curr_vals | (1 << bit) , reg); outb(curr_vals | (1 << bit), reg);
else else
outb(curr_vals & ~(1 << bit), reg); outb(curr_vals & ~(1 << bit), reg);
......
/*
* 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");
...@@ -72,7 +72,7 @@ struct lp_gpio { ...@@ -72,7 +72,7 @@ struct lp_gpio {
* *
* per gpio specific registers consist of two 32bit registers per 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 * (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: * A simplified view of the register layout look like this:
* *
......
...@@ -429,6 +429,14 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type) ...@@ -429,6 +429,14 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
return 0; 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 = { static struct irq_chip max732x_irq_chip = {
.name = "max732x", .name = "max732x",
.irq_mask = max732x_irq_mask, .irq_mask = max732x_irq_mask,
...@@ -436,6 +444,7 @@ static struct irq_chip max732x_irq_chip = { ...@@ -436,6 +444,7 @@ static struct irq_chip max732x_irq_chip = {
.irq_bus_lock = max732x_irq_bus_lock, .irq_bus_lock = max732x_irq_bus_lock,
.irq_bus_sync_unlock = max732x_irq_bus_sync_unlock, .irq_bus_sync_unlock = max732x_irq_bus_sync_unlock,
.irq_set_type = max732x_irq_set_type, .irq_set_type = max732x_irq_set_type,
.irq_set_wake = max732x_irq_set_wake,
}; };
static uint8_t max732x_irq_pending(struct max732x_chip *chip) static uint8_t max732x_irq_pending(struct max732x_chip *chip)
...@@ -507,12 +516,10 @@ static int max732x_irq_setup(struct max732x_chip *chip, ...@@ -507,12 +516,10 @@ static int max732x_irq_setup(struct max732x_chip *chip,
chip->irq_features = has_irq; chip->irq_features = has_irq;
mutex_init(&chip->irq_lock); mutex_init(&chip->irq_lock);
ret = devm_request_threaded_irq(&client->dev, ret = devm_request_threaded_irq(&client->dev, client->irq,
client->irq, NULL, max732x_irq_handler, IRQF_ONESHOT |
NULL, IRQF_TRIGGER_FALLING | IRQF_SHARED,
max732x_irq_handler, dev_name(&client->dev), chip);
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
dev_name(&client->dev), chip);
if (ret) { if (ret) {
dev_err(&client->dev, "failed to request irq %d\n", dev_err(&client->dev, "failed to request irq %d\n",
client->irq); client->irq);
...@@ -521,7 +528,7 @@ static int max732x_irq_setup(struct max732x_chip *chip, ...@@ -521,7 +528,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
ret = gpiochip_irqchip_add(&chip->gpio_chip, ret = gpiochip_irqchip_add(&chip->gpio_chip,
&max732x_irq_chip, &max732x_irq_chip,
irq_base, irq_base,
handle_edge_irq, handle_simple_irq,
IRQ_TYPE_NONE); IRQ_TYPE_NONE);
if (ret) { if (ret) {
dev_err(&client->dev, dev_err(&client->dev,
......
...@@ -39,17 +39,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) ...@@ -39,17 +39,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
pinctrl_free_gpio(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) static int moxart_gpio_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -68,8 +57,9 @@ static int moxart_gpio_probe(struct platform_device *pdev) ...@@ -68,8 +57,9 @@ static int moxart_gpio_probe(struct platform_device *pdev)
return PTR_ERR(base); return PTR_ERR(base);
ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN, ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN,
base + GPIO_DATA_OUT, NULL, base + GPIO_DATA_OUT, NULL,
base + GPIO_PIN_DIRECTION, NULL, 0); base + GPIO_PIN_DIRECTION, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
if (ret) { if (ret) {
dev_err(&pdev->dev, "bgpio_init failed\n"); dev_err(&pdev->dev, "bgpio_init failed\n");
return ret; return ret;
...@@ -78,7 +68,6 @@ static int moxart_gpio_probe(struct platform_device *pdev) ...@@ -78,7 +68,6 @@ static int moxart_gpio_probe(struct platform_device *pdev)
bgc->gc.label = "moxart-gpio"; bgc->gc.label = "moxart-gpio";
bgc->gc.request = moxart_gpio_request; bgc->gc.request = moxart_gpio_request;
bgc->gc.free = moxart_gpio_free; bgc->gc.free = moxart_gpio_free;
bgc->gc.get = moxart_gpio_get;
bgc->data = bgc->read_reg(bgc->reg_set); bgc->data = bgc->read_reg(bgc->reg_set);
bgc->gc.base = 0; bgc->gc.base = 0;
bgc->gc.ngpio = 32; bgc->gc.ngpio = 32;
......
...@@ -131,7 +131,7 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata; ...@@ -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_FALL_EDGE (mxc_gpio_hwdata->fall_edge)
#define GPIO_INT_BOTH_EDGES 0x4 #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", .name = "imx1-gpio",
.driver_data = IMX1_GPIO, .driver_data = IMX1_GPIO,
...@@ -449,7 +449,8 @@ static int mxc_gpio_probe(struct platform_device *pdev) ...@@ -449,7 +449,8 @@ static int mxc_gpio_probe(struct platform_device *pdev)
err = bgpio_init(&port->bgc, &pdev->dev, 4, err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + GPIO_PSR, port->base + GPIO_PSR,
port->base + GPIO_DR, NULL, port->base + GPIO_DR, NULL,
port->base + GPIO_GDIR, NULL, 0); port->base + GPIO_GDIR, NULL,
BGPIOF_READ_OUTPUT_REG_SET);
if (err) if (err)
goto out_bgio; goto out_bgio;
......
...@@ -239,7 +239,7 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset) ...@@ -239,7 +239,7 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
return !(dir & mask); return !(dir & mask);
} }
static struct platform_device_id mxs_gpio_ids[] = { static const struct platform_device_id mxs_gpio_ids[] = {
{ {
.name = "imx23-gpio", .name = "imx23-gpio",
.driver_data = IMX23_GPIO, .driver_data = IMX23_GPIO,
......
...@@ -488,9 +488,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) ...@@ -488,9 +488,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
unsigned long flags; unsigned long flags;
unsigned offset = d->hwirq; unsigned offset = d->hwirq;
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
if (type & ~IRQ_TYPE_SENSE_MASK) if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL; return -EINVAL;
...@@ -498,12 +495,18 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) ...@@ -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))) (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL; return -EINVAL;
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
retval = omap_set_gpio_triggering(bank, offset, type); retval = omap_set_gpio_triggering(bank, offset, type);
if (retval)
goto error;
omap_gpio_init_irq(bank, offset); omap_gpio_init_irq(bank, offset);
if (!omap_gpio_is_input(bank, offset)) { if (!omap_gpio_is_input(bank, offset)) {
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL; retval = -EINVAL;
goto error;
} }
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
...@@ -512,6 +515,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) ...@@ -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)) else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
__irq_set_handler_locked(d->irq, handle_edge_irq); __irq_set_handler_locked(d->irq, handle_edge_irq);
return 0;
error:
if (!BANK_USED(bank))
pm_runtime_put(bank->dev);
return retval; return retval;
} }
...@@ -638,15 +646,6 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset, ...@@ -638,15 +646,6 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
return 0; 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 */ /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable) 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) ...@@ -669,14 +668,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
pm_runtime_get_sync(bank->dev); pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
/* Set trigger to none. You need to enable the desired trigger with omap_enable_gpio_module(bank, offset);
* 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);
}
bank->mod_usage |= BIT(offset); bank->mod_usage |= BIT(offset);
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
...@@ -690,8 +682,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) ...@@ -690,8 +682,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
spin_lock_irqsave(&bank->lock, flags); spin_lock_irqsave(&bank->lock, flags);
bank->mod_usage &= ~(BIT(offset)); 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_disable_gpio_module(bank, offset);
omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
/* /*
...@@ -795,11 +790,23 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) ...@@ -795,11 +790,23 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
pm_runtime_get_sync(bank->dev); pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags); 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); spin_unlock_irqrestore(&bank->lock, flags);
omap_gpio_unmask_irq(d); omap_gpio_unmask_irq(d);
return 0; 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) static void omap_gpio_irq_shutdown(struct irq_data *d)
...@@ -810,8 +817,12 @@ 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); spin_lock_irqsave(&bank->lock, flags);
bank->irq_usage &= ~(BIT(offset)); 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_disable_gpio_module(bank, offset);
omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags); spin_unlock_irqrestore(&bank->lock, flags);
/* /*
...@@ -1233,6 +1244,17 @@ static int omap_gpio_probe(struct platform_device *pdev) ...@@ -1233,6 +1244,17 @@ static int omap_gpio_probe(struct platform_device *pdev)
return 0; 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 #ifdef CONFIG_ARCH_OMAP2PLUS
#if defined(CONFIG_PM) #if defined(CONFIG_PM)
...@@ -1418,6 +1440,7 @@ static int omap_gpio_runtime_resume(struct device *dev) ...@@ -1418,6 +1440,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
void omap2_gpio_prepare_for_idle(int pwr_mode) void omap2_gpio_prepare_for_idle(int pwr_mode)
{ {
struct gpio_bank *bank; struct gpio_bank *bank;
...@@ -1443,6 +1466,7 @@ void omap2_gpio_resume_after_idle(void) ...@@ -1443,6 +1466,7 @@ void omap2_gpio_resume_after_idle(void)
pm_runtime_get_sync(bank->dev); pm_runtime_get_sync(bank->dev);
} }
} }
#endif
#if defined(CONFIG_PM) #if defined(CONFIG_PM)
static void omap_gpio_init_context(struct gpio_bank *p) static void omap_gpio_init_context(struct gpio_bank *p)
...@@ -1598,6 +1622,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match); ...@@ -1598,6 +1622,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match);
static struct platform_driver omap_gpio_driver = { static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe, .probe = omap_gpio_probe,
.remove = omap_gpio_remove,
.driver = { .driver = {
.name = "omap_gpio", .name = "omap_gpio",
.pm = &gpio_pm_ops, .pm = &gpio_pm_ops,
...@@ -1615,3 +1640,13 @@ static int __init omap_gpio_drv_reg(void) ...@@ -1615,3 +1640,13 @@ static int __init omap_gpio_drv_reg(void)
return platform_driver_register(&omap_gpio_driver); return platform_driver_register(&omap_gpio_driver);
} }
postcore_initcall(omap_gpio_drv_reg); 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");
...@@ -443,12 +443,13 @@ static struct irq_chip pca953x_irq_chip = { ...@@ -443,12 +443,13 @@ static struct irq_chip pca953x_irq_chip = {
.irq_set_type = pca953x_irq_set_type, .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 cur_stat[MAX_BANK];
u8 old_stat[MAX_BANK]; u8 old_stat[MAX_BANK];
u8 pendings = 0; bool pending_seen = false;
u8 trigger[MAX_BANK], triggers = 0; bool trigger_seen = false;
u8 trigger[MAX_BANK];
int ret, i, offset = 0; int ret, i, offset = 0;
switch (chip->chip_type) { switch (chip->chip_type) {
...@@ -461,7 +462,7 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) ...@@ -461,7 +462,7 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
} }
ret = pca953x_read_regs(chip, offset, cur_stat); ret = pca953x_read_regs(chip, offset, cur_stat);
if (ret) if (ret)
return 0; return false;
/* Remove output pins from the equation */ /* Remove output pins from the equation */
for (i = 0; i < NBANK(chip); i++) for (i = 0; i < NBANK(chip); i++)
...@@ -471,11 +472,12 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) ...@@ -471,11 +472,12 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
for (i = 0; i < NBANK(chip); i++) { for (i = 0; i < NBANK(chip); i++) {
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i]; trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
triggers += trigger[i]; if (trigger[i])
trigger_seen = true;
} }
if (!triggers) if (!trigger_seen)
return 0; return false;
memcpy(chip->irq_stat, cur_stat, NBANK(chip)); memcpy(chip->irq_stat, cur_stat, NBANK(chip));
...@@ -483,10 +485,11 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending) ...@@ -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]) | pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
(cur_stat[i] & chip->irq_trig_raise[i]); (cur_stat[i] & chip->irq_trig_raise[i]);
pending[i] &= trigger[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) 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) ...@@ -630,7 +633,7 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
memset(val, 0, NBANK(chip)); memset(val, 0, NBANK(chip));
pca953x_write_regs(chip, PCA957X_INVRT, val); 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)); memset(val, 0x02, NBANK(chip));
pca953x_write_regs(chip, PCA957X_BKEN, val); pca953x_write_regs(chip, PCA957X_BKEN, val);
......
...@@ -91,6 +91,8 @@ struct pcf857x { ...@@ -91,6 +91,8 @@ struct pcf857x {
spinlock_t slock; /* protect irq demux */ spinlock_t slock; /* protect irq demux */
unsigned out; /* software latch */ unsigned out; /* software latch */
unsigned status; /* current status */ unsigned status; /* current status */
unsigned int irq_parent;
unsigned irq_enabled; /* enabled irqs */
int (*write)(struct i2c_client *client, unsigned data); int (*write)(struct i2c_client *client, unsigned data);
int (*read)(struct i2c_client *client); int (*read)(struct i2c_client *client);
...@@ -194,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data) ...@@ -194,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
* interrupt source, just to avoid bad irqs * 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) for_each_set_bit(i, &change, gpio->chip.ngpio)
handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
gpio->status = status; gpio->status = status;
...@@ -209,29 +211,62 @@ static irqreturn_t pcf857x_irq(int irq, void *data) ...@@ -209,29 +211,62 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
*/ */
static void noop(struct irq_data *data) { } static void noop(struct irq_data *data) { }
static unsigned int noop_ret(struct irq_data *data) static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
{ {
return 0; struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
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 int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on) static void pcf857x_irq_enable(struct irq_data *data)
{ {
struct pcf857x *gpio = irq_data_get_irq_chip_data(data); struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
irq_set_irq_wake(gpio->client->irq, on); gpio->irq_enabled |= (1 << data->hwirq);
return 0; }
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 = { static struct irq_chip pcf857x_irq_chip = {
.name = "pcf857x", .name = "pcf857x",
.irq_startup = noop_ret, .irq_enable = pcf857x_irq_enable,
.irq_shutdown = noop, .irq_disable = pcf857x_irq_disable,
.irq_enable = noop,
.irq_disable = noop,
.irq_ack = noop, .irq_ack = noop,
.irq_mask = noop, .irq_mask = noop,
.irq_unmask = noop, .irq_unmask = noop,
.irq_set_wake = pcf857x_irq_set_wake, .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, ...@@ -364,6 +399,7 @@ static int pcf857x_probe(struct i2c_client *client,
gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip, gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip,
client->irq, NULL); client->irq, NULL);
gpio->irq_parent = client->irq;
} }
/* Let platform code set up the GPIOs and their users. /* Let platform code set up the GPIOs and their users.
......
...@@ -177,8 +177,17 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on) ...@@ -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_chip *gc = irq_data_get_irq_chip_data(d);
struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv, struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
gpio_chip); 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) if (!p->clk)
return 0; return 0;
......
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
#define XWAY_STP_ADSL_MASK 0x3 #define XWAY_STP_ADSL_MASK 0x3
/* 2 groups of 3 bits can be driven by the phys */ /* 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_PHY1_SHIFT 27
#define XWAY_STP_PHY2_SHIFT 15 #define XWAY_STP_PHY2_SHIFT 15
...@@ -200,7 +200,7 @@ static int xway_stp_hw_init(struct xway_stp *chip) ...@@ -200,7 +200,7 @@ static int xway_stp_hw_init(struct xway_stp *chip)
static int xway_stp_probe(struct platform_device *pdev) static int xway_stp_probe(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
const __be32 *shadow, *groups, *dsl, *phy; u32 shadow, groups, dsl, phy;
struct xway_stp *chip; struct xway_stp *chip;
struct clk *clk; struct clk *clk;
int ret = 0; int ret = 0;
...@@ -223,33 +223,28 @@ static int xway_stp_probe(struct platform_device *pdev) ...@@ -223,33 +223,28 @@ static int xway_stp_probe(struct platform_device *pdev)
chip->gc.owner = THIS_MODULE; chip->gc.owner = THIS_MODULE;
/* store the shadow value if one was passed by the devicetree */ /* store the shadow value if one was passed by the devicetree */
shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL); if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
if (shadow) chip->shadow = shadow;
chip->shadow = be32_to_cpu(*shadow);
/* find out which gpio groups should be enabled */ /* find out which gpio groups should be enabled */
groups = of_get_property(pdev->dev.of_node, "lantiq,groups", NULL); if (!of_property_read_u32(pdev->dev.of_node, "lantiq,groups", &groups))
if (groups) chip->groups = groups & XWAY_STP_GROUP_MASK;
chip->groups = be32_to_cpu(*groups) & XWAY_STP_GROUP_MASK;
else else
chip->groups = XWAY_STP_GROUP0; chip->groups = XWAY_STP_GROUP0;
chip->gc.ngpio = fls(chip->groups) * 8; chip->gc.ngpio = fls(chip->groups) * 8;
/* find out which gpios are controlled by the dsl core */ /* find out which gpios are controlled by the dsl core */
dsl = of_get_property(pdev->dev.of_node, "lantiq,dsl", NULL); if (!of_property_read_u32(pdev->dev.of_node, "lantiq,dsl", &dsl))
if (dsl) chip->dsl = dsl & XWAY_STP_ADSL_MASK;
chip->dsl = be32_to_cpu(*dsl) & XWAY_STP_ADSL_MASK;
/* find out which gpios are controlled by the phys */ /* find out which gpios are controlled by the phys */
if (of_machine_is_compatible("lantiq,ar9") || if (of_machine_is_compatible("lantiq,ar9") ||
of_machine_is_compatible("lantiq,gr9") || of_machine_is_compatible("lantiq,gr9") ||
of_machine_is_compatible("lantiq,vr9")) { of_machine_is_compatible("lantiq,vr9")) {
phy = of_get_property(pdev->dev.of_node, "lantiq,phy1", NULL); if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy1", &phy))
if (phy) chip->phy1 = phy & XWAY_STP_PHY_MASK;
chip->phy1 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK; if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy2", &phy))
phy = of_get_property(pdev->dev.of_node, "lantiq,phy2", NULL); chip->phy2 = phy & XWAY_STP_PHY_MASK;
if (phy)
chip->phy2 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK;
} }
/* check which edge trigger we should use, default to a falling edge */ /* check which edge trigger we should use, default to a falling edge */
......
...@@ -292,7 +292,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev) ...@@ -292,7 +292,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev)
BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0); BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0);
kfree(tb10x_gpio->domain->gc); kfree(tb10x_gpio->domain->gc);
irq_domain_remove(tb10x_gpio->domain); irq_domain_remove(tb10x_gpio->domain);
free_irq(tb10x_gpio->irq, tb10x_gpio);
} }
gpiochip_remove(&tb10x_gpio->gc); gpiochip_remove(&tb10x_gpio->gc);
......
...@@ -288,7 +288,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -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)); tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
/* if gpio is edge triggered, clear condition /* 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 * miss edges
*/ */
if (lvl & (0x100 << pin)) { if (lvl & (0x100 << pin)) {
......
...@@ -440,7 +440,7 @@ static int ts5500_dio_remove(struct platform_device *pdev) ...@@ -440,7 +440,7 @@ static int ts5500_dio_remove(struct platform_device *pdev)
return 0; return 0;
} }
static struct platform_device_id ts5500_dio_ids[] = { static const struct platform_device_id ts5500_dio_ids[] = {
{ "ts5500-dio1", TS5500_DIO1 }, { "ts5500-dio1", TS5500_DIO1 },
{ "ts5500-dio2", TS5500_DIO2 }, { "ts5500-dio2", TS5500_DIO2 },
{ "ts5500-dio-lcd", TS5500_LCD }, { "ts5500-dio-lcd", TS5500_LCD },
......
...@@ -25,8 +25,11 @@ ...@@ -25,8 +25,11 @@
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/acpi.h>
#include <linux/basic_mmio_gpio.h> #include <linux/basic_mmio_gpio.h>
#include "gpiolib.h"
#define XGENE_MAX_GPIO_DS 22 #define XGENE_MAX_GPIO_DS 22
#define XGENE_MAX_GPIO_DS_IRQ 6 #define XGENE_MAX_GPIO_DS_IRQ 6
...@@ -112,7 +115,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev) ...@@ -112,7 +115,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
GFP_KERNEL); GFP_KERNEL);
if (!priv->irq) if (!priv->irq)
return -ENOMEM; return -ENOMEM;
memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS);
for (i = 0; i < priv->nirq; i++) { for (i = 0; i < priv->nirq; i++) {
priv->irq[default_lines[i]] = platform_get_irq(pdev, 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) ...@@ -129,6 +131,11 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
else else
dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n"); 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; return ret;
} }
...@@ -136,6 +143,10 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev) ...@@ -136,6 +143,10 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)
{ {
struct xgene_gpio_sb *priv = platform_get_drvdata(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); return bgpio_remove(&priv->bgc);
} }
...@@ -145,10 +156,19 @@ static const struct of_device_id xgene_gpio_sb_of_match[] = { ...@@ -145,10 +156,19 @@ static const struct of_device_id xgene_gpio_sb_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, 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 = { static struct platform_driver xgene_gpio_sb_driver = {
.driver = { .driver = {
.name = "xgene-gpio-sb", .name = "xgene-gpio-sb",
.of_match_table = xgene_gpio_sb_of_match, .of_match_table = xgene_gpio_sb_of_match,
.acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match),
}, },
.probe = xgene_gpio_sb_probe, .probe = xgene_gpio_sb_probe,
.remove = xgene_gpio_sb_remove, .remove = xgene_gpio_sb_remove,
......
...@@ -41,10 +41,10 @@ ...@@ -41,10 +41,10 @@
/** /**
* struct xgpio_instance - Stores information about GPIO device * struct xgpio_instance - Stores information about GPIO device
* @mmchip: OF GPIO chip for memory mapped banks * @mmchip: OF GPIO chip for memory mapped banks
* @gpio_width: GPIO width for every channel
* @gpio_state: GPIO state shadow register * @gpio_state: GPIO state shadow register
* @gpio_dir: GPIO direction shadow register * @gpio_dir: GPIO direction shadow register
* @gpio_lock: Lock used for synchronization * @gpio_lock: Lock used for synchronization
* @inited: True if the port has been inited
*/ */
struct xgpio_instance { struct xgpio_instance {
struct of_mm_gpio_chip mmchip; struct of_mm_gpio_chip mmchip;
...@@ -231,6 +231,8 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) ...@@ -231,6 +231,8 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
* @pdev: pointer to the platform device * @pdev: pointer to the platform device
* *
* This function remove gpiochips and frees all the allocated resources. * This function remove gpiochips and frees all the allocated resources.
*
* Return: 0 always
*/ */
static int xgpio_remove(struct platform_device *pdev) static int xgpio_remove(struct platform_device *pdev)
{ {
......
/*
* 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");
...@@ -18,34 +18,47 @@ ...@@ -18,34 +18,47 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/of.h>
#define DRIVER_NAME "zynq-gpio" #define DRIVER_NAME "zynq-gpio"
/* Maximum banks */ /* Maximum banks */
#define ZYNQ_GPIO_MAX_BANK 4 #define ZYNQ_GPIO_MAX_BANK 4
#define ZYNQMP_GPIO_MAX_BANK 6
#define ZYNQ_GPIO_BANK0_NGPIO 32 #define ZYNQ_GPIO_BANK0_NGPIO 32
#define ZYNQ_GPIO_BANK1_NGPIO 22 #define ZYNQ_GPIO_BANK1_NGPIO 22
#define ZYNQ_GPIO_BANK2_NGPIO 32 #define ZYNQ_GPIO_BANK2_NGPIO 32
#define ZYNQ_GPIO_BANK3_NGPIO 32 #define ZYNQ_GPIO_BANK3_NGPIO 32
#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \ #define ZYNQMP_GPIO_BANK0_NGPIO 26
ZYNQ_GPIO_BANK1_NGPIO + \ #define ZYNQMP_GPIO_BANK1_NGPIO 26
ZYNQ_GPIO_BANK2_NGPIO + \ #define ZYNQMP_GPIO_BANK2_NGPIO 26
ZYNQ_GPIO_BANK3_NGPIO) #define ZYNQMP_GPIO_BANK3_NGPIO 32
#define ZYNQMP_GPIO_BANK4_NGPIO 32
#define ZYNQ_GPIO_BANK0_PIN_MIN 0 #define ZYNQMP_GPIO_BANK5_NGPIO 32
#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \
ZYNQ_GPIO_BANK0_NGPIO - 1) #define ZYNQ_GPIO_NR_GPIOS 118
#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1) #define ZYNQMP_GPIO_NR_GPIOS 174
#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \
ZYNQ_GPIO_BANK1_NGPIO - 1) #define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0
#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1) #define ZYNQ_GPIO_BANK0_PIN_MAX(str) (ZYNQ_GPIO_BANK0_PIN_MIN(str) + \
#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \ ZYNQ##str##_GPIO_BANK0_NGPIO - 1)
ZYNQ_GPIO_BANK2_NGPIO - 1) #define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1)
#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1) #define ZYNQ_GPIO_BANK1_PIN_MAX(str) (ZYNQ_GPIO_BANK1_PIN_MIN(str) + \
#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \ ZYNQ##str##_GPIO_BANK1_NGPIO - 1)
ZYNQ_GPIO_BANK3_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 */ /* Register offsets for the GPIO device */
...@@ -89,12 +102,30 @@ ...@@ -89,12 +102,30 @@
* @base_addr: base address of the GPIO device * @base_addr: base address of the GPIO device
* @clk: clock resource for this controller * @clk: clock resource for this controller
* @irq: interrupt for the GPIO device * @irq: interrupt for the GPIO device
* @p_data: pointer to platform data
*/ */
struct zynq_gpio { struct zynq_gpio {
struct gpio_chip chip; struct gpio_chip chip;
void __iomem *base_addr; void __iomem *base_addr;
struct clk *clk; struct clk *clk;
int irq; 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; static struct irq_chip zynq_gpio_level_irqchip;
...@@ -112,39 +143,26 @@ static struct irq_chip zynq_gpio_edge_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, static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
unsigned int *bank_num, unsigned int *bank_num,
unsigned int *bank_pin_num) unsigned int *bank_pin_num,
struct zynq_gpio *gpio)
{ {
switch (pin_num) { int bank;
case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX:
*bank_num = 0; for (bank = 0; bank < gpio->p_data->max_bank; bank++) {
*bank_pin_num = pin_num; if ((pin_num >= gpio->p_data->bank_min[bank]) &&
break; (pin_num <= gpio->p_data->bank_max[bank])) {
case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX: *bank_num = bank;
*bank_num = 1; *bank_pin_num = pin_num -
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN; gpio->p_data->bank_min[bank];
break; return;
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;
} }
}
static const unsigned int zynq_gpio_bank_offset[] = { /* default */
ZYNQ_GPIO_BANK0_PIN_MIN, WARN(true, "invalid GPIO pin number: %u", pin_num);
ZYNQ_GPIO_BANK1_PIN_MIN, *bank_num = 0;
ZYNQ_GPIO_BANK2_PIN_MIN, *bank_pin_num = 0;
ZYNQ_GPIO_BANK3_PIN_MIN, }
};
/** /**
* zynq_gpio_get_value - Get the state of the specified pin of GPIO device * 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) ...@@ -161,7 +179,7 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
unsigned int bank_num, bank_pin_num; unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); 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 + data = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
...@@ -185,7 +203,7 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin, ...@@ -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; unsigned int reg_offset, bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); 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) { if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
/* only 16 data bits in bit maskable reg */ /* 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) ...@@ -222,7 +240,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
unsigned int bank_num, bank_pin_num; unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); 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 */ /* 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)) 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, ...@@ -255,7 +273,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
unsigned int bank_num, bank_pin_num; unsigned int bank_num, bank_pin_num;
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); 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 */ /* set the GPIO pin as output */
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 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) ...@@ -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); struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq; 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), writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_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) ...@@ -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); struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq; 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), writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_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) ...@@ -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); struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq; 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), writel_relaxed(BIT(bank_pin_num),
gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_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) ...@@ -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 * @irq_data: irq data containing irq number of gpio pin for the interrupt
* to enable * 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) 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) ...@@ -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); struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
device_pin_num = irq_data->hwirq; 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 + int_type = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
...@@ -470,7 +488,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio, ...@@ -470,7 +488,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
unsigned int bank_num, unsigned int bank_num,
unsigned long pending) 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; struct irq_domain *irqdomain = gpio->chip.irqdomain;
int offset; int offset;
...@@ -505,7 +523,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) ...@@ -505,7 +523,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
chained_irq_enter(irqchip, 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 + int_sts = readl_relaxed(gpio->base_addr +
ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
int_enb = readl_relaxed(gpio->base_addr + int_enb = readl_relaxed(gpio->base_addr +
...@@ -582,6 +600,46 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = { ...@@ -582,6 +600,46 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
zynq_gpio_runtime_resume, NULL) 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 * zynq_gpio_probe - Initialization method for a zynq_gpio device
* @pdev: platform device instance * @pdev: platform device instance
...@@ -599,11 +657,18 @@ static int zynq_gpio_probe(struct platform_device *pdev) ...@@ -599,11 +657,18 @@ static int zynq_gpio_probe(struct platform_device *pdev)
struct zynq_gpio *gpio; struct zynq_gpio *gpio;
struct gpio_chip *chip; struct gpio_chip *chip;
struct resource *res; struct resource *res;
const struct of_device_id *match;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio) if (!gpio)
return -ENOMEM; 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); platform_set_drvdata(pdev, gpio);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
...@@ -619,7 +684,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) ...@@ -619,7 +684,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
/* configure the gpio chip */ /* configure the gpio chip */
chip = &gpio->chip; chip = &gpio->chip;
chip->label = "zynq_gpio"; chip->label = gpio->p_data->label;
chip->owner = THIS_MODULE; chip->owner = THIS_MODULE;
chip->dev = &pdev->dev; chip->dev = &pdev->dev;
chip->get = zynq_gpio_get_value; chip->get = zynq_gpio_get_value;
...@@ -629,7 +694,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) ...@@ -629,7 +694,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
chip->direction_input = zynq_gpio_dir_in; chip->direction_input = zynq_gpio_dir_in;
chip->direction_output = zynq_gpio_dir_out; chip->direction_output = zynq_gpio_dir_out;
chip->base = -1; chip->base = -1;
chip->ngpio = ZYNQ_GPIO_NR_GPIOS; chip->ngpio = gpio->p_data->ngpio;
/* Enable GPIO clock */ /* Enable GPIO clock */
gpio->clk = devm_clk_get(&pdev->dev, NULL); gpio->clk = devm_clk_get(&pdev->dev, NULL);
...@@ -651,7 +716,7 @@ static int zynq_gpio_probe(struct platform_device *pdev) ...@@ -651,7 +716,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
} }
/* disable interrupts for all banks */ /* 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 + writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
...@@ -695,12 +760,6 @@ static int zynq_gpio_remove(struct platform_device *pdev) ...@@ -695,12 +760,6 @@ static int zynq_gpio_remove(struct platform_device *pdev)
return 0; 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 = { static struct platform_driver zynq_gpio_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
......
...@@ -114,10 +114,11 @@ static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, ...@@ -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") * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
* @pin: ACPI GPIO pin number (0-based, controller-relative) * @pin: ACPI GPIO pin number (0-based, controller-relative)
* *
* Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR * Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
* error value * 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) static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
...@@ -131,7 +132,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) ...@@ -131,7 +132,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
chip = gpiochip_find(handle, acpi_gpiochip_find); chip = gpiochip_find(handle, acpi_gpiochip_find);
if (!chip) if (!chip)
return ERR_PTR(-ENODEV); return ERR_PTR(-EPROBE_DEFER);
offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin); offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
if (offset < 0) if (offset < 0)
...@@ -307,6 +308,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) ...@@ -307,6 +308,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
acpi_walk_resources(handle, "_AEI", acpi_walk_resources(handle, "_AEI",
acpi_gpiochip_request_interrupt, acpi_gpio); acpi_gpiochip_request_interrupt, acpi_gpio);
} }
EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
/** /**
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
...@@ -346,6 +348,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) ...@@ -346,6 +348,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
kfree(event); kfree(event);
} }
} }
EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts);
int acpi_dev_add_driver_gpios(struct acpi_device *adev, int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios) const struct acpi_gpio_mapping *gpios)
...@@ -514,6 +517,35 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev, ...@@ -514,6 +517,35 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); 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 static acpi_status
acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
u32 bits, u64 *value, void *handler_context, u32 bits, u64 *value, void *handler_context,
......
...@@ -242,7 +242,7 @@ int of_gpio_simple_xlate(struct gpio_chip *gc, ...@@ -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 * 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, * number and the flags from a single gpio cell -- this is possible,
* but not recommended). * but not recommended).
*/ */
......
...@@ -6,14 +6,29 @@ ...@@ -6,14 +6,29 @@
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <linux/slab.h>
#include "gpiolib.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;
struct mutex mutex;
struct kernfs_node *value_kn;
int irq;
unsigned char irq_flags;
/* lock protects against unexport_gpio() being called while bool direction_can_change;
* sysfs files are active. };
/*
* Lock to serialise gpiod export and unexport, and prevent re-export of
* gpiod whose chip is being unregistered.
*/ */
static DEFINE_MUTEX(sysfs_lock); static DEFINE_MUTEX(sysfs_lock);
...@@ -38,38 +53,35 @@ static DEFINE_MUTEX(sysfs_lock); ...@@ -38,38 +53,35 @@ static DEFINE_MUTEX(sysfs_lock);
* /edge configuration * /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 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; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) { gpiod_get_direction(desc);
status = -EIO; status = sprintf(buf, "%s\n",
} else {
gpiod_get_direction(desc);
status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags) test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in"); ? "out" : "in");
}
mutex_unlock(&sysfs_lock); mutex_unlock(&data->mutex);
return status; 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 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; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) if (sysfs_streq(buf, "high"))
status = -EIO;
else if (sysfs_streq(buf, "high"))
status = gpiod_direction_output_raw(desc, 1); status = gpiod_direction_output_raw(desc, 1);
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
status = gpiod_direction_output_raw(desc, 0); status = gpiod_direction_output_raw(desc, 0);
...@@ -78,43 +90,40 @@ static ssize_t gpio_direction_store(struct device *dev, ...@@ -78,43 +90,40 @@ static ssize_t gpio_direction_store(struct device *dev,
else else
status = -EINVAL; status = -EINVAL;
mutex_unlock(&sysfs_lock); mutex_unlock(&data->mutex);
return status ? : size; return status ? : size;
} }
static DEVICE_ATTR_RW(direction);
static /* const */ DEVICE_ATTR(direction, 0644, static ssize_t value_show(struct device *dev,
gpio_direction_show, gpio_direction_store);
static ssize_t gpio_value_show(struct device *dev,
struct device_attribute *attr, char *buf) 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; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
status = -EIO;
else mutex_unlock(&data->mutex);
status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
mutex_unlock(&sysfs_lock);
return status; 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 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; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
status = -EIO;
else if (!test_bit(FLAG_IS_OUT, &desc->flags))
status = -EPERM; status = -EPERM;
else { } else {
long value; long value;
status = kstrtol(buf, 0, &value); status = kstrtol(buf, 0, &value);
...@@ -124,172 +133,168 @@ static ssize_t gpio_value_store(struct device *dev, ...@@ -124,172 +133,168 @@ static ssize_t gpio_value_store(struct device *dev,
} }
} }
mutex_unlock(&sysfs_lock); mutex_unlock(&data->mutex);
return status; return status;
} }
static DEVICE_ATTR_RW(value);
static DEVICE_ATTR(value, 0644,
gpio_value_show, gpio_value_store);
static irqreturn_t gpio_sysfs_irq(int irq, void *priv) 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; return IRQ_HANDLED;
} }
static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, /* Caller holds gpiod-data mutex. */
unsigned long gpio_flags) 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; unsigned long irq_flags;
int ret, irq, id; int ret;
if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) data->irq = gpiod_to_irq(desc);
return 0; if (data->irq < 0)
irq = gpiod_to_irq(desc);
if (irq < 0)
return -EIO; return -EIO;
id = desc->flags >> ID_SHIFT; data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value");
value_sd = idr_find(&dirent_idr, id); if (!data->value_kn)
if (value_sd) return -ENODEV;
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;
}
irq_flags = IRQF_SHARED; 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) ? irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; 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) ? irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
if (!value_sd) { /*
value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); * FIXME: This should be done in the irq_request_resources callback
if (!value_sd) { * when the irq is requested, but a few drivers currently fail
ret = -ENODEV; * to do so.
goto err_out; *
} * Remove this redundant call (along with the corresponding
* unlock) when those drivers have been fixed.
ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL); */
if (ret < 0) ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
goto free_sd; if (ret < 0)
id = ret; goto err_put_kn;
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, ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags,
"gpiolib", value_sd); "gpiolib", data);
if (ret < 0) if (ret < 0)
goto free_id; goto err_unlock;
ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc)); data->irq_flags = flags;
if (ret < 0) {
gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
goto free_id;
}
desc->flags |= gpio_flags;
return 0; return 0;
free_id: err_unlock:
idr_remove(&dirent_idr, id); gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
desc->flags &= GPIO_FLAGS_MASK; err_put_kn:
free_sd: sysfs_put(data->value_kn);
if (value_sd)
sysfs_put(value_sd);
err_out:
return ret; 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 { static const struct {
const char *name; const char *name;
unsigned long flags; unsigned char flags;
} trigger_types[] = { } trigger_types[] = {
{ "none", 0 }, { "none", 0 },
{ "falling", BIT(FLAG_TRIG_FALL) }, { "falling", GPIO_IRQF_TRIGGER_FALLING },
{ "rising", BIT(FLAG_TRIG_RISE) }, { "rising", GPIO_IRQF_TRIGGER_RISING },
{ "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) }, { "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) struct device_attribute *attr, char *buf)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpiod_data *data = dev_get_drvdata(dev);
ssize_t status; 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++) {
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) if (data->irq_flags == trigger_types[i].flags) {
if ((desc->flags & GPIO_TRIGGER_MASK) status = sprintf(buf, "%s\n", trigger_types[i].name);
== trigger_types[i].flags) { break;
status = sprintf(buf, "%s\n", }
trigger_types[i].name);
break;
}
} }
mutex_unlock(&sysfs_lock); mutex_unlock(&data->mutex);
return status; 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 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; unsigned char flags;
int i; 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)) if (sysfs_streq(trigger_types[i].name, buf))
goto found; break;
return -EINVAL; }
found: if (i == ARRAY_SIZE(trigger_types))
mutex_lock(&sysfs_lock); return -EINVAL;
if (!test_bit(FLAG_EXPORT, &desc->flags)) flags = trigger_types[i].flags;
status = -EIO;
else { mutex_lock(&data->mutex);
status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
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) if (!status)
status = size; status = size;
} }
mutex_unlock(&sysfs_lock); out_unlock:
mutex_unlock(&data->mutex);
return status; return status;
} }
static DEVICE_ATTR_RW(edge);
static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store); /* Caller holds gpiod-data mutex. */
static int gpio_sysfs_set_active_low(struct device *dev, int value)
static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
int value)
{ {
struct gpiod_data *data = dev_get_drvdata(dev);
struct gpio_desc *desc = data->desc;
int status = 0; int status = 0;
unsigned int flags = data->irq_flags;
if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value) if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
return 0; return 0;
...@@ -300,69 +305,59 @@ static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev, ...@@ -300,69 +305,59 @@ static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
clear_bit(FLAG_ACTIVE_LOW, &desc->flags); clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
/* reconfigure poll(2) support if enabled on one edge only */ /* reconfigure poll(2) support if enabled on one edge only */
if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^ if (flags == GPIO_IRQF_TRIGGER_FALLING ||
!!test_bit(FLAG_TRIG_FALL, &desc->flags))) { flags == GPIO_IRQF_TRIGGER_RISING) {
unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK; gpio_sysfs_free_irq(dev);
status = gpio_sysfs_request_irq(dev, flags);
gpio_setup_irq(desc, dev, 0);
status = gpio_setup_irq(desc, dev, trigger_flags);
} }
return status; 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) 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; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) status = sprintf(buf, "%d\n",
status = -EIO;
else
status = sprintf(buf, "%d\n",
!!test_bit(FLAG_ACTIVE_LOW, &desc->flags)); !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
mutex_unlock(&sysfs_lock); mutex_unlock(&data->mutex);
return status; 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 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; ssize_t status;
long value;
mutex_lock(&sysfs_lock); mutex_lock(&data->mutex);
if (!test_bit(FLAG_EXPORT, &desc->flags)) { status = kstrtol(buf, 0, &value);
status = -EIO; if (status == 0)
} else { status = gpio_sysfs_set_active_low(dev, value);
long value;
status = kstrtol(buf, 0, &value); mutex_unlock(&data->mutex);
if (status == 0)
status = sysfs_set_active_low(desc, dev, value != 0);
}
mutex_unlock(&sysfs_lock);
return status ? : size; return status ? : size;
} }
static DEVICE_ATTR_RW(active_low);
static DEVICE_ATTR(active_low, 0644,
gpio_active_low_show, gpio_active_low_store);
static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr, static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
int n) int n)
{ {
struct device *dev = container_of(kobj, struct device, kobj); 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; 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 (attr == &dev_attr_direction.attr) {
if (!show_direction) if (!show_direction)
...@@ -402,32 +397,32 @@ static const struct attribute_group *gpio_groups[] = { ...@@ -402,32 +397,32 @@ static const struct attribute_group *gpio_groups[] = {
* /ngpio ... matching gpio_chip.ngpio * /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) struct device_attribute *attr, char *buf)
{ {
const struct gpio_chip *chip = dev_get_drvdata(dev); const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", chip->base); 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) struct device_attribute *attr, char *buf)
{ {
const struct gpio_chip *chip = dev_get_drvdata(dev); const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", chip->label ? : ""); 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) struct device_attribute *attr, char *buf)
{ {
const struct gpio_chip *chip = dev_get_drvdata(dev); const struct gpio_chip *chip = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", chip->ngpio); 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[] = { static struct attribute *gpiochip_attrs[] = {
&dev_attr_base.attr, &dev_attr_base.attr,
...@@ -552,6 +547,7 @@ static struct class gpio_class = { ...@@ -552,6 +547,7 @@ static struct class gpio_class = {
int gpiod_export(struct gpio_desc *desc, bool direction_may_change) int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpiod_data *data;
unsigned long flags; unsigned long flags;
int status; int status;
const char *ioname = NULL; const char *ioname = NULL;
...@@ -574,9 +570,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ...@@ -574,9 +570,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
/* check if chip is being removed */ /* check if chip is being removed */
if (!chip || !chip->exported) { if (!chip || !chip->cdev) {
status = -ENODEV; status = -ENODEV;
goto fail_unlock; goto err_unlock;
} }
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
...@@ -588,43 +584,54 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ...@@ -588,43 +584,54 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags)); test_bit(FLAG_EXPORT, &desc->flags));
status = -EPERM; status = -EPERM;
goto fail_unlock; goto err_unlock;
} }
spin_unlock_irqrestore(&gpio_lock, flags);
if (desc->chip->direction_input && desc->chip->direction_output && data = kzalloc(sizeof(*data), GFP_KERNEL);
direction_may_change) { if (!data) {
set_bit(FLAG_SYSFS_DIR, &desc->flags); status = -ENOMEM;
goto err_unlock;
} }
spin_unlock_irqrestore(&gpio_lock, flags); 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); offset = gpio_chip_hwgpio(desc);
if (desc->chip->names && desc->chip->names[offset]) if (chip->names && chip->names[offset])
ioname = desc->chip->names[offset]; ioname = chip->names[offset];
dev = device_create_with_groups(&gpio_class, desc->chip->dev, dev = device_create_with_groups(&gpio_class, chip->dev,
MKDEV(0, 0), desc, gpio_groups, MKDEV(0, 0), data, gpio_groups,
ioname ? ioname : "gpio%u", ioname ? ioname : "gpio%u",
desc_to_gpio(desc)); desc_to_gpio(desc));
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
status = PTR_ERR(dev); status = PTR_ERR(dev);
goto fail_unlock; goto err_free_data;
} }
set_bit(FLAG_EXPORT, &desc->flags); set_bit(FLAG_EXPORT, &desc->flags);
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
return 0; return 0;
fail_unlock: err_free_data:
kfree(data);
err_unlock:
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
gpiod_dbg(desc, "%s: status %d\n", __func__, status); gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status; return status;
} }
EXPORT_SYMBOL_GPL(gpiod_export); 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) ...@@ -641,81 +648,25 @@ static int match_export(struct device *dev, const void *data)
int gpiod_export_link(struct device *dev, const char *name, int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc) struct gpio_desc *desc)
{ {
int status = -EINVAL; struct device *cdev;
int ret;
if (!desc) { if (!desc) {
pr_warn("%s: invalid GPIO\n", __func__); pr_warn("%s: invalid GPIO\n", __func__);
return -EINVAL; return -EINVAL;
} }
mutex_lock(&sysfs_lock); cdev = class_find_device(&gpio_class, NULL, desc, match_export);
if (!cdev)
if (test_bit(FLAG_EXPORT, &desc->flags)) { return -ENODEV;
struct device *tdev;
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) ret = sysfs_create_link(&dev->kobj, &cdev->kobj, name);
gpiod_dbg(desc, "%s: status %d\n", __func__, status); put_device(cdev);
return status; return ret;
} }
EXPORT_SYMBOL_GPL(gpiod_export_link); 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() * gpiod_unexport - reverse effect of gpio_export()
* @gpio: gpio to make unavailable * @gpio: gpio to make unavailable
...@@ -724,8 +675,8 @@ EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); ...@@ -724,8 +675,8 @@ EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
*/ */
void gpiod_unexport(struct gpio_desc *desc) void gpiod_unexport(struct gpio_desc *desc)
{ {
int status = 0; struct gpiod_data *data;
struct device *dev = NULL; struct device *dev;
if (!desc) { if (!desc) {
pr_warn("%s: invalid GPIO\n", __func__); pr_warn("%s: invalid GPIO\n", __func__);
...@@ -734,82 +685,79 @@ void gpiod_unexport(struct gpio_desc *desc) ...@@ -734,82 +685,79 @@ void gpiod_unexport(struct gpio_desc *desc)
mutex_lock(&sysfs_lock); 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); dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev) { if (!dev)
gpio_setup_irq(desc, dev, 0); goto err_unlock;
clear_bit(FLAG_SYSFS_DIR, &desc->flags);
clear_bit(FLAG_EXPORT, &desc->flags); data = dev_get_drvdata(dev);
} else
status = -ENODEV; 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); mutex_unlock(&sysfs_lock);
if (dev) { put_device(dev);
device_unregister(dev); kfree(data);
put_device(dev);
}
if (status) return;
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
err_unlock:
mutex_unlock(&sysfs_lock);
} }
EXPORT_SYMBOL_GPL(gpiod_unexport); 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; 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 * 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. * verify that _some_ field of gpio_class got initialized.
*/ */
if (!gpio_class.p) if (!gpio_class.p)
return 0; return 0;
/* use chip->base for the ID; it's already known to be unique */ /* 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), dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
chip, gpiochip_groups, chip, gpiochip_groups,
"gpiochip%d", chip->base); "gpiochip%d", chip->base);
if (IS_ERR(dev)) if (IS_ERR(dev))
status = PTR_ERR(dev); return PTR_ERR(dev);
else
status = 0;
chip->exported = (status == 0);
mutex_unlock(&sysfs_lock);
if (status) mutex_lock(&sysfs_lock);
chip_dbg(chip, "%s: status %d\n", __func__, status); chip->cdev = dev;
mutex_unlock(&sysfs_lock);
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; struct gpio_desc *desc;
unsigned int i; unsigned int i;
if (!chip->cdev)
return;
device_unregister(chip->cdev);
/* prevent further gpiod exports */
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
dev = class_find_device(&gpio_class, NULL, chip, match_export); chip->cdev = NULL;
if (dev) {
put_device(dev);
device_unregister(dev);
/* prevent further gpiod exports */
chip->exported = false;
status = 0;
} else
status = -ENODEV;
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
if (status)
chip_dbg(chip, "%s: status %d\n", __func__, status);
/* unregister gpiod class devices owned by sysfs */ /* unregister gpiod class devices owned by sysfs */
for (i = 0; i < chip->ngpio; i++) { for (i = 0; i < chip->ngpio; i++) {
desc = &chip->desc[i]; desc = &chip->desc[i];
...@@ -836,19 +784,20 @@ static int __init gpiolib_sysfs_init(void) ...@@ -836,19 +784,20 @@ static int __init gpiolib_sysfs_init(void)
*/ */
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(chip, &gpio_chips, list) { list_for_each_entry(chip, &gpio_chips, list) {
if (chip->exported) if (chip->cdev)
continue; continue;
/* /*
* TODO we yield gpio_lock here because gpiochip_export() * TODO we yield gpio_lock here because
* acquires a mutex. This is unsafe and needs to be fixed. * 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 * Also it would be nice to use gpiochip_find() here so we
* can keep gpio_chips local to gpiolib.c, but the yield of * can keep gpio_chips local to gpiolib.c, but the yield of
* gpio_lock prevents us from doing this. * gpio_lock prevents us from doing this.
*/ */
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
status = gpiochip_export(chip); status = gpiochip_sysfs_register(chip);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
......
...@@ -290,7 +290,7 @@ int gpiochip_add(struct gpio_chip *chip) ...@@ -290,7 +290,7 @@ int gpiochip_add(struct gpio_chip *chip)
of_gpiochip_add(chip); of_gpiochip_add(chip);
acpi_gpiochip_add(chip); acpi_gpiochip_add(chip);
status = gpiochip_export(chip); status = gpiochip_sysfs_register(chip);
if (status) if (status)
goto err_remove_chip; goto err_remove_chip;
...@@ -327,10 +327,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add); ...@@ -327,10 +327,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add);
*/ */
void gpiochip_remove(struct gpio_chip *chip) void gpiochip_remove(struct gpio_chip *chip)
{ {
struct gpio_desc *desc;
unsigned long flags; unsigned long flags;
unsigned id; unsigned id;
bool requested = false;
gpiochip_unexport(chip); gpiochip_sysfs_unregister(chip);
gpiochip_irqchip_remove(chip); gpiochip_irqchip_remove(chip);
...@@ -341,15 +343,17 @@ void gpiochip_remove(struct gpio_chip *chip) ...@@ -341,15 +343,17 @@ void gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
for (id = 0; id < chip->ngpio; id++) { for (id = 0; id < chip->ngpio; id++) {
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) desc = &chip->desc[id];
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); 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); list_del(&chip->list);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (requested)
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
kfree(chip->desc); kfree(chip->desc);
chip->desc = NULL; chip->desc = NULL;
} }
...@@ -441,6 +445,8 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, ...@@ -441,6 +445,8 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
*/ */
irq_set_handler_data(parent_irq, gpiochip); irq_set_handler_data(parent_irq, gpiochip);
irq_set_chained_handler(parent_irq, parent_handler); irq_set_chained_handler(parent_irq, parent_handler);
gpiochip->irq_parent = parent_irq;
} }
/* Set the parent IRQ for all affected IRQs */ /* Set the parent IRQ for all affected IRQs */
...@@ -549,6 +555,11 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) ...@@ -549,6 +555,11 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
acpi_gpiochip_free_interrupts(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 */ /* Remove all IRQ mappings and delete the domain */
if (gpiochip->irqdomain) { if (gpiochip->irqdomain) {
for (offset = 0; offset < gpiochip->ngpio; offset++) for (offset = 0; offset < gpiochip->ngpio; offset++)
...@@ -608,7 +619,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, ...@@ -608,7 +619,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
of_node = gpiochip->dev->of_node; of_node = gpiochip->dev->of_node;
#ifdef CONFIG_OF_GPIO #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 * FIXME: get rid of this and use gpiochip->dev->of_node everywhere
*/ */
if (gpiochip->of_node) if (gpiochip->of_node)
...@@ -1211,7 +1222,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); ...@@ -1211,7 +1222,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
/* /*
* _gpio_set_open_drain_value() - Set the open drain gpio's value. * _gpio_set_open_drain_value() - Set the open drain gpio's value.
* @desc: gpio descriptor whose state need to be set. * @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) 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) ...@@ -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. * _gpio_set_open_source_value() - Set the open source gpio's value.
* @desc: gpio descriptor whose state need to be set. * @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) 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, ...@@ -1300,17 +1311,16 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
continue; continue;
} }
/* set outputs if the corresponding mask bit is set */ /* 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)); chip->set(chip, i, test_bit(i, bits));
}
} }
} }
} }
static void gpiod_set_array_priv(bool raw, bool can_sleep, static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
unsigned int array_size, unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
{ {
int i = 0; int i = 0;
...@@ -1320,9 +1330,9 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep, ...@@ -1320,9 +1330,9 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
unsigned long bits[BITS_TO_LONGS(chip->ngpio)]; unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
int count = 0; int count = 0;
if (!can_sleep) { if (!can_sleep)
WARN_ON(chip->can_sleep); WARN_ON(chip->can_sleep);
}
memset(mask, 0, sizeof(mask)); memset(mask, 0, sizeof(mask));
do { do {
struct gpio_desc *desc = desc_array[i]; struct gpio_desc *desc = desc_array[i];
...@@ -1337,24 +1347,22 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep, ...@@ -1337,24 +1347,22 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
* open drain and open source outputs are set individually * open drain and open source outputs are set individually
*/ */
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { 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)) { } else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
_gpio_set_open_source_value(desc, value); _gpio_set_open_source_value(desc, value);
} else { } else {
__set_bit(hwgpio, mask); __set_bit(hwgpio, mask);
if (value) { if (value)
__set_bit(hwgpio, bits); __set_bit(hwgpio, bits);
} else { else
__clear_bit(hwgpio, bits); __clear_bit(hwgpio, bits);
}
count++; count++;
} }
i++; i++;
} while ((i < array_size) && (desc_array[i]->chip == chip)); } while ((i < array_size) && (desc_array[i]->chip == chip));
/* push collected bits to outputs */ /* push collected bits to outputs */
if (count != 0) { if (count != 0)
gpio_chip_set_multiple(chip, mask, bits); gpio_chip_set_multiple(chip, mask, bits);
}
} }
} }
...@@ -1403,7 +1411,7 @@ void gpiod_set_value(struct gpio_desc *desc, int value) ...@@ -1403,7 +1411,7 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
EXPORT_SYMBOL_GPL(gpiod_set_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 * @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @value_array: array of values to assign
...@@ -1414,17 +1422,18 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); ...@@ -1414,17 +1422,18 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
* This function should be called from contexts where we cannot sleep, and will * This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep. * 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) struct gpio_desc **desc_array, int *value_array)
{ {
if (!desc_array) if (!desc_array)
return; 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 * @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @value_array: array of values to assign
...@@ -1435,14 +1444,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array); ...@@ -1435,14 +1444,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
* This function should be called from contexts where we cannot sleep, and will * This function should be called from contexts where we cannot sleep, and will
* complain if the GPIO chip functions potentially sleep. * complain if the GPIO chip functions potentially sleep.
*/ */
void gpiod_set_array(unsigned int array_size, void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array) struct gpio_desc **desc_array, int *value_array)
{ {
if (!desc_array) if (!desc_array)
return; 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 * gpiod_cansleep() - report whether gpio value access may sleep
...@@ -1604,7 +1614,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) ...@@ -1604,7 +1614,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); 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 * @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @value_array: array of values to assign
...@@ -1614,19 +1624,20 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); ...@@ -1614,19 +1624,20 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
* *
* This function is to be called from contexts that can sleep. * This function is to be called from contexts that can sleep.
*/ */
void gpiod_set_raw_array_cansleep(unsigned int array_size, void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc_array) if (!desc_array)
return; 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 * @array_size: number of elements in the descriptor / value arrays
* @desc_array: array of GPIO descriptors whose values will be assigned * @desc_array: array of GPIO descriptors whose values will be assigned
* @value_array: array of values to assign * @value_array: array of values to assign
...@@ -1636,16 +1647,17 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep); ...@@ -1636,16 +1647,17 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
* *
* This function is to be called from contexts that can sleep. * This function is to be called from contexts that can sleep.
*/ */
void gpiod_set_array_cansleep(unsigned int array_size, void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
{ {
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
if (!desc_array) if (!desc_array)
return; 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 * gpiod_add_lookup_table() - register GPIO device consumers
...@@ -1880,7 +1892,7 @@ EXPORT_SYMBOL_GPL(gpiod_count); ...@@ -1880,7 +1892,7 @@ EXPORT_SYMBOL_GPL(gpiod_count);
* *
* Return the GPIO descriptor corresponding to the function con_id of device * 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 * 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, struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id,
enum gpiod_flags flags) enum gpiod_flags flags)
...@@ -1960,7 +1972,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, ...@@ -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 * 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 * 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, struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
const char *con_id, const char *con_id,
...@@ -2118,13 +2130,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, ...@@ -2118,13 +2130,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
local_desc = gpiochip_request_own_desc(chip, hwnum, name); local_desc = gpiochip_request_own_desc(chip, hwnum, name);
if (IS_ERR(local_desc)) { 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); return PTR_ERR(local_desc);
} }
status = gpiod_configure_flags(desc, name, lflags, dflags); status = gpiod_configure_flags(desc, name, lflags, dflags);
if (status < 0) { 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); gpiochip_free_own_desc(desc);
return status; return status;
} }
......
...@@ -83,20 +83,12 @@ struct gpio_desc { ...@@ -83,20 +83,12 @@ struct gpio_desc {
#define FLAG_IS_OUT 1 #define FLAG_IS_OUT 1
#define FLAG_EXPORT 2 /* protected by sysfs_lock */ #define FLAG_EXPORT 2 /* protected by sysfs_lock */
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ #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_ACTIVE_LOW 6 /* value has active low */
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source 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_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 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; const char *label;
}; };
...@@ -151,17 +143,17 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc) ...@@ -151,17 +143,17 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
#ifdef CONFIG_GPIO_SYSFS #ifdef CONFIG_GPIO_SYSFS
int gpiochip_export(struct gpio_chip *chip); int gpiochip_sysfs_register(struct gpio_chip *chip);
void gpiochip_unexport(struct gpio_chip *chip); void gpiochip_sysfs_unregister(struct gpio_chip *chip);
#else #else
static inline int gpiochip_export(struct gpio_chip *chip) static inline int gpiochip_sysfs_register(struct gpio_chip *chip)
{ {
return 0; return 0;
} }
static inline void gpiochip_unexport(struct gpio_chip *chip) static inline void gpiochip_sysfs_unregister(struct gpio_chip *chip)
{ {
} }
......
...@@ -107,7 +107,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) ...@@ -107,7 +107,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
if (sb->access_mode == ACPI_I2C_10BIT_MODE) if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN; info->flags |= I2C_CLIENT_TEN;
} }
} else if (info->irq < 0) { } else if (!info->irq) {
struct resource r; struct resource r;
if (acpi_dev_resource_interrupt(ares, 0, &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, ...@@ -134,7 +134,6 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
info.fwnode = acpi_fwnode_handle(adev); info.fwnode = acpi_fwnode_handle(adev);
info.irq = -1;
INIT_LIST_HEAD(&resource_list); INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, ret = acpi_dev_get_resources(adev, &resource_list,
...@@ -632,8 +631,13 @@ static int i2c_device_probe(struct device *dev) ...@@ -632,8 +631,13 @@ static int i2c_device_probe(struct device *dev)
if (!client) if (!client)
return 0; return 0;
if (!client->irq && dev->of_node) { if (!client->irq) {
int irq = of_irq_get(dev->of_node, 0); 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) if (irq == -EPROBE_DEFER)
return irq; return irq;
......
...@@ -35,7 +35,8 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child, ...@@ -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++) for (n = 0; n < s->gpios->ndescs; n++)
values[n] = (desired_child >> n) & 1; 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; return 0;
} }
......
...@@ -55,7 +55,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) ...@@ -55,7 +55,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
count++; count++;
} }
gpiod_set_array(count, desc_array, value_array); gpiod_set_array_value(count, desc_array, value_array);
} }
EXPORT_SYMBOL_GPL(mctrl_gpio_set); EXPORT_SYMBOL_GPL(mctrl_gpio_set);
......
...@@ -128,11 +128,6 @@ static inline int gpio_export_link(struct device *dev, const char *name, ...@@ -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)); 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) static inline void gpio_unexport(unsigned gpio)
{ {
gpiod_unexport(gpio_to_desc(gpio)); gpiod_unexport(gpio_to_desc(gpio));
......
...@@ -721,6 +721,8 @@ static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) ...@@ -721,6 +721,8 @@ static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
if (adev) if (adev)
adev->driver_gpios = NULL; adev->driver_gpios = NULL;
} }
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
#else #else
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev, static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
const struct acpi_gpio_mapping *gpios) const struct acpi_gpio_mapping *gpios)
...@@ -728,6 +730,11 @@ static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev, ...@@ -728,6 +730,11 @@ static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
return -ENXIO; return -ENXIO;
} }
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {} 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 #endif
/* Device properties */ /* Device properties */
......
...@@ -74,5 +74,6 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, ...@@ -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_SET BIT(1) /* reg_set is unreadable */
#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */ #define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */
#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3) #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 */ #endif /* __BASIC_MMIO_GPIO_H */
...@@ -196,13 +196,6 @@ static inline int gpio_export_link(struct device *dev, const char *name, ...@@ -196,13 +196,6 @@ static inline int gpio_export_link(struct device *dev, const char *name,
return -EINVAL; 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) static inline void gpio_unexport(unsigned gpio)
{ {
/* GPIO can never have been exported */ /* GPIO can never have been exported */
......
...@@ -100,24 +100,25 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value); ...@@ -100,24 +100,25 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
/* Value get/set from non-sleeping context */ /* Value get/set from non-sleeping context */
int gpiod_get_value(const struct gpio_desc *desc); int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_set_value(struct gpio_desc *desc, int value); void gpiod_set_value(struct gpio_desc *desc, int value);
void gpiod_set_array(unsigned int array_size, void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, int *value_array); struct gpio_desc **desc_array, int *value_array);
int gpiod_get_raw_value(const struct gpio_desc *desc); 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_value(struct gpio_desc *desc, int value);
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); struct gpio_desc **desc_array,
int *value_array);
/* Value get/set from sleeping context */ /* Value get/set from sleeping context */
int gpiod_get_value_cansleep(const struct gpio_desc *desc); int gpiod_get_value_cansleep(const struct gpio_desc *desc);
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_array_cansleep(unsigned int array_size, void gpiod_set_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); int *value_array);
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc); 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_value_cansleep(struct gpio_desc *desc, int value);
void gpiod_set_raw_array_cansleep(unsigned int array_size, void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array); int *value_array);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); 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) ...@@ -304,9 +305,9 @@ static inline void gpiod_set_value(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
} }
static inline void gpiod_set_array(unsigned int array_size, static inline void gpiod_set_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
...@@ -322,9 +323,9 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value) ...@@ -322,9 +323,9 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
} }
static inline void gpiod_set_raw_array(unsigned int array_size, static inline void gpiod_set_raw_array_value(unsigned int array_size,
struct gpio_desc **desc_array, struct gpio_desc **desc_array,
int *value_array) int *value_array)
{ {
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); WARN_ON(1);
...@@ -341,7 +342,7 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) ...@@ -341,7 +342,7 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); 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, struct gpio_desc **desc_array,
int *value_array) int *value_array)
{ {
...@@ -360,7 +361,7 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, ...@@ -360,7 +361,7 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
/* GPIO can never have been requested */ /* GPIO can never have been requested */
WARN_ON(1); 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, struct gpio_desc **desc_array,
int *value_array) int *value_array)
{ {
...@@ -449,7 +450,6 @@ static inline int desc_to_gpio(const struct gpio_desc *desc) ...@@ -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(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name, int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc); struct gpio_desc *desc);
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
void gpiod_unexport(struct gpio_desc *desc); void gpiod_unexport(struct gpio_desc *desc);
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
...@@ -466,11 +466,6 @@ static inline int gpiod_export_link(struct device *dev, const char *name, ...@@ -466,11 +466,6 @@ static inline int gpiod_export_link(struct device *dev, const char *name,
return -ENOSYS; 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) static inline void gpiod_unexport(struct gpio_desc *desc)
{ {
} }
......
...@@ -20,6 +20,7 @@ struct seq_file; ...@@ -20,6 +20,7 @@ struct seq_file;
* struct gpio_chip - abstract a GPIO controller * struct gpio_chip - abstract a GPIO controller
* @label: for diagnostics * @label: for diagnostics
* @dev: optional device providing the GPIOs * @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 * @owner: helps prevent removal of modules exporting active GPIOs
* @list: links gpio_chips together for traversal * @list: links gpio_chips together for traversal
* @request: optional hook for chip-specific activation, such as * @request: optional hook for chip-specific activation, such as
...@@ -41,8 +42,12 @@ struct seq_file; ...@@ -41,8 +42,12 @@ struct seq_file;
* @dbg_show: optional routine to show contents in debugfs; default code * @dbg_show: optional routine to show contents in debugfs; default code
* will be used when this is omitted, but custom code can show extra * will be used when this is omitted, but custom code can show extra
* state (such as pullup/pulldown configuration). * state (such as pullup/pulldown configuration).
* @base: identifies the first GPIO number handled by this chip; or, if * @base: identifies the first GPIO number handled by this chip;
* negative during registration, requests dynamic ID allocation. * 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 * @ngpio: the number of GPIOs handled by this controller; the last GPIO
* handled is (base + ngpio - 1). * handled is (base + ngpio - 1).
* @desc: array of ngpio descriptors. Private. * @desc: array of ngpio descriptors. Private.
...@@ -57,7 +62,6 @@ struct seq_file; ...@@ -57,7 +62,6 @@ struct seq_file;
* implies that if the chip supports IRQs, these IRQs need to be threaded * 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 * as the chip access may sleep when e.g. reading out the IRQ status
* registers. * 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 * @irq_not_threaded: flag must be set if @can_sleep is set but the
* IRQs don't need to be threaded * IRQs don't need to be threaded
* *
...@@ -74,6 +78,7 @@ struct seq_file; ...@@ -74,6 +78,7 @@ struct seq_file;
struct gpio_chip { struct gpio_chip {
const char *label; const char *label;
struct device *dev; struct device *dev;
struct device *cdev;
struct module *owner; struct module *owner;
struct list_head list; struct list_head list;
...@@ -109,7 +114,6 @@ struct gpio_chip { ...@@ -109,7 +114,6 @@ struct gpio_chip {
const char *const *names; const char *const *names;
bool can_sleep; bool can_sleep;
bool irq_not_threaded; bool irq_not_threaded;
bool exported;
#ifdef CONFIG_GPIOLIB_IRQCHIP #ifdef CONFIG_GPIOLIB_IRQCHIP
/* /*
...@@ -121,6 +125,7 @@ struct gpio_chip { ...@@ -121,6 +125,7 @@ struct gpio_chip {
unsigned int irq_base; unsigned int irq_base;
irq_flow_handler_t irq_handler; irq_flow_handler_t irq_handler;
unsigned int irq_default_type; unsigned int irq_default_type;
int irq_parent;
#endif #endif
#if defined(CONFIG_OF_GPIO) #if defined(CONFIG_OF_GPIO)
......
...@@ -208,9 +208,17 @@ struct omap_gpio_platform_data { ...@@ -208,9 +208,17 @@ struct omap_gpio_platform_data {
int (*get_context_loss_count)(struct device *dev); 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_prepare_for_idle(int off_mode);
extern void omap2_gpio_resume_after_idle(void); extern void omap2_gpio_resume_after_idle(void);
extern void omap_set_gpio_debounce(int gpio, int enable); #else
extern void omap_set_gpio_debounce_time(int gpio, int enable); static inline void omap2_gpio_prepare_for_idle(int off_mode)
{
}
static inline void omap2_gpio_resume_after_idle(void)
{
}
#endif
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment