forked from Minki/linux
This is the big bulk of GPIO changes queued for the v4.2
kernel series: - A big set of cleanups to the aged sysfs interface from Johan Hovold. To get these in, v4.1-rc3 was merged into the tree as the first patch in that series had to go into stable. This makes the locking much more fine-grained (get rid of the "big GPIO lock(s)" and store states in the GPIO descriptors. - Rename gpiod_[g|s]et_array() to gpiod_[g|s]et_array_value() to avoid confusions. - New drivers for: - NXP LPC18xx (currently LPC1850) - NetLogic XLP - Broadcom STB SoC's - Axis ETRAXFS - Zynq Ultrascale+ (subdriver) - ACPI: - Make it possible to retrieve GpioInt resources from a GPIO device using acpi_dev_gpio_irq_get() - Merge some dependent I2C changes exploiting this. - Support the ARM X-Gene GPIO standby driver. - Make it possible for the generic GPIO driver to read back the value set registers to reflect current status. - Loads of OMAP IRQ handling fixes. - Incremental improvements to Kona, max732x, OMAP, MXC, RCAR, PCA953x, STP-XWAY, PCF857x, Crystalcove, TB10x. - Janitorial (contification, checkpatch cleanups) -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVh76DAAoJEEEQszewGV1zYFsP/AnyCHs4M67k5Eegxtiwoomc OTqkVtOcob9kfqMkbZ1dsjZe2ZYIDiyWeQ1xuV+dD9nx/iAu6inUxb0dXhxKXonr +7mQglg32+zWTepLOJosoftoIqOb06lsMfgjL+tJcY5Od7/rewpdEplfEcjmq1O0 0OdaV2FCXIhHDt52iYHT4tYI1GCky9K4Au9NlPCbKAsGneb3fQahF9o3JpYXl1Oq YhIFzUEhM+Zi2IoRsloGdK/eGEHni59IDekhZDf4PnYgA4Dkx2/e1A2Q0h5oT+QI j2yfRbI9t1gA5UK7JR/rVJF+5+E8uZ06TZgTo8tU00U4ZvppNgHt8O4KZkJMFBce KZzD9rkVVGp0NIDVwmOWjnfwkVVcQzMg/Wf17oM+qdaPO4GHEXNaQaInk1zmwqZq tQiTk47zA4rrEaYq3YZjt4xQjl8+ExDlOzFjnfLYAm27gbIl6EFWbX2ON981MC8g Nap8MLZINbGTlyDHtuqUlnqN+oXoP8niFuuDixYR+pM1P1bgwIVF+VopRJBFJRJP IeR6VdsI9KS99Kg8ICf4ds6WdKAGU3Htj+26udgMhIlOWrkCbvvexIxq9oBkwIB1 VZofnSZLqnlKvo9Z140atvJWkFti7mqhItVjohmZyvyImLtmQBMq3kSGurXEqWms /NGZ0txPd1lMHx5o6ZPK =vKYs -----END PGP SIGNATURE----- Merge tag 'gpio-v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull gpio updates from Linus Walleij: "This is the big bulk of GPIO changes queued for the v4.2 kernel series: - a big set of cleanups to the aged sysfs interface from Johan Hovold. To get these in, v4.1-rc3 was merged into the tree as the first patch in that series had to go into stable. This makes the locking much more fine-grained (get rid of the "big GPIO lock(s)" and store states in the GPIO descriptors. - rename gpiod_[g|s]et_array() to gpiod_[g|s]et_array_value() to avoid confusions. - New drivers for: * NXP LPC18xx (currently LPC1850) * NetLogic XLP * Broadcom STB SoC's * Axis ETRAXFS * Zynq Ultrascale+ (subdriver) - ACPI: * make it possible to retrieve GpioInt resources from a GPIO device using acpi_dev_gpio_irq_get() * merge some dependent I2C changes exploiting this. * support the ARM X-Gene GPIO standby driver. - make it possible for the generic GPIO driver to read back the value set registers to reflect current status. - loads of OMAP IRQ handling fixes. - incremental improvements to Kona, max732x, OMAP, MXC, RCAR, PCA953x, STP-XWAY, PCF857x, Crystalcove, TB10x. - janitorial (constification, checkpatch cleanups)" * tag 'gpio-v4.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (71 commits) gpio: Fix checkpatch.pl issues gpio: pcf857x: handle only enabled irqs gpio / ACPI: Return -EPROBE_DEFER if the gpiochip was not found GPIO / ACPI: export acpi_gpiochip_request(free)_interrupts for module use gpio: improve error reporting on own descriptors gpio: promote own request failure to pr_err() gpio: Added support to Zynq Ultrascale+ MPSoC gpio: add ETRAXFS GPIO driver fix documentation after renaming gpiod_set_array to gpiod_set_array_value gpio: Add GPIO support for Broadcom STB SoCs gpio: xgene: add ACPI support for APM X-Gene GPIO standby driver gpio: tb10x: Drop unneeded free_irq() call gpio: crystalcove: set IRQCHIP_SKIP_SET_WAKE for the irqchip gpio: stp-xway: Use the of_property_read_u32 helper gpio: pcf857x: Check for irq_set_irq_wake() failures gpio-stp-xway: Fix enabling the highest bit of the PHY LEDs gpio: Prevent an integer overflow in the pca953x driver gpio: omap: rework omap_gpio_irq_startup to handle current pin state properly gpio: omap: rework omap_gpio_request to touch only gpio specific registers gpio: omap: rework omap_x_irq_shutdown to touch only irqs specific registers ...
This commit is contained in:
commit
10b4b096d0
65
Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
Normal file
65
Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
Normal file
@ -0,0 +1,65 @@
|
||||
Broadcom STB "UPG GIO" GPIO controller
|
||||
|
||||
The controller's registers are organized as sets of eight 32-bit
|
||||
registers with each set controlling a bank of up to 32 pins. A single
|
||||
interrupt is shared for all of the banks handled by the controller.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible:
|
||||
Must be "brcm,brcmstb-gpio"
|
||||
|
||||
- reg:
|
||||
Define the base and range of the I/O address space containing
|
||||
the brcmstb GPIO controller registers
|
||||
|
||||
- #gpio-cells:
|
||||
Should be <2>. The first cell is the pin number (within the controller's
|
||||
pin space), and the second is used for the following:
|
||||
bit[0]: polarity (0 for active-high, 1 for active-low)
|
||||
|
||||
- gpio-controller:
|
||||
Specifies that the node is a GPIO controller.
|
||||
|
||||
- brcm,gpio-bank-widths:
|
||||
Number of GPIO lines for each bank. Number of elements must
|
||||
correspond to number of banks suggested by the 'reg' property.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- interrupts:
|
||||
The interrupt shared by all GPIO lines for this controller.
|
||||
|
||||
- interrupt-parent:
|
||||
phandle of the parent interrupt controller
|
||||
|
||||
- #interrupt-cells:
|
||||
Should be <2>. The first cell is the GPIO number, the second should specify
|
||||
flags. The following subset of flags is supported:
|
||||
- bits[3:0] trigger type and level flags
|
||||
1 = low-to-high edge triggered
|
||||
2 = high-to-low edge triggered
|
||||
4 = active high level-sensitive
|
||||
8 = active low level-sensitive
|
||||
Valid combinations are 1, 2, 3, 4, 8.
|
||||
See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
- interrupt-controller:
|
||||
Marks the device node as an interrupt controller
|
||||
|
||||
- interrupt-names:
|
||||
The name of the IRQ resource used by this controller
|
||||
|
||||
Example:
|
||||
upg_gio: gpio@f040a700 {
|
||||
#gpio-cells = <0x2>;
|
||||
#interrupt-cells = <0x2>;
|
||||
compatible = "brcm,bcm7445-gpio", "brcm,brcmstb-gpio";
|
||||
gpio-controller;
|
||||
interrupt-controller;
|
||||
reg = <0xf040a700 0x80>;
|
||||
interrupt-parent = <0xf>;
|
||||
interrupts = <0x6>;
|
||||
interrupt-names = "upg_gio";
|
||||
brcm,gpio-bank-widths = <0x20 0x20 0x20 0x18>;
|
||||
};
|
21
Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt
Normal file
21
Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt
Normal file
@ -0,0 +1,21 @@
|
||||
Axis ETRAX FS General I/O controller bindings
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible:
|
||||
- "axis,etraxfs-gio"
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- #gpio-cells: Should be 3
|
||||
- The first cell is the gpio offset number.
|
||||
- The second cell is reserved and is currently unused.
|
||||
- The third cell is the port number (hex).
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
|
||||
Example:
|
||||
|
||||
gio: gpio@b001a000 {
|
||||
compatible = "axis,etraxfs-gio";
|
||||
reg = <0xb001a000 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <3>;
|
||||
};
|
47
Documentation/devicetree/bindings/gpio/gpio-xlp.txt
Normal file
47
Documentation/devicetree/bindings/gpio/gpio-xlp.txt
Normal file
@ -0,0 +1,47 @@
|
||||
Netlogic XLP Family GPIO
|
||||
========================
|
||||
|
||||
This GPIO driver is used for following Netlogic XLP SoCs:
|
||||
XLP832, XLP316, XLP208, XLP980, XLP532
|
||||
|
||||
Required properties:
|
||||
-------------------
|
||||
|
||||
- compatible: Should be one of the following:
|
||||
- "netlogic,xlp832-gpio": For Netlogic XLP832
|
||||
- "netlogic,xlp316-gpio": For Netlogic XLP316
|
||||
- "netlogic,xlp208-gpio": For Netlogic XLP208
|
||||
- "netlogic,xlp980-gpio": For Netlogic XLP980
|
||||
- "netlogic,xlp532-gpio": For Netlogic XLP532
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- #gpio-cells: Should be two. The first cell is the pin number and the second
|
||||
cell is used to specify optional parameters (currently unused).
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- nr-gpios: Number of GPIO pins supported by the controller.
|
||||
- interrupt-cells: Should be two. The first cell is the GPIO Number. The
|
||||
second cell is used to specify flags. The following subset of flags is
|
||||
supported:
|
||||
- trigger type:
|
||||
1 = low to high edge triggered.
|
||||
2 = high to low edge triggered.
|
||||
4 = active high level-sensitive.
|
||||
8 = active low level-sensitive.
|
||||
- interrupts: Interrupt number for this device.
|
||||
- interrupt-parent: phandle of the parent interrupt controller.
|
||||
- interrupt-controller: Identifies the node as an interrupt controller.
|
||||
|
||||
Example:
|
||||
|
||||
gpio: xlp_gpio@34000 {
|
||||
compatible = "netlogic,xlp316-gpio";
|
||||
reg = <0 0x34100 0x1000
|
||||
0 0x35100 0x1000>;
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
nr-gpios = <57>;
|
||||
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&pic>;
|
||||
interrupts = <39>;
|
||||
interrupt-controller;
|
||||
};
|
@ -6,7 +6,7 @@ Required properties:
|
||||
- First cell is the GPIO line number
|
||||
- Second cell is used to specify optional
|
||||
parameters (unused)
|
||||
- compatible : Should be "xlnx,zynq-gpio-1.0"
|
||||
- compatible : Should be "xlnx,zynq-gpio-1.0" or "xlnx,zynqmp-gpio-1.0"
|
||||
- clocks : Clock specifier (see clock bindings for details)
|
||||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
- interrupts : Interrupt specifier (see interrupt bindings for
|
||||
|
39
Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt
Normal file
39
Documentation/devicetree/bindings/gpio/nxp,lpc1850-gpio.txt
Normal file
@ -0,0 +1,39 @@
|
||||
NXP LPC18xx/43xx GPIO controller Device Tree Bindings
|
||||
-----------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "nxp,lpc1850-gpio"
|
||||
- reg : Address and length of the register set for the device
|
||||
- clocks : Clock specifier (see clock bindings for details)
|
||||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
- #gpio-cells : Should be two
|
||||
- First cell is the GPIO line number
|
||||
- Second cell is used to specify polarity
|
||||
|
||||
Optional properties:
|
||||
- gpio-ranges : Mapping between GPIO and pinctrl
|
||||
|
||||
Example:
|
||||
#define LPC_GPIO(port, pin) (port * 32 + pin)
|
||||
#define LPC_PIN(port, pin) (0x##port * 32 + pin)
|
||||
|
||||
gpio: gpio@400f4000 {
|
||||
compatible = "nxp,lpc1850-gpio";
|
||||
reg = <0x400f4000 0x4000>;
|
||||
clocks = <&ccu1 CLK_CPU_GPIO>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&pinctrl LPC_GPIO(0,0) LPC_PIN(0,0) 2>,
|
||||
...
|
||||
<&pinctrl LPC_GPIO(7,19) LPC_PIN(f,5) 7>;
|
||||
};
|
||||
|
||||
gpio_joystick {
|
||||
compatible = "gpio-keys-polled";
|
||||
...
|
||||
|
||||
button@0 {
|
||||
...
|
||||
gpios = <&gpio LPC_GPIO(4,8) GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
@ -241,18 +241,18 @@ Set multiple GPIO outputs with a single function call
|
||||
-----------------------------------------------------
|
||||
The following functions set the output values of an array of GPIOs:
|
||||
|
||||
void gpiod_set_array(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_raw_array(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_array_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_raw_array_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
|
||||
The array can be an arbitrary set of GPIOs. The functions will try to set
|
||||
GPIOs belonging to the same bank or chip simultaneously if supported by the
|
||||
@ -271,8 +271,8 @@ matches the desired group of GPIOs, those GPIOs can be set by simply using
|
||||
the struct gpio_descs returned by gpiod_get_array():
|
||||
|
||||
struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
|
||||
gpiod_set_array(my_gpio_descs->ndescs, my_gpio_descs->desc,
|
||||
my_gpio_values);
|
||||
gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
|
||||
my_gpio_values);
|
||||
|
||||
It is also possible to set a completely arbitrary array of descriptors. The
|
||||
descriptors may be obtained using any combination of gpiod_get() and
|
||||
|
@ -751,9 +751,6 @@ requested using gpio_request():
|
||||
int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
|
||||
/* change the polarity of a GPIO node in sysfs */
|
||||
int gpio_sysfs_set_active_low(unsigned gpio, int value);
|
||||
|
||||
After a kernel driver requests a GPIO, it may only be made available in
|
||||
the sysfs interface by gpio_export(). The driver can control whether the
|
||||
signal direction may change. This helps drivers prevent userspace code
|
||||
@ -767,9 +764,3 @@ After the GPIO has been exported, gpio_export_link() allows creating
|
||||
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
|
||||
use this to provide the interface under their own device in sysfs with
|
||||
a descriptive name.
|
||||
|
||||
Drivers can use gpio_sysfs_set_active_low() to hide GPIO line polarity
|
||||
differences between boards from user space. This only affects the
|
||||
sysfs interface. Polarity change can be done both before and after
|
||||
gpio_export(), and previously enabled poll(2) support for either
|
||||
rising or falling edge will be reconfigured to follow this setting.
|
||||
|
@ -132,9 +132,6 @@ requested using gpio_request():
|
||||
int gpiod_export_link(struct device *dev, const char *name,
|
||||
struct gpio_desc *desc);
|
||||
|
||||
/* change the polarity of a GPIO node in sysfs */
|
||||
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
|
||||
|
||||
After a kernel driver requests a GPIO, it may only be made available in
|
||||
the sysfs interface by gpiod_export(). The driver can control whether the
|
||||
signal direction may change. This helps drivers prevent userspace code
|
||||
@ -148,8 +145,3 @@ After the GPIO has been exported, gpiod_export_link() allows creating
|
||||
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
|
||||
use this to provide the interface under their own device in sysfs with
|
||||
a descriptive name.
|
||||
|
||||
Drivers can use gpiod_sysfs_set_active_low() to hide GPIO line polarity
|
||||
differences between boards from user space. Polarity change can be done both
|
||||
before and after gpiod_export(), and previously enabled poll(2) support for
|
||||
either rising or falling edge will be reconfigured to follow this setting.
|
||||
|
@ -638,9 +638,6 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
|
||||
int gpio_export_link(struct device *dev, const char *name,
|
||||
unsigned gpio)
|
||||
|
||||
/* 改变 sysfs 中的一个 GPIO 节点的极性 */
|
||||
int gpio_sysfs_set_active_low(unsigned gpio, int value);
|
||||
|
||||
在一个内核驱动申请一个 GPIO 之后,它可以通过 gpio_export()使其在 sysfs
|
||||
接口中可见。该驱动可以控制信号方向是否可修改。这有助于防止用户空间代码无意间
|
||||
破坏重要的系统状态。
|
||||
@ -651,8 +648,3 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
|
||||
在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方
|
||||
创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
|
||||
名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
|
||||
|
||||
驱动可以使用 gpio_sysfs_set_active_low() 来在用户空间隐藏电路板之间
|
||||
GPIO 线的极性差异。这个仅对 sysfs 接口起作用。极性的改变可以在 gpio_export()
|
||||
前后进行,且之前使能的轮询操作(poll(2))支持(上升或下降沿)将会被重新配置来遵循
|
||||
这个设置。
|
||||
|
@ -2250,6 +2250,13 @@ N: bcm9583*
|
||||
N: bcm583*
|
||||
N: bcm113*
|
||||
|
||||
BROADCOM BRCMSTB GPIO DRIVER
|
||||
M: Gregory Fong <gregory.0xf0@gmail.com>
|
||||
L: bcm-kernel-feedback-list@broadcom.com>
|
||||
S: Supported
|
||||
F: drivers/gpio/gpio-brcmstb.c
|
||||
F: Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt
|
||||
|
||||
BROADCOM KONA GPIO DRIVER
|
||||
M: Ray Jui <rjui@broadcom.com>
|
||||
L: bcm-kernel-feedback-list@broadcom.com
|
||||
|
@ -126,6 +126,14 @@ config GPIO_BCM_KONA
|
||||
help
|
||||
Turn on GPIO support for Broadcom "Kona" chips.
|
||||
|
||||
config GPIO_BRCMSTB
|
||||
tristate "BRCMSTB GPIO support"
|
||||
default y if ARCH_BRCMSTB
|
||||
depends on OF_GPIO && (ARCH_BRCMSTB || COMPILE_TEST)
|
||||
select GPIO_GENERIC
|
||||
help
|
||||
Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs.
|
||||
|
||||
config GPIO_CLPS711X
|
||||
tristate "CLPS711X GPIO support"
|
||||
depends on ARCH_CLPS711X || COMPILE_TEST
|
||||
@ -159,6 +167,14 @@ config GPIO_EP93XX
|
||||
depends on ARCH_EP93XX
|
||||
select GPIO_GENERIC
|
||||
|
||||
config GPIO_ETRAXFS
|
||||
bool "Axis ETRAX FS General I/O"
|
||||
depends on CRIS || COMPILE_TEST
|
||||
depends on OF
|
||||
select GPIO_GENERIC
|
||||
help
|
||||
Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
|
||||
|
||||
config GPIO_F7188X
|
||||
tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
|
||||
depends on X86
|
||||
@ -230,6 +246,14 @@ config GPIO_LOONGSON
|
||||
help
|
||||
driver for GPIO functionality on Loongson-2F/3A/3B processors.
|
||||
|
||||
config GPIO_LPC18XX
|
||||
bool "NXP LPC18XX/43XX GPIO support"
|
||||
default y if ARCH_LPC18XX
|
||||
depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST)
|
||||
help
|
||||
Select this option to enable GPIO driver for
|
||||
NXP LPC18XX/43XX devices.
|
||||
|
||||
config GPIO_LYNXPOINT
|
||||
tristate "Intel Lynxpoint GPIO support"
|
||||
depends on ACPI && X86
|
||||
@ -308,7 +332,7 @@ config GPIO_OCTEON
|
||||
family of SOCs.
|
||||
|
||||
config GPIO_OMAP
|
||||
bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS
|
||||
tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST
|
||||
default y if ARCH_OMAP
|
||||
depends on ARM
|
||||
select GENERIC_IRQ_CHIP
|
||||
@ -488,6 +512,17 @@ config GPIO_XILINX
|
||||
help
|
||||
Say yes here to support the Xilinx FPGA GPIO device
|
||||
|
||||
config GPIO_XLP
|
||||
tristate "Netlogic XLP GPIO support"
|
||||
depends on CPU_XLP
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
This driver provides support for GPIO interface on Netlogic XLP MIPS64
|
||||
SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX,
|
||||
XLP9XX and XLP5XX.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config GPIO_XTENSA
|
||||
bool "Xtensa GPIO32 support"
|
||||
depends on XTENSA
|
||||
@ -505,7 +540,7 @@ config GPIO_ZEVIO
|
||||
|
||||
config GPIO_ZYNQ
|
||||
tristate "Xilinx Zynq GPIO support"
|
||||
depends on ARCH_ZYNQ
|
||||
depends on ARCH_ZYNQ || ARCH_ZYNQMP
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support Xilinx Zynq GPIO controller.
|
||||
|
@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
|
||||
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
|
||||
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
||||
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
|
||||
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
|
||||
@ -32,6 +33,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
|
||||
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
|
||||
obj-$(CONFIG_GPIO_EM) += gpio-em.o
|
||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||
obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o
|
||||
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
|
||||
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
||||
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
|
||||
@ -44,6 +46,7 @@ obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
|
||||
obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
|
||||
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
|
||||
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
|
||||
obj-$(CONFIG_GPIO_LPC18XX) += gpio-lpc18xx.o
|
||||
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
|
||||
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
|
||||
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
|
||||
@ -109,6 +112,7 @@ obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
|
||||
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
|
||||
obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
|
||||
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
|
||||
obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o
|
||||
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
|
||||
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
|
||||
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
|
||||
|
@ -107,7 +107,8 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static unsigned int altera_gpio_irq_startup(struct irq_data *d) {
|
||||
static unsigned int altera_gpio_irq_startup(struct irq_data *d)
|
||||
{
|
||||
altera_gpio_irq_unmask(d);
|
||||
|
||||
return 0;
|
||||
|
@ -122,6 +122,16 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
|
||||
void __iomem *reg_base = kona_gpio->reg_base;
|
||||
u32 val;
|
||||
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK;
|
||||
return val ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
|
||||
}
|
||||
|
||||
static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
||||
{
|
||||
struct bcm_kona_gpio *kona_gpio;
|
||||
@ -135,12 +145,8 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
/* determine the GPIO pin direction */
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||
val &= GPIO_GPCTR0_IOTR_MASK;
|
||||
|
||||
/* this function only applies to output pin */
|
||||
if (GPIO_GPCTR0_IOTR_CMD_INPUT == val)
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
|
||||
goto out;
|
||||
|
||||
reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
|
||||
@ -166,13 +172,12 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
||||
reg_base = kona_gpio->reg_base;
|
||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||
|
||||
/* determine the GPIO pin direction */
|
||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||
val &= GPIO_GPCTR0_IOTR_MASK;
|
||||
if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN)
|
||||
reg_offset = GPIO_IN_STATUS(bank_id);
|
||||
else
|
||||
reg_offset = GPIO_OUT_STATUS(bank_id);
|
||||
|
||||
/* read the GPIO bank status */
|
||||
reg_offset = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ?
|
||||
GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
|
||||
val = readl(reg_base + reg_offset);
|
||||
|
||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||
@ -310,6 +315,7 @@ static struct gpio_chip template_chip = {
|
||||
.owner = THIS_MODULE,
|
||||
.request = bcm_kona_gpio_request,
|
||||
.free = bcm_kona_gpio_free,
|
||||
.get_direction = bcm_kona_gpio_get_dir,
|
||||
.direction_input = bcm_kona_gpio_direction_input,
|
||||
.get = bcm_kona_gpio_get,
|
||||
.direction_output = bcm_kona_gpio_direction_output,
|
||||
|
252
drivers/gpio/gpio-brcmstb.c
Normal file
252
drivers/gpio/gpio-brcmstb.c
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Broadcom Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/basic_mmio_gpio.h>
|
||||
|
||||
#define GIO_BANK_SIZE 0x20
|
||||
#define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00)
|
||||
#define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04)
|
||||
#define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08)
|
||||
#define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c)
|
||||
#define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10)
|
||||
#define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14)
|
||||
#define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18)
|
||||
#define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c)
|
||||
|
||||
struct brcmstb_gpio_bank {
|
||||
struct list_head node;
|
||||
int id;
|
||||
struct bgpio_chip bgc;
|
||||
struct brcmstb_gpio_priv *parent_priv;
|
||||
u32 width;
|
||||
};
|
||||
|
||||
struct brcmstb_gpio_priv {
|
||||
struct list_head bank_list;
|
||||
void __iomem *reg_base;
|
||||
int num_banks;
|
||||
struct platform_device *pdev;
|
||||
int gpio_base;
|
||||
};
|
||||
|
||||
#define MAX_GPIO_PER_BANK 32
|
||||
#define GPIO_BANK(gpio) ((gpio) >> 5)
|
||||
/* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
|
||||
#define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1))
|
||||
|
||||
static inline struct brcmstb_gpio_bank *
|
||||
brcmstb_gpio_gc_to_bank(struct gpio_chip *gc)
|
||||
{
|
||||
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
||||
return container_of(bgc, struct brcmstb_gpio_bank, bgc);
|
||||
}
|
||||
|
||||
static inline struct brcmstb_gpio_priv *
|
||||
brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
|
||||
{
|
||||
struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
|
||||
return bank->parent_priv;
|
||||
}
|
||||
|
||||
/* Make sure that the number of banks matches up between properties */
|
||||
static int brcmstb_gpio_sanity_check_banks(struct device *dev,
|
||||
struct device_node *np, struct resource *res)
|
||||
{
|
||||
int res_num_banks = resource_size(res) / GIO_BANK_SIZE;
|
||||
int num_banks =
|
||||
of_property_count_u32_elems(np, "brcm,gpio-bank-widths");
|
||||
|
||||
if (res_num_banks != num_banks) {
|
||||
dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n",
|
||||
res_num_banks, num_banks);
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
|
||||
struct list_head *pos;
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
int ret = 0;
|
||||
|
||||
list_for_each(pos, &priv->bank_list) {
|
||||
bank = list_entry(pos, struct brcmstb_gpio_bank, node);
|
||||
ret = bgpio_remove(&bank->bgc);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "gpiochip_remove fail in cleanup");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec, u32 *flags)
|
||||
{
|
||||
struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
|
||||
struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc);
|
||||
int offset;
|
||||
|
||||
if (gc->of_gpio_n_cells != 2) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
|
||||
return -EINVAL;
|
||||
|
||||
offset = gpiospec->args[0] - (gc->base - priv->gpio_base);
|
||||
if (offset >= gc->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(offset >= bank->width)) {
|
||||
dev_warn_ratelimited(&priv->pdev->dev,
|
||||
"Received request for invalid GPIO offset %d\n",
|
||||
gpiospec->args[0]);
|
||||
}
|
||||
|
||||
if (flags)
|
||||
*flags = gpiospec->args[1];
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
void __iomem *reg_base;
|
||||
struct brcmstb_gpio_priv *priv;
|
||||
struct resource *res;
|
||||
struct property *prop;
|
||||
const __be32 *p;
|
||||
u32 bank_width;
|
||||
int err;
|
||||
static int gpio_base;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(reg_base))
|
||||
return PTR_ERR(reg_base);
|
||||
|
||||
priv->gpio_base = gpio_base;
|
||||
priv->reg_base = reg_base;
|
||||
priv->pdev = pdev;
|
||||
|
||||
INIT_LIST_HEAD(&priv->bank_list);
|
||||
if (brcmstb_gpio_sanity_check_banks(dev, np, res))
|
||||
return -EINVAL;
|
||||
|
||||
of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p,
|
||||
bank_width) {
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
struct bgpio_chip *bgc;
|
||||
struct gpio_chip *gc;
|
||||
|
||||
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
|
||||
if (!bank) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bank->parent_priv = priv;
|
||||
bank->id = priv->num_banks;
|
||||
if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) {
|
||||
dev_err(dev, "Invalid bank width %d\n", bank_width);
|
||||
goto fail;
|
||||
} else {
|
||||
bank->width = bank_width;
|
||||
}
|
||||
|
||||
/*
|
||||
* Regs are 4 bytes wide, have data reg, no set/clear regs,
|
||||
* and direction bits have 0 = output and 1 = input
|
||||
*/
|
||||
bgc = &bank->bgc;
|
||||
err = bgpio_init(bgc, dev, 4,
|
||||
reg_base + GIO_DATA(bank->id),
|
||||
NULL, NULL, NULL,
|
||||
reg_base + GIO_IODIR(bank->id), 0);
|
||||
if (err) {
|
||||
dev_err(dev, "bgpio_init() failed\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gc = &bgc->gc;
|
||||
gc->of_node = np;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->label = np->full_name;
|
||||
gc->base = gpio_base;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
gc->of_xlate = brcmstb_gpio_of_xlate;
|
||||
/* not all ngpio lines are valid, will use bank width later */
|
||||
gc->ngpio = MAX_GPIO_PER_BANK;
|
||||
|
||||
err = gpiochip_add(gc);
|
||||
if (err) {
|
||||
dev_err(dev, "Could not add gpiochip for bank %d\n",
|
||||
bank->id);
|
||||
goto fail;
|
||||
}
|
||||
gpio_base += gc->ngpio;
|
||||
dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id,
|
||||
gc->base, gc->ngpio, bank->width);
|
||||
|
||||
/* Everything looks good, so add bank to list */
|
||||
list_add(&bank->node, &priv->bank_list);
|
||||
|
||||
priv->num_banks++;
|
||||
}
|
||||
|
||||
dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
|
||||
priv->num_banks, priv->gpio_base, gpio_base - 1);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
(void) brcmstb_gpio_remove(pdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id brcmstb_gpio_of_match[] = {
|
||||
{ .compatible = "brcm,brcmstb-gpio" },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match);
|
||||
|
||||
static struct platform_driver brcmstb_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "brcmstb-gpio",
|
||||
.of_match_table = brcmstb_gpio_of_match,
|
||||
},
|
||||
.probe = brcmstb_gpio_probe,
|
||||
.remove = brcmstb_gpio_remove,
|
||||
};
|
||||
module_platform_driver(brcmstb_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Gregory Fong");
|
||||
MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/seq_file.h>
|
||||
@ -94,9 +95,8 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
|
||||
{
|
||||
int reg;
|
||||
|
||||
if (gpio == 94) {
|
||||
if (gpio == 94)
|
||||
return GPIOPANELCTL;
|
||||
}
|
||||
|
||||
if (reg_type == CTRL_IN) {
|
||||
if (gpio < 8)
|
||||
@ -255,6 +255,7 @@ static struct irq_chip crystalcove_irqchip = {
|
||||
.irq_set_type = crystalcove_irq_type,
|
||||
.irq_bus_lock = crystalcove_bus_lock,
|
||||
.irq_bus_sync_unlock = crystalcove_bus_sync_unlock,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
|
||||
|
@ -466,7 +466,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
|
||||
dln2->gpio.owner = THIS_MODULE;
|
||||
dln2->gpio.base = -1;
|
||||
dln2->gpio.ngpio = pins;
|
||||
dln2->gpio.exported = true;
|
||||
dln2->gpio.can_sleep = true;
|
||||
dln2->gpio.irq_not_threaded = true;
|
||||
dln2->gpio.set = dln2_gpio_set;
|
||||
|
176
drivers/gpio/gpio-etraxfs.c
Normal file
176
drivers/gpio/gpio-etraxfs.c
Normal file
@ -0,0 +1,176 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/basic_mmio_gpio.h>
|
||||
|
||||
#define ETRAX_FS_rw_pa_dout 0
|
||||
#define ETRAX_FS_r_pa_din 4
|
||||
#define ETRAX_FS_rw_pa_oe 8
|
||||
#define ETRAX_FS_rw_intr_cfg 12
|
||||
#define ETRAX_FS_rw_intr_mask 16
|
||||
#define ETRAX_FS_rw_ack_intr 20
|
||||
#define ETRAX_FS_r_intr 24
|
||||
#define ETRAX_FS_rw_pb_dout 32
|
||||
#define ETRAX_FS_r_pb_din 36
|
||||
#define ETRAX_FS_rw_pb_oe 40
|
||||
#define ETRAX_FS_rw_pc_dout 48
|
||||
#define ETRAX_FS_r_pc_din 52
|
||||
#define ETRAX_FS_rw_pc_oe 56
|
||||
#define ETRAX_FS_rw_pd_dout 64
|
||||
#define ETRAX_FS_r_pd_din 68
|
||||
#define ETRAX_FS_rw_pd_oe 72
|
||||
#define ETRAX_FS_rw_pe_dout 80
|
||||
#define ETRAX_FS_r_pe_din 84
|
||||
#define ETRAX_FS_rw_pe_oe 88
|
||||
|
||||
struct etraxfs_gpio_port {
|
||||
const char *label;
|
||||
unsigned int oe;
|
||||
unsigned int dout;
|
||||
unsigned int din;
|
||||
unsigned int ngpio;
|
||||
};
|
||||
|
||||
struct etraxfs_gpio_info {
|
||||
unsigned int num_ports;
|
||||
const struct etraxfs_gpio_port *ports;
|
||||
};
|
||||
|
||||
static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = {
|
||||
{
|
||||
.label = "A",
|
||||
.ngpio = 8,
|
||||
.oe = ETRAX_FS_rw_pa_oe,
|
||||
.dout = ETRAX_FS_rw_pa_dout,
|
||||
.din = ETRAX_FS_r_pa_din,
|
||||
},
|
||||
{
|
||||
.label = "B",
|
||||
.ngpio = 18,
|
||||
.oe = ETRAX_FS_rw_pb_oe,
|
||||
.dout = ETRAX_FS_rw_pb_dout,
|
||||
.din = ETRAX_FS_r_pb_din,
|
||||
},
|
||||
{
|
||||
.label = "C",
|
||||
.ngpio = 18,
|
||||
.oe = ETRAX_FS_rw_pc_oe,
|
||||
.dout = ETRAX_FS_rw_pc_dout,
|
||||
.din = ETRAX_FS_r_pc_din,
|
||||
},
|
||||
{
|
||||
.label = "D",
|
||||
.ngpio = 18,
|
||||
.oe = ETRAX_FS_rw_pd_oe,
|
||||
.dout = ETRAX_FS_rw_pd_dout,
|
||||
.din = ETRAX_FS_r_pd_din,
|
||||
},
|
||||
{
|
||||
.label = "E",
|
||||
.ngpio = 18,
|
||||
.oe = ETRAX_FS_rw_pe_oe,
|
||||
.dout = ETRAX_FS_rw_pe_dout,
|
||||
.din = ETRAX_FS_r_pe_din,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = {
|
||||
.num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports),
|
||||
.ports = etraxfs_gpio_etraxfs_ports,
|
||||
};
|
||||
|
||||
static int etraxfs_gpio_of_xlate(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec,
|
||||
u32 *flags)
|
||||
{
|
||||
/*
|
||||
* Port numbers are A to E, and the properties are integers, so we
|
||||
* specify them as 0xA - 0xE.
|
||||
*/
|
||||
if (gc->label[0] - 'A' + 0xA != gpiospec->args[2])
|
||||
return -EINVAL;
|
||||
|
||||
return of_gpio_simple_xlate(gc, gpiospec, flags);
|
||||
}
|
||||
|
||||
static const struct of_device_id etraxfs_gpio_of_table[] = {
|
||||
{
|
||||
.compatible = "axis,etraxfs-gio",
|
||||
.data = &etraxfs_gpio_etraxfs,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static int etraxfs_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct etraxfs_gpio_info *info;
|
||||
const struct of_device_id *match;
|
||||
struct bgpio_chip *chips;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
regs = devm_ioremap_resource(dev, res);
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_node(etraxfs_gpio_of_table, dev->of_node);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
info = match->data;
|
||||
|
||||
chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL);
|
||||
if (!chips)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < info->num_ports; i++) {
|
||||
struct bgpio_chip *bgc = &chips[i];
|
||||
const struct etraxfs_gpio_port *port = &info->ports[i];
|
||||
|
||||
ret = bgpio_init(bgc, dev, 4,
|
||||
regs + port->din, /* dat */
|
||||
regs + port->dout, /* set */
|
||||
NULL, /* clr */
|
||||
regs + port->oe, /* dirout */
|
||||
NULL, /* dirin */
|
||||
BGPIOF_UNREADABLE_REG_SET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bgc->gc.ngpio = port->ngpio;
|
||||
bgc->gc.label = port->label;
|
||||
|
||||
bgc->gc.of_node = dev->of_node;
|
||||
bgc->gc.of_gpio_n_cells = 3;
|
||||
bgc->gc.of_xlate = etraxfs_gpio_of_xlate;
|
||||
|
||||
ret = gpiochip_add(&bgc->gc);
|
||||
if (ret)
|
||||
dev_err(dev, "Unable to register port %s\n",
|
||||
bgc->gc.label);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver etraxfs_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "etraxfs-gpio",
|
||||
.of_match_table = of_match_ptr(etraxfs_gpio_of_table),
|
||||
},
|
||||
.probe = etraxfs_gpio_probe,
|
||||
};
|
||||
|
||||
static int __init etraxfs_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&etraxfs_gpio_driver);
|
||||
}
|
||||
|
||||
device_initcall(etraxfs_gpio_init);
|
@ -172,7 +172,7 @@ static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
|
||||
};
|
||||
|
||||
static struct f7188x_gpio_bank f71882_gpio_bank[] = {
|
||||
F7188X_GPIO_BANK(0 , 8, 0xF0),
|
||||
F7188X_GPIO_BANK(0, 8, 0xF0),
|
||||
F7188X_GPIO_BANK(10, 8, 0xE0),
|
||||
F7188X_GPIO_BANK(20, 8, 0xD0),
|
||||
F7188X_GPIO_BANK(30, 4, 0xC0),
|
||||
@ -180,7 +180,7 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = {
|
||||
};
|
||||
|
||||
static struct f7188x_gpio_bank f71889_gpio_bank[] = {
|
||||
F7188X_GPIO_BANK(0 , 7, 0xF0),
|
||||
F7188X_GPIO_BANK(0, 7, 0xF0),
|
||||
F7188X_GPIO_BANK(10, 7, 0xE0),
|
||||
F7188X_GPIO_BANK(20, 8, 0xD0),
|
||||
F7188X_GPIO_BANK(30, 8, 0xC0),
|
||||
|
@ -135,6 +135,17 @@ static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
|
||||
return 1 << (bgc->bits - 1 - pin);
|
||||
}
|
||||
|
||||
static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
||||
unsigned long pinmask = bgc->pin2mask(bgc, gpio);
|
||||
|
||||
if (bgc->dir & pinmask)
|
||||
return bgc->read_reg(bgc->reg_set) & pinmask;
|
||||
else
|
||||
return bgc->read_reg(bgc->reg_dat) & pinmask;
|
||||
}
|
||||
|
||||
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
||||
@ -416,7 +427,8 @@ static int bgpio_setup_accessors(struct device *dev,
|
||||
static int bgpio_setup_io(struct bgpio_chip *bgc,
|
||||
void __iomem *dat,
|
||||
void __iomem *set,
|
||||
void __iomem *clr)
|
||||
void __iomem *clr,
|
||||
unsigned long flags)
|
||||
{
|
||||
|
||||
bgc->reg_dat = dat;
|
||||
@ -437,7 +449,11 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
|
||||
bgc->gc.set_multiple = bgpio_set_multiple;
|
||||
}
|
||||
|
||||
bgc->gc.get = bgpio_get;
|
||||
if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
|
||||
(flags & BGPIOF_READ_OUTPUT_REG_SET))
|
||||
bgc->gc.get = bgpio_get_set;
|
||||
else
|
||||
bgc->gc.get = bgpio_get;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -500,7 +516,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
|
||||
bgc->gc.ngpio = bgc->bits;
|
||||
bgc->gc.request = bgpio_request;
|
||||
|
||||
ret = bgpio_setup_io(bgc, dat, set, clr);
|
||||
ret = bgpio_setup_io(bgc, dat, set, clr, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -123,7 +123,7 @@ static void it8761e_gpio_set(struct gpio_chip *gc,
|
||||
|
||||
curr_vals = inb(reg);
|
||||
if (val)
|
||||
outb(curr_vals | (1 << bit) , reg);
|
||||
outb(curr_vals | (1 << bit), reg);
|
||||
else
|
||||
outb(curr_vals & ~(1 << bit), reg);
|
||||
|
||||
|
180
drivers/gpio/gpio-lpc18xx.c
Normal file
180
drivers/gpio/gpio-lpc18xx.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* GPIO driver for NXP LPC18xx/43xx.
|
||||
*
|
||||
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* LPC18xx GPIO register offsets */
|
||||
#define LPC18XX_REG_DIR(n) (0x2000 + n * sizeof(u32))
|
||||
|
||||
#define LPC18XX_MAX_PORTS 8
|
||||
#define LPC18XX_PINS_PER_PORT 32
|
||||
|
||||
struct lpc18xx_gpio_chip {
|
||||
struct gpio_chip gpio;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static inline struct lpc18xx_gpio_chip *to_lpc18xx_gpio(struct gpio_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct lpc18xx_gpio_chip, gpio);
|
||||
}
|
||||
|
||||
static int lpc18xx_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(offset);
|
||||
}
|
||||
|
||||
static void lpc18xx_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(offset);
|
||||
}
|
||||
|
||||
static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
|
||||
writeb(value ? 1 : 0, gc->base + offset);
|
||||
}
|
||||
|
||||
static int lpc18xx_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
|
||||
return !!readb(gc->base + offset);
|
||||
}
|
||||
|
||||
static int lpc18xx_gpio_direction(struct gpio_chip *chip, unsigned offset,
|
||||
bool out)
|
||||
{
|
||||
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
|
||||
unsigned long flags;
|
||||
u32 port, pin, dir;
|
||||
|
||||
port = offset / LPC18XX_PINS_PER_PORT;
|
||||
pin = offset % LPC18XX_PINS_PER_PORT;
|
||||
|
||||
spin_lock_irqsave(&gc->lock, flags);
|
||||
dir = readl(gc->base + LPC18XX_REG_DIR(port));
|
||||
if (out)
|
||||
dir |= BIT(pin);
|
||||
else
|
||||
dir &= ~BIT(pin);
|
||||
writel(dir, gc->base + LPC18XX_REG_DIR(port));
|
||||
spin_unlock_irqrestore(&gc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc18xx_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
return lpc18xx_gpio_direction(chip, offset, false);
|
||||
}
|
||||
|
||||
static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
lpc18xx_gpio_set(chip, offset, value);
|
||||
return lpc18xx_gpio_direction(chip, offset, true);
|
||||
}
|
||||
|
||||
static struct gpio_chip lpc18xx_chip = {
|
||||
.label = "lpc18xx/43xx-gpio",
|
||||
.request = lpc18xx_gpio_request,
|
||||
.free = lpc18xx_gpio_free,
|
||||
.direction_input = lpc18xx_gpio_direction_input,
|
||||
.direction_output = lpc18xx_gpio_direction_output,
|
||||
.set = lpc18xx_gpio_set,
|
||||
.get = lpc18xx_gpio_get,
|
||||
.ngpio = LPC18XX_MAX_PORTS * LPC18XX_PINS_PER_PORT,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lpc18xx_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_gpio_chip *gc;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
|
||||
gc->gpio = lpc18xx_chip;
|
||||
platform_set_drvdata(pdev, gc);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
gc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(gc->base))
|
||||
return PTR_ERR(gc->base);
|
||||
|
||||
gc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(gc->clk)) {
|
||||
dev_err(&pdev->dev, "input clock not found\n");
|
||||
return PTR_ERR(gc->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(gc->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_init(&gc->lock);
|
||||
|
||||
gc->gpio.dev = &pdev->dev;
|
||||
|
||||
ret = gpiochip_add(&gc->gpio);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add gpio chip\n");
|
||||
clk_disable_unprepare(gc->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc18xx_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&gc->gpio);
|
||||
clk_disable_unprepare(gc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc18xx_gpio_match[] = {
|
||||
{ .compatible = "nxp,lpc1850-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match);
|
||||
|
||||
static struct platform_driver lpc18xx_gpio_driver = {
|
||||
.probe = lpc18xx_gpio_probe,
|
||||
.remove = lpc18xx_gpio_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-gpio",
|
||||
.of_match_table = lpc18xx_gpio_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpc18xx_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
|
||||
MODULE_DESCRIPTION("GPIO driver for LPC18xx/43xx");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -72,7 +72,7 @@ struct lp_gpio {
|
||||
*
|
||||
* per gpio specific registers consist of two 32bit registers per gpio
|
||||
* (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of
|
||||
* 188 config registes.
|
||||
* 188 config registers.
|
||||
*
|
||||
* A simplified view of the register layout look like this:
|
||||
*
|
||||
|
@ -429,6 +429,14 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max732x_irq_set_wake(struct irq_data *data, unsigned int on)
|
||||
{
|
||||
struct max732x_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
|
||||
irq_set_irq_wake(chip->client->irq, on);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip max732x_irq_chip = {
|
||||
.name = "max732x",
|
||||
.irq_mask = max732x_irq_mask,
|
||||
@ -436,6 +444,7 @@ static struct irq_chip max732x_irq_chip = {
|
||||
.irq_bus_lock = max732x_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = max732x_irq_bus_sync_unlock,
|
||||
.irq_set_type = max732x_irq_set_type,
|
||||
.irq_set_wake = max732x_irq_set_wake,
|
||||
};
|
||||
|
||||
static uint8_t max732x_irq_pending(struct max732x_chip *chip)
|
||||
@ -507,12 +516,10 @@ static int max732x_irq_setup(struct max732x_chip *chip,
|
||||
chip->irq_features = has_irq;
|
||||
mutex_init(&chip->irq_lock);
|
||||
|
||||
ret = devm_request_threaded_irq(&client->dev,
|
||||
client->irq,
|
||||
NULL,
|
||||
max732x_irq_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
dev_name(&client->dev), chip);
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, max732x_irq_handler, IRQF_ONESHOT |
|
||||
IRQF_TRIGGER_FALLING | IRQF_SHARED,
|
||||
dev_name(&client->dev), chip);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to request irq %d\n",
|
||||
client->irq);
|
||||
@ -521,7 +528,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
|
||||
ret = gpiochip_irqchip_add(&chip->gpio_chip,
|
||||
&max732x_irq_chip,
|
||||
irq_base,
|
||||
handle_edge_irq,
|
||||
handle_simple_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
|
@ -39,17 +39,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
pinctrl_free_gpio(offset);
|
||||
}
|
||||
|
||||
static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct bgpio_chip *bgc = to_bgpio_chip(chip);
|
||||
u32 ret = bgc->read_reg(bgc->reg_dir);
|
||||
|
||||
if (ret & BIT(offset))
|
||||
return !!(bgc->read_reg(bgc->reg_set) & BIT(offset));
|
||||
else
|
||||
return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset));
|
||||
}
|
||||
|
||||
static int moxart_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -68,8 +57,9 @@ static int moxart_gpio_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN,
|
||||
base + GPIO_DATA_OUT, NULL,
|
||||
base + GPIO_PIN_DIRECTION, NULL, 0);
|
||||
base + GPIO_DATA_OUT, NULL,
|
||||
base + GPIO_PIN_DIRECTION, NULL,
|
||||
BGPIOF_READ_OUTPUT_REG_SET);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "bgpio_init failed\n");
|
||||
return ret;
|
||||
@ -78,7 +68,6 @@ static int moxart_gpio_probe(struct platform_device *pdev)
|
||||
bgc->gc.label = "moxart-gpio";
|
||||
bgc->gc.request = moxart_gpio_request;
|
||||
bgc->gc.free = moxart_gpio_free;
|
||||
bgc->gc.get = moxart_gpio_get;
|
||||
bgc->data = bgc->read_reg(bgc->reg_set);
|
||||
bgc->gc.base = 0;
|
||||
bgc->gc.ngpio = 32;
|
||||
|
@ -131,7 +131,7 @@ static struct mxc_gpio_hwdata *mxc_gpio_hwdata;
|
||||
#define GPIO_INT_FALL_EDGE (mxc_gpio_hwdata->fall_edge)
|
||||
#define GPIO_INT_BOTH_EDGES 0x4
|
||||
|
||||
static struct platform_device_id mxc_gpio_devtype[] = {
|
||||
static const struct platform_device_id mxc_gpio_devtype[] = {
|
||||
{
|
||||
.name = "imx1-gpio",
|
||||
.driver_data = IMX1_GPIO,
|
||||
@ -449,7 +449,8 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
||||
err = bgpio_init(&port->bgc, &pdev->dev, 4,
|
||||
port->base + GPIO_PSR,
|
||||
port->base + GPIO_DR, NULL,
|
||||
port->base + GPIO_GDIR, NULL, 0);
|
||||
port->base + GPIO_GDIR, NULL,
|
||||
BGPIOF_READ_OUTPUT_REG_SET);
|
||||
if (err)
|
||||
goto out_bgio;
|
||||
|
||||
|
@ -239,7 +239,7 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
|
||||
return !(dir & mask);
|
||||
}
|
||||
|
||||
static struct platform_device_id mxs_gpio_ids[] = {
|
||||
static const struct platform_device_id mxs_gpio_ids[] = {
|
||||
{
|
||||
.name = "imx23-gpio",
|
||||
.driver_data = IMX23_GPIO,
|
||||
|
@ -488,9 +488,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
unsigned long flags;
|
||||
unsigned offset = d->hwirq;
|
||||
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
if (type & ~IRQ_TYPE_SENSE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
@ -498,12 +495,18 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
retval = omap_set_gpio_triggering(bank, offset, type);
|
||||
if (retval)
|
||||
goto error;
|
||||
omap_gpio_init_irq(bank, offset);
|
||||
if (!omap_gpio_is_input(bank, offset)) {
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
return -EINVAL;
|
||||
retval = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
@ -512,6 +515,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
__irq_set_handler_locked(d->irq, handle_edge_irq);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_put(bank->dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -638,15 +646,6 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset)
|
||||
{
|
||||
omap_set_gpio_direction(bank, offset, 1);
|
||||
omap_set_gpio_irqenable(bank, offset, 0);
|
||||
omap_clear_gpio_irqstatus(bank, offset);
|
||||
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
|
||||
omap_clear_gpio_debounce(bank, offset);
|
||||
}
|
||||
|
||||
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
|
||||
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
@ -669,14 +668,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
/* Set trigger to none. You need to enable the desired trigger with
|
||||
* request_irq() or set_irq_type(). Only do this if the IRQ line has
|
||||
* not already been requested.
|
||||
*/
|
||||
if (!LINE_USED(bank->irq_usage, offset)) {
|
||||
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
|
||||
omap_enable_gpio_module(bank, offset);
|
||||
}
|
||||
omap_enable_gpio_module(bank, offset);
|
||||
bank->mod_usage |= BIT(offset);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
@ -690,8 +682,11 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
bank->mod_usage &= ~(BIT(offset));
|
||||
if (!LINE_USED(bank->irq_usage, offset)) {
|
||||
omap_set_gpio_direction(bank, offset, 1);
|
||||
omap_clear_gpio_debounce(bank, offset);
|
||||
}
|
||||
omap_disable_gpio_module(bank, offset);
|
||||
omap_reset_gpio(bank, offset);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
/*
|
||||
@ -795,11 +790,23 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
omap_gpio_init_irq(bank, offset);
|
||||
|
||||
if (!LINE_USED(bank->mod_usage, offset))
|
||||
omap_set_gpio_direction(bank, offset, 1);
|
||||
else if (!omap_gpio_is_input(bank, offset))
|
||||
goto err;
|
||||
omap_enable_gpio_module(bank, offset);
|
||||
bank->irq_usage |= BIT(offset);
|
||||
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
omap_gpio_unmask_irq(d);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_put(bank->dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void omap_gpio_irq_shutdown(struct irq_data *d)
|
||||
@ -810,8 +817,12 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
|
||||
|
||||
spin_lock_irqsave(&bank->lock, flags);
|
||||
bank->irq_usage &= ~(BIT(offset));
|
||||
omap_set_gpio_irqenable(bank, offset, 0);
|
||||
omap_clear_gpio_irqstatus(bank, offset);
|
||||
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
|
||||
if (!LINE_USED(bank->mod_usage, offset))
|
||||
omap_clear_gpio_debounce(bank, offset);
|
||||
omap_disable_gpio_module(bank, offset);
|
||||
omap_reset_gpio(bank, offset);
|
||||
spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
/*
|
||||
@ -1233,6 +1244,17 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_bank *bank = platform_get_drvdata(pdev);
|
||||
|
||||
list_del(&bank->node);
|
||||
gpiochip_remove(&bank->chip);
|
||||
pm_runtime_disable(bank->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP2PLUS
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
@ -1418,6 +1440,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
|
||||
void omap2_gpio_prepare_for_idle(int pwr_mode)
|
||||
{
|
||||
struct gpio_bank *bank;
|
||||
@ -1443,6 +1466,7 @@ void omap2_gpio_resume_after_idle(void)
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PM)
|
||||
static void omap_gpio_init_context(struct gpio_bank *p)
|
||||
@ -1598,6 +1622,7 @@ MODULE_DEVICE_TABLE(of, omap_gpio_match);
|
||||
|
||||
static struct platform_driver omap_gpio_driver = {
|
||||
.probe = omap_gpio_probe,
|
||||
.remove = omap_gpio_remove,
|
||||
.driver = {
|
||||
.name = "omap_gpio",
|
||||
.pm = &gpio_pm_ops,
|
||||
@ -1615,3 +1640,13 @@ static int __init omap_gpio_drv_reg(void)
|
||||
return platform_driver_register(&omap_gpio_driver);
|
||||
}
|
||||
postcore_initcall(omap_gpio_drv_reg);
|
||||
|
||||
static void __exit omap_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&omap_gpio_driver);
|
||||
}
|
||||
module_exit(omap_gpio_exit);
|
||||
|
||||
MODULE_DESCRIPTION("omap gpio driver");
|
||||
MODULE_ALIAS("platform:gpio-omap");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -443,12 +443,13 @@ static struct irq_chip pca953x_irq_chip = {
|
||||
.irq_set_type = pca953x_irq_set_type,
|
||||
};
|
||||
|
||||
static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
||||
static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
||||
{
|
||||
u8 cur_stat[MAX_BANK];
|
||||
u8 old_stat[MAX_BANK];
|
||||
u8 pendings = 0;
|
||||
u8 trigger[MAX_BANK], triggers = 0;
|
||||
bool pending_seen = false;
|
||||
bool trigger_seen = false;
|
||||
u8 trigger[MAX_BANK];
|
||||
int ret, i, offset = 0;
|
||||
|
||||
switch (chip->chip_type) {
|
||||
@ -461,7 +462,7 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
||||
}
|
||||
ret = pca953x_read_regs(chip, offset, cur_stat);
|
||||
if (ret)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* Remove output pins from the equation */
|
||||
for (i = 0; i < NBANK(chip); i++)
|
||||
@ -471,11 +472,12 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
||||
|
||||
for (i = 0; i < NBANK(chip); i++) {
|
||||
trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
|
||||
triggers += trigger[i];
|
||||
if (trigger[i])
|
||||
trigger_seen = true;
|
||||
}
|
||||
|
||||
if (!triggers)
|
||||
return 0;
|
||||
if (!trigger_seen)
|
||||
return false;
|
||||
|
||||
memcpy(chip->irq_stat, cur_stat, NBANK(chip));
|
||||
|
||||
@ -483,10 +485,11 @@ static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
|
||||
pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
|
||||
(cur_stat[i] & chip->irq_trig_raise[i]);
|
||||
pending[i] &= trigger[i];
|
||||
pendings += pending[i];
|
||||
if (pending[i])
|
||||
pending_seen = true;
|
||||
}
|
||||
|
||||
return pendings;
|
||||
return pending_seen;
|
||||
}
|
||||
|
||||
static irqreturn_t pca953x_irq_handler(int irq, void *devid)
|
||||
@ -630,7 +633,7 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
|
||||
memset(val, 0, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_INVRT, val);
|
||||
|
||||
/* To enable register 6, 7 to controll pull up and pull down */
|
||||
/* To enable register 6, 7 to control pull up and pull down */
|
||||
memset(val, 0x02, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_BKEN, val);
|
||||
|
||||
|
@ -91,6 +91,8 @@ struct pcf857x {
|
||||
spinlock_t slock; /* protect irq demux */
|
||||
unsigned out; /* software latch */
|
||||
unsigned status; /* current status */
|
||||
unsigned int irq_parent;
|
||||
unsigned irq_enabled; /* enabled irqs */
|
||||
|
||||
int (*write)(struct i2c_client *client, unsigned data);
|
||||
int (*read)(struct i2c_client *client);
|
||||
@ -194,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
|
||||
* interrupt source, just to avoid bad irqs
|
||||
*/
|
||||
|
||||
change = (gpio->status ^ status);
|
||||
change = (gpio->status ^ status) & gpio->irq_enabled;
|
||||
for_each_set_bit(i, &change, gpio->chip.ngpio)
|
||||
handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
|
||||
gpio->status = status;
|
||||
@ -209,29 +211,62 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
|
||||
*/
|
||||
static void noop(struct irq_data *data) { }
|
||||
|
||||
static unsigned int noop_ret(struct irq_data *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
|
||||
{
|
||||
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
|
||||
|
||||
irq_set_irq_wake(gpio->client->irq, on);
|
||||
return 0;
|
||||
int error = 0;
|
||||
|
||||
if (gpio->irq_parent) {
|
||||
error = irq_set_irq_wake(gpio->irq_parent, on);
|
||||
if (error) {
|
||||
dev_dbg(&gpio->client->dev,
|
||||
"irq %u doesn't support irq_set_wake\n",
|
||||
gpio->irq_parent);
|
||||
gpio->irq_parent = 0;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void pcf857x_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
|
||||
|
||||
gpio->irq_enabled |= (1 << data->hwirq);
|
||||
}
|
||||
|
||||
static void pcf857x_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
|
||||
|
||||
gpio->irq_enabled &= ~(1 << data->hwirq);
|
||||
}
|
||||
|
||||
static void pcf857x_irq_bus_lock(struct irq_data *data)
|
||||
{
|
||||
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&gpio->lock);
|
||||
}
|
||||
|
||||
static void pcf857x_irq_bus_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_unlock(&gpio->lock);
|
||||
}
|
||||
|
||||
static struct irq_chip pcf857x_irq_chip = {
|
||||
.name = "pcf857x",
|
||||
.irq_startup = noop_ret,
|
||||
.irq_shutdown = noop,
|
||||
.irq_enable = noop,
|
||||
.irq_disable = noop,
|
||||
.irq_enable = pcf857x_irq_enable,
|
||||
.irq_disable = pcf857x_irq_disable,
|
||||
.irq_ack = noop,
|
||||
.irq_mask = noop,
|
||||
.irq_unmask = noop,
|
||||
.irq_set_wake = pcf857x_irq_set_wake,
|
||||
.irq_bus_lock = pcf857x_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -364,6 +399,7 @@ static int pcf857x_probe(struct i2c_client *client,
|
||||
|
||||
gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip,
|
||||
client->irq, NULL);
|
||||
gpio->irq_parent = client->irq;
|
||||
}
|
||||
|
||||
/* Let platform code set up the GPIOs and their users.
|
||||
|
@ -177,8 +177,17 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
|
||||
gpio_chip);
|
||||
int error;
|
||||
|
||||
irq_set_irq_wake(p->irq_parent, on);
|
||||
if (p->irq_parent) {
|
||||
error = irq_set_irq_wake(p->irq_parent, on);
|
||||
if (error) {
|
||||
dev_dbg(&p->pdev->dev,
|
||||
"irq %u doesn't support irq_set_wake\n",
|
||||
p->irq_parent);
|
||||
p->irq_parent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!p->clk)
|
||||
return 0;
|
||||
|
@ -58,7 +58,7 @@
|
||||
#define XWAY_STP_ADSL_MASK 0x3
|
||||
|
||||
/* 2 groups of 3 bits can be driven by the phys */
|
||||
#define XWAY_STP_PHY_MASK 0x3
|
||||
#define XWAY_STP_PHY_MASK 0x7
|
||||
#define XWAY_STP_PHY1_SHIFT 27
|
||||
#define XWAY_STP_PHY2_SHIFT 15
|
||||
|
||||
@ -200,7 +200,7 @@ static int xway_stp_hw_init(struct xway_stp *chip)
|
||||
static int xway_stp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
const __be32 *shadow, *groups, *dsl, *phy;
|
||||
u32 shadow, groups, dsl, phy;
|
||||
struct xway_stp *chip;
|
||||
struct clk *clk;
|
||||
int ret = 0;
|
||||
@ -223,33 +223,28 @@ static int xway_stp_probe(struct platform_device *pdev)
|
||||
chip->gc.owner = THIS_MODULE;
|
||||
|
||||
/* store the shadow value if one was passed by the devicetree */
|
||||
shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL);
|
||||
if (shadow)
|
||||
chip->shadow = be32_to_cpu(*shadow);
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
|
||||
chip->shadow = shadow;
|
||||
|
||||
/* find out which gpio groups should be enabled */
|
||||
groups = of_get_property(pdev->dev.of_node, "lantiq,groups", NULL);
|
||||
if (groups)
|
||||
chip->groups = be32_to_cpu(*groups) & XWAY_STP_GROUP_MASK;
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,groups", &groups))
|
||||
chip->groups = groups & XWAY_STP_GROUP_MASK;
|
||||
else
|
||||
chip->groups = XWAY_STP_GROUP0;
|
||||
chip->gc.ngpio = fls(chip->groups) * 8;
|
||||
|
||||
/* find out which gpios are controlled by the dsl core */
|
||||
dsl = of_get_property(pdev->dev.of_node, "lantiq,dsl", NULL);
|
||||
if (dsl)
|
||||
chip->dsl = be32_to_cpu(*dsl) & XWAY_STP_ADSL_MASK;
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,dsl", &dsl))
|
||||
chip->dsl = dsl & XWAY_STP_ADSL_MASK;
|
||||
|
||||
/* find out which gpios are controlled by the phys */
|
||||
if (of_machine_is_compatible("lantiq,ar9") ||
|
||||
of_machine_is_compatible("lantiq,gr9") ||
|
||||
of_machine_is_compatible("lantiq,vr9")) {
|
||||
phy = of_get_property(pdev->dev.of_node, "lantiq,phy1", NULL);
|
||||
if (phy)
|
||||
chip->phy1 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK;
|
||||
phy = of_get_property(pdev->dev.of_node, "lantiq,phy2", NULL);
|
||||
if (phy)
|
||||
chip->phy2 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK;
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy1", &phy))
|
||||
chip->phy1 = phy & XWAY_STP_PHY_MASK;
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "lantiq,phy2", &phy))
|
||||
chip->phy2 = phy & XWAY_STP_PHY_MASK;
|
||||
}
|
||||
|
||||
/* check which edge trigger we should use, default to a falling edge */
|
||||
|
@ -292,7 +292,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev)
|
||||
BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0);
|
||||
kfree(tb10x_gpio->domain->gc);
|
||||
irq_domain_remove(tb10x_gpio->domain);
|
||||
free_irq(tb10x_gpio->irq, tb10x_gpio);
|
||||
}
|
||||
gpiochip_remove(&tb10x_gpio->gc);
|
||||
|
||||
|
@ -288,7 +288,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
|
||||
|
||||
/* if gpio is edge triggered, clear condition
|
||||
* before executing the hander so that we don't
|
||||
* before executing the handler so that we don't
|
||||
* miss edges
|
||||
*/
|
||||
if (lvl & (0x100 << pin)) {
|
||||
|
@ -440,7 +440,7 @@ static int ts5500_dio_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id ts5500_dio_ids[] = {
|
||||
static const struct platform_device_id ts5500_dio_ids[] = {
|
||||
{ "ts5500-dio1", TS5500_DIO1 },
|
||||
{ "ts5500-dio2", TS5500_DIO2 },
|
||||
{ "ts5500-dio-lcd", TS5500_LCD },
|
||||
|
@ -25,8 +25,11 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/basic_mmio_gpio.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
#define XGENE_MAX_GPIO_DS 22
|
||||
#define XGENE_MAX_GPIO_DS_IRQ 6
|
||||
|
||||
@ -112,7 +115,6 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
|
||||
GFP_KERNEL);
|
||||
if (!priv->irq)
|
||||
return -ENOMEM;
|
||||
memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS);
|
||||
|
||||
for (i = 0; i < priv->nirq; i++) {
|
||||
priv->irq[default_lines[i]] = platform_get_irq(pdev, i);
|
||||
@ -129,6 +131,11 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
|
||||
else
|
||||
dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n");
|
||||
|
||||
if (priv->nirq > 0) {
|
||||
/* Register interrupt handlers for gpio signaled acpi events */
|
||||
acpi_gpiochip_request_interrupts(&priv->bgc.gc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -136,6 +143,10 @@ static int xgene_gpio_sb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct xgene_gpio_sb *priv = platform_get_drvdata(pdev);
|
||||
|
||||
if (priv->nirq > 0) {
|
||||
acpi_gpiochip_free_interrupts(&priv->bgc.gc);
|
||||
}
|
||||
|
||||
return bgpio_remove(&priv->bgc);
|
||||
}
|
||||
|
||||
@ -145,10 +156,19 @@ static const struct of_device_id xgene_gpio_sb_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id xgene_gpio_sb_acpi_match[] = {
|
||||
{"APMC0D15", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, xgene_gpio_sb_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver xgene_gpio_sb_driver = {
|
||||
.driver = {
|
||||
.name = "xgene-gpio-sb",
|
||||
.of_match_table = xgene_gpio_sb_of_match,
|
||||
.acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match),
|
||||
},
|
||||
.probe = xgene_gpio_sb_probe,
|
||||
.remove = xgene_gpio_sb_remove,
|
||||
|
@ -41,10 +41,10 @@
|
||||
/**
|
||||
* struct xgpio_instance - Stores information about GPIO device
|
||||
* @mmchip: OF GPIO chip for memory mapped banks
|
||||
* @gpio_width: GPIO width for every channel
|
||||
* @gpio_state: GPIO state shadow register
|
||||
* @gpio_dir: GPIO direction shadow register
|
||||
* @gpio_lock: Lock used for synchronization
|
||||
* @inited: True if the port has been inited
|
||||
*/
|
||||
struct xgpio_instance {
|
||||
struct of_mm_gpio_chip mmchip;
|
||||
@ -231,6 +231,8 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
|
||||
* @pdev: pointer to the platform device
|
||||
*
|
||||
* This function remove gpiochips and frees all the allocated resources.
|
||||
*
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int xgpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
427
drivers/gpio/gpio-xlp.c
Normal file
427
drivers/gpio/gpio-xlp.c
Normal file
@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2015 Broadcom Corporation
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
/*
|
||||
* XLP GPIO has multiple 32 bit registers for each feature where each register
|
||||
* controls 32 pins. So, pins up to 64 require 2 32-bit registers and up to 96
|
||||
* require 3 32-bit registers for each feature.
|
||||
* Here we only define offset of the first register for each feature. Offset of
|
||||
* the registers for pins greater than 32 can be calculated as following(Use
|
||||
* GPIO_INT_STAT as example):
|
||||
*
|
||||
* offset = (gpio / XLP_GPIO_REGSZ) * 4;
|
||||
* reg_addr = addr + offset;
|
||||
*
|
||||
* where addr is base address of the that feature register and gpio is the pin.
|
||||
*/
|
||||
#define GPIO_OUTPUT_EN 0x00
|
||||
#define GPIO_PADDRV 0x08
|
||||
#define GPIO_INT_EN00 0x18
|
||||
#define GPIO_INT_EN10 0x20
|
||||
#define GPIO_INT_EN20 0x28
|
||||
#define GPIO_INT_EN30 0x30
|
||||
#define GPIO_INT_POL 0x38
|
||||
#define GPIO_INT_TYPE 0x40
|
||||
#define GPIO_INT_STAT 0x48
|
||||
|
||||
#define GPIO_9XX_BYTESWAP 0X00
|
||||
#define GPIO_9XX_CTRL 0X04
|
||||
#define GPIO_9XX_OUTPUT_EN 0x14
|
||||
#define GPIO_9XX_PADDRV 0x24
|
||||
/*
|
||||
* Only for 4 interrupt enable reg are defined for now,
|
||||
* total reg available are 12.
|
||||
*/
|
||||
#define GPIO_9XX_INT_EN00 0x44
|
||||
#define GPIO_9XX_INT_EN10 0x54
|
||||
#define GPIO_9XX_INT_EN20 0x64
|
||||
#define GPIO_9XX_INT_EN30 0x74
|
||||
#define GPIO_9XX_INT_POL 0x104
|
||||
#define GPIO_9XX_INT_TYPE 0x114
|
||||
#define GPIO_9XX_INT_STAT 0x124
|
||||
|
||||
#define GPIO_3XX_INT_EN00 0x18
|
||||
#define GPIO_3XX_INT_EN10 0x20
|
||||
#define GPIO_3XX_INT_EN20 0x28
|
||||
#define GPIO_3XX_INT_EN30 0x30
|
||||
#define GPIO_3XX_INT_POL 0x78
|
||||
#define GPIO_3XX_INT_TYPE 0x80
|
||||
#define GPIO_3XX_INT_STAT 0x88
|
||||
|
||||
/* Interrupt type register mask */
|
||||
#define XLP_GPIO_IRQ_TYPE_LVL 0x0
|
||||
#define XLP_GPIO_IRQ_TYPE_EDGE 0x1
|
||||
|
||||
/* Interrupt polarity register mask */
|
||||
#define XLP_GPIO_IRQ_POL_HIGH 0x0
|
||||
#define XLP_GPIO_IRQ_POL_LOW 0x1
|
||||
|
||||
#define XLP_GPIO_REGSZ 32
|
||||
#define XLP_GPIO_IRQ_BASE 768
|
||||
#define XLP_MAX_NR_GPIO 96
|
||||
|
||||
/* XLP variants supported by this driver */
|
||||
enum {
|
||||
XLP_GPIO_VARIANT_XLP832 = 1,
|
||||
XLP_GPIO_VARIANT_XLP316,
|
||||
XLP_GPIO_VARIANT_XLP208,
|
||||
XLP_GPIO_VARIANT_XLP980,
|
||||
XLP_GPIO_VARIANT_XLP532
|
||||
};
|
||||
|
||||
struct xlp_gpio_priv {
|
||||
struct gpio_chip chip;
|
||||
DECLARE_BITMAP(gpio_enabled_mask, XLP_MAX_NR_GPIO);
|
||||
void __iomem *gpio_intr_en; /* pointer to first intr enable reg */
|
||||
void __iomem *gpio_intr_stat; /* pointer to first intr status reg */
|
||||
void __iomem *gpio_intr_type; /* pointer to first intr type reg */
|
||||
void __iomem *gpio_intr_pol; /* pointer to first intr polarity reg */
|
||||
void __iomem *gpio_out_en; /* pointer to first output enable reg */
|
||||
void __iomem *gpio_paddrv; /* pointer to first pad drive reg */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static struct xlp_gpio_priv *gpio_chip_to_xlp_priv(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct xlp_gpio_priv, chip);
|
||||
}
|
||||
|
||||
static int xlp_gpio_get_reg(void __iomem *addr, unsigned gpio)
|
||||
{
|
||||
u32 pos, regset;
|
||||
|
||||
pos = gpio % XLP_GPIO_REGSZ;
|
||||
regset = (gpio / XLP_GPIO_REGSZ) * 4;
|
||||
return !!(readl(addr + regset) & BIT(pos));
|
||||
}
|
||||
|
||||
static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state)
|
||||
{
|
||||
u32 value, pos, regset;
|
||||
|
||||
pos = gpio % XLP_GPIO_REGSZ;
|
||||
regset = (gpio / XLP_GPIO_REGSZ) * 4;
|
||||
value = readl(addr + regset);
|
||||
|
||||
if (state)
|
||||
value |= BIT(pos);
|
||||
else
|
||||
value &= ~BIT(pos);
|
||||
|
||||
writel(value, addr + regset);
|
||||
}
|
||||
|
||||
static void xlp_gpio_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
|
||||
__clear_bit(d->hwirq, priv->gpio_enabled_mask);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static void xlp_gpio_irq_mask_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
|
||||
xlp_gpio_set_reg(priv->gpio_intr_stat, d->hwirq, 0x1);
|
||||
__clear_bit(d->hwirq, priv->gpio_enabled_mask);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static void xlp_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x1);
|
||||
__set_bit(d->hwirq, priv->gpio_enabled_mask);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
}
|
||||
|
||||
static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
int pol, irq_type;
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
|
||||
pol = XLP_GPIO_IRQ_POL_HIGH;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
|
||||
pol = XLP_GPIO_IRQ_POL_LOW;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
irq_type = XLP_GPIO_IRQ_TYPE_LVL;
|
||||
pol = XLP_GPIO_IRQ_POL_HIGH;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
irq_type = XLP_GPIO_IRQ_TYPE_LVL;
|
||||
pol = XLP_GPIO_IRQ_POL_LOW;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
xlp_gpio_set_reg(priv->gpio_intr_type, d->hwirq, irq_type);
|
||||
xlp_gpio_set_reg(priv->gpio_intr_pol, d->hwirq, pol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip xlp_gpio_irq_chip = {
|
||||
.name = "XLP-GPIO",
|
||||
.irq_mask_ack = xlp_gpio_irq_mask_ack,
|
||||
.irq_disable = xlp_gpio_irq_disable,
|
||||
.irq_set_type = xlp_gpio_set_irq_type,
|
||||
.irq_unmask = xlp_gpio_irq_unmask,
|
||||
.flags = IRQCHIP_ONESHOT_SAFE,
|
||||
};
|
||||
|
||||
static irqreturn_t xlp_gpio_generic_handler(int irq, void *data)
|
||||
{
|
||||
struct xlp_gpio_priv *priv = data;
|
||||
int gpio, regoff;
|
||||
u32 gpio_stat;
|
||||
|
||||
regoff = -1;
|
||||
gpio_stat = 0;
|
||||
for_each_set_bit(gpio, priv->gpio_enabled_mask, XLP_MAX_NR_GPIO) {
|
||||
if (regoff != gpio / XLP_GPIO_REGSZ) {
|
||||
regoff = gpio / XLP_GPIO_REGSZ;
|
||||
gpio_stat = readl(priv->gpio_intr_stat + regoff * 4);
|
||||
}
|
||||
if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
|
||||
generic_handle_irq(irq_find_mapping(
|
||||
priv->chip.irqdomain, gpio));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
|
||||
{
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
|
||||
BUG_ON(gpio >= gc->ngpio);
|
||||
xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio)
|
||||
{
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
|
||||
BUG_ON(gpio >= gc->ngpio);
|
||||
xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio)
|
||||
{
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
|
||||
BUG_ON(gpio >= gc->ngpio);
|
||||
return xlp_gpio_get_reg(priv->gpio_paddrv, gpio);
|
||||
}
|
||||
|
||||
static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state)
|
||||
{
|
||||
struct xlp_gpio_priv *priv = gpio_chip_to_xlp_priv(gc);
|
||||
|
||||
BUG_ON(gpio >= gc->ngpio);
|
||||
xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state);
|
||||
}
|
||||
|
||||
static const struct of_device_id xlp_gpio_of_ids[] = {
|
||||
{
|
||||
.compatible = "netlogic,xlp832-gpio",
|
||||
.data = (void *)XLP_GPIO_VARIANT_XLP832,
|
||||
},
|
||||
{
|
||||
.compatible = "netlogic,xlp316-gpio",
|
||||
.data = (void *)XLP_GPIO_VARIANT_XLP316,
|
||||
},
|
||||
{
|
||||
.compatible = "netlogic,xlp208-gpio",
|
||||
.data = (void *)XLP_GPIO_VARIANT_XLP208,
|
||||
},
|
||||
{
|
||||
.compatible = "netlogic,xlp980-gpio",
|
||||
.data = (void *)XLP_GPIO_VARIANT_XLP980,
|
||||
},
|
||||
{
|
||||
.compatible = "netlogic,xlp532-gpio",
|
||||
.data = (void *)XLP_GPIO_VARIANT_XLP532,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
|
||||
|
||||
static int xlp_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_chip *gc;
|
||||
struct resource *iores;
|
||||
struct xlp_gpio_priv *priv;
|
||||
const struct of_device_id *of_id;
|
||||
void __iomem *gpio_base;
|
||||
int irq_base, irq, err;
|
||||
int ngpio;
|
||||
u32 soc_type;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!iores)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
gpio_base = devm_ioremap_resource(&pdev->dev, iores);
|
||||
if (IS_ERR(gpio_base))
|
||||
return PTR_ERR(gpio_base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
of_id = of_match_device(xlp_gpio_of_ids, &pdev->dev);
|
||||
if (!of_id) {
|
||||
dev_err(&pdev->dev, "Failed to get soc type!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
soc_type = (uintptr_t) of_id->data;
|
||||
|
||||
switch (soc_type) {
|
||||
case XLP_GPIO_VARIANT_XLP832:
|
||||
priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
|
||||
priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
|
||||
priv->gpio_intr_stat = gpio_base + GPIO_INT_STAT;
|
||||
priv->gpio_intr_type = gpio_base + GPIO_INT_TYPE;
|
||||
priv->gpio_intr_pol = gpio_base + GPIO_INT_POL;
|
||||
priv->gpio_intr_en = gpio_base + GPIO_INT_EN00;
|
||||
ngpio = 41;
|
||||
break;
|
||||
case XLP_GPIO_VARIANT_XLP208:
|
||||
case XLP_GPIO_VARIANT_XLP316:
|
||||
priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
|
||||
priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
|
||||
priv->gpio_intr_stat = gpio_base + GPIO_3XX_INT_STAT;
|
||||
priv->gpio_intr_type = gpio_base + GPIO_3XX_INT_TYPE;
|
||||
priv->gpio_intr_pol = gpio_base + GPIO_3XX_INT_POL;
|
||||
priv->gpio_intr_en = gpio_base + GPIO_3XX_INT_EN00;
|
||||
|
||||
ngpio = (soc_type == XLP_GPIO_VARIANT_XLP208) ? 42 : 57;
|
||||
break;
|
||||
case XLP_GPIO_VARIANT_XLP980:
|
||||
case XLP_GPIO_VARIANT_XLP532:
|
||||
priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN;
|
||||
priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV;
|
||||
priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT;
|
||||
priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE;
|
||||
priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL;
|
||||
priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00;
|
||||
|
||||
ngpio = (soc_type == XLP_GPIO_VARIANT_XLP980) ? 66 : 67;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown Processor type!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bitmap_zero(priv->gpio_enabled_mask, XLP_MAX_NR_GPIO);
|
||||
|
||||
gc = &priv->chip;
|
||||
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->label = dev_name(&pdev->dev);
|
||||
gc->base = 0;
|
||||
gc->dev = &pdev->dev;
|
||||
gc->ngpio = ngpio;
|
||||
gc->of_node = pdev->dev.of_node;
|
||||
gc->direction_output = xlp_gpio_dir_output;
|
||||
gc->direction_input = xlp_gpio_dir_input;
|
||||
gc->set = xlp_gpio_set;
|
||||
gc->get = xlp_gpio_get;
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
err = devm_request_irq(&pdev->dev, irq, xlp_gpio_generic_handler,
|
||||
IRQ_TYPE_NONE, pdev->name, priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = gpiochip_add(gc);
|
||||
if (err < 0)
|
||||
goto out_free_desc;
|
||||
|
||||
err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base,
|
||||
handle_level_irq, IRQ_TYPE_NONE);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n");
|
||||
goto out_gpio_remove;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
|
||||
|
||||
return 0;
|
||||
|
||||
out_gpio_remove:
|
||||
gpiochip_remove(gc);
|
||||
out_free_desc:
|
||||
irq_free_descs(irq_base, gc->ngpio);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct platform_driver xlp_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "xlp-gpio",
|
||||
.of_match_table = xlp_gpio_of_ids,
|
||||
},
|
||||
.probe = xlp_gpio_probe,
|
||||
};
|
||||
module_platform_driver(xlp_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
|
||||
MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@broadcom.com>");
|
||||
MODULE_DESCRIPTION("Netlogic XLP GPIO Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -18,34 +18,47 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define DRIVER_NAME "zynq-gpio"
|
||||
|
||||
/* Maximum banks */
|
||||
#define ZYNQ_GPIO_MAX_BANK 4
|
||||
#define ZYNQMP_GPIO_MAX_BANK 6
|
||||
|
||||
#define ZYNQ_GPIO_BANK0_NGPIO 32
|
||||
#define ZYNQ_GPIO_BANK1_NGPIO 22
|
||||
#define ZYNQ_GPIO_BANK2_NGPIO 32
|
||||
#define ZYNQ_GPIO_BANK3_NGPIO 32
|
||||
|
||||
#define ZYNQ_GPIO_NR_GPIOS (ZYNQ_GPIO_BANK0_NGPIO + \
|
||||
ZYNQ_GPIO_BANK1_NGPIO + \
|
||||
ZYNQ_GPIO_BANK2_NGPIO + \
|
||||
ZYNQ_GPIO_BANK3_NGPIO)
|
||||
#define ZYNQMP_GPIO_BANK0_NGPIO 26
|
||||
#define ZYNQMP_GPIO_BANK1_NGPIO 26
|
||||
#define ZYNQMP_GPIO_BANK2_NGPIO 26
|
||||
#define ZYNQMP_GPIO_BANK3_NGPIO 32
|
||||
#define ZYNQMP_GPIO_BANK4_NGPIO 32
|
||||
#define ZYNQMP_GPIO_BANK5_NGPIO 32
|
||||
|
||||
#define ZYNQ_GPIO_BANK0_PIN_MIN 0
|
||||
#define ZYNQ_GPIO_BANK0_PIN_MAX (ZYNQ_GPIO_BANK0_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK0_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK1_PIN_MIN (ZYNQ_GPIO_BANK0_PIN_MAX + 1)
|
||||
#define ZYNQ_GPIO_BANK1_PIN_MAX (ZYNQ_GPIO_BANK1_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK1_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK2_PIN_MIN (ZYNQ_GPIO_BANK1_PIN_MAX + 1)
|
||||
#define ZYNQ_GPIO_BANK2_PIN_MAX (ZYNQ_GPIO_BANK2_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK2_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK3_PIN_MIN (ZYNQ_GPIO_BANK2_PIN_MAX + 1)
|
||||
#define ZYNQ_GPIO_BANK3_PIN_MAX (ZYNQ_GPIO_BANK3_PIN_MIN + \
|
||||
ZYNQ_GPIO_BANK3_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_NR_GPIOS 118
|
||||
#define ZYNQMP_GPIO_NR_GPIOS 174
|
||||
|
||||
#define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0
|
||||
#define ZYNQ_GPIO_BANK0_PIN_MAX(str) (ZYNQ_GPIO_BANK0_PIN_MIN(str) + \
|
||||
ZYNQ##str##_GPIO_BANK0_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1)
|
||||
#define ZYNQ_GPIO_BANK1_PIN_MAX(str) (ZYNQ_GPIO_BANK1_PIN_MIN(str) + \
|
||||
ZYNQ##str##_GPIO_BANK1_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK2_PIN_MIN(str) (ZYNQ_GPIO_BANK1_PIN_MAX(str) + 1)
|
||||
#define ZYNQ_GPIO_BANK2_PIN_MAX(str) (ZYNQ_GPIO_BANK2_PIN_MIN(str) + \
|
||||
ZYNQ##str##_GPIO_BANK2_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK3_PIN_MIN(str) (ZYNQ_GPIO_BANK2_PIN_MAX(str) + 1)
|
||||
#define ZYNQ_GPIO_BANK3_PIN_MAX(str) (ZYNQ_GPIO_BANK3_PIN_MIN(str) + \
|
||||
ZYNQ##str##_GPIO_BANK3_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK4_PIN_MIN(str) (ZYNQ_GPIO_BANK3_PIN_MAX(str) + 1)
|
||||
#define ZYNQ_GPIO_BANK4_PIN_MAX(str) (ZYNQ_GPIO_BANK4_PIN_MIN(str) + \
|
||||
ZYNQ##str##_GPIO_BANK4_NGPIO - 1)
|
||||
#define ZYNQ_GPIO_BANK5_PIN_MIN(str) (ZYNQ_GPIO_BANK4_PIN_MAX(str) + 1)
|
||||
#define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \
|
||||
ZYNQ##str##_GPIO_BANK5_NGPIO - 1)
|
||||
|
||||
|
||||
/* Register offsets for the GPIO device */
|
||||
@ -89,12 +102,30 @@
|
||||
* @base_addr: base address of the GPIO device
|
||||
* @clk: clock resource for this controller
|
||||
* @irq: interrupt for the GPIO device
|
||||
* @p_data: pointer to platform data
|
||||
*/
|
||||
struct zynq_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *base_addr;
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
const struct zynq_platform_data *p_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zynq_platform_data - zynq gpio platform data structure
|
||||
* @label: string to store in gpio->label
|
||||
* @ngpio: max number of gpio pins
|
||||
* @max_bank: maximum number of gpio banks
|
||||
* @bank_min: this array represents bank's min pin
|
||||
* @bank_max: this array represents bank's max pin
|
||||
*/
|
||||
struct zynq_platform_data {
|
||||
const char *label;
|
||||
u16 ngpio;
|
||||
int max_bank;
|
||||
int bank_min[ZYNQMP_GPIO_MAX_BANK];
|
||||
int bank_max[ZYNQMP_GPIO_MAX_BANK];
|
||||
};
|
||||
|
||||
static struct irq_chip zynq_gpio_level_irqchip;
|
||||
@ -112,39 +143,26 @@ static struct irq_chip zynq_gpio_edge_irqchip;
|
||||
*/
|
||||
static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
|
||||
unsigned int *bank_num,
|
||||
unsigned int *bank_pin_num)
|
||||
unsigned int *bank_pin_num,
|
||||
struct zynq_gpio *gpio)
|
||||
{
|
||||
switch (pin_num) {
|
||||
case ZYNQ_GPIO_BANK0_PIN_MIN ... ZYNQ_GPIO_BANK0_PIN_MAX:
|
||||
*bank_num = 0;
|
||||
*bank_pin_num = pin_num;
|
||||
break;
|
||||
case ZYNQ_GPIO_BANK1_PIN_MIN ... ZYNQ_GPIO_BANK1_PIN_MAX:
|
||||
*bank_num = 1;
|
||||
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK1_PIN_MIN;
|
||||
break;
|
||||
case ZYNQ_GPIO_BANK2_PIN_MIN ... ZYNQ_GPIO_BANK2_PIN_MAX:
|
||||
*bank_num = 2;
|
||||
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK2_PIN_MIN;
|
||||
break;
|
||||
case ZYNQ_GPIO_BANK3_PIN_MIN ... ZYNQ_GPIO_BANK3_PIN_MAX:
|
||||
*bank_num = 3;
|
||||
*bank_pin_num = pin_num - ZYNQ_GPIO_BANK3_PIN_MIN;
|
||||
break;
|
||||
default:
|
||||
WARN(true, "invalid GPIO pin number: %u", pin_num);
|
||||
*bank_num = 0;
|
||||
*bank_pin_num = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int bank;
|
||||
|
||||
static const unsigned int zynq_gpio_bank_offset[] = {
|
||||
ZYNQ_GPIO_BANK0_PIN_MIN,
|
||||
ZYNQ_GPIO_BANK1_PIN_MIN,
|
||||
ZYNQ_GPIO_BANK2_PIN_MIN,
|
||||
ZYNQ_GPIO_BANK3_PIN_MIN,
|
||||
};
|
||||
for (bank = 0; bank < gpio->p_data->max_bank; bank++) {
|
||||
if ((pin_num >= gpio->p_data->bank_min[bank]) &&
|
||||
(pin_num <= gpio->p_data->bank_max[bank])) {
|
||||
*bank_num = bank;
|
||||
*bank_pin_num = pin_num -
|
||||
gpio->p_data->bank_min[bank];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* default */
|
||||
WARN(true, "invalid GPIO pin number: %u", pin_num);
|
||||
*bank_num = 0;
|
||||
*bank_pin_num = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_get_value - Get the state of the specified pin of GPIO device
|
||||
@ -161,7 +179,7 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
|
||||
@ -185,7 +203,7 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
|
||||
unsigned int reg_offset, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) {
|
||||
/* only 16 data bits in bit maskable reg */
|
||||
@ -222,7 +240,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
/* bank 0 pins 7 and 8 are special and cannot be used as inputs */
|
||||
if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
|
||||
@ -255,7 +273,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
/* set the GPIO pin as output */
|
||||
reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
@ -286,7 +304,7 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data)
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
writel_relaxed(BIT(bank_pin_num),
|
||||
gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
||||
}
|
||||
@ -306,7 +324,7 @@ static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
writel_relaxed(BIT(bank_pin_num),
|
||||
gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num));
|
||||
}
|
||||
@ -325,7 +343,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data)
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
writel_relaxed(BIT(bank_pin_num),
|
||||
gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
|
||||
}
|
||||
@ -335,7 +353,7 @@ static void zynq_gpio_irq_ack(struct irq_data *irq_data)
|
||||
* @irq_data: irq data containing irq number of gpio pin for the interrupt
|
||||
* to enable
|
||||
*
|
||||
* Clears the INTSTS bit and unmasks the given interrrupt.
|
||||
* Clears the INTSTS bit and unmasks the given interrupt.
|
||||
*/
|
||||
static void zynq_gpio_irq_enable(struct irq_data *irq_data)
|
||||
{
|
||||
@ -375,7 +393,7 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num);
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
int_type = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
|
||||
@ -470,7 +488,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
|
||||
unsigned int bank_num,
|
||||
unsigned long pending)
|
||||
{
|
||||
unsigned int bank_offset = zynq_gpio_bank_offset[bank_num];
|
||||
unsigned int bank_offset = gpio->p_data->bank_min[bank_num];
|
||||
struct irq_domain *irqdomain = gpio->chip.irqdomain;
|
||||
int offset;
|
||||
|
||||
@ -505,7 +523,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++) {
|
||||
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) {
|
||||
int_sts = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
|
||||
int_enb = readl_relaxed(gpio->base_addr +
|
||||
@ -582,6 +600,46 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
|
||||
zynq_gpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct zynq_platform_data zynqmp_gpio_def = {
|
||||
.label = "zynqmp_gpio",
|
||||
.ngpio = ZYNQMP_GPIO_NR_GPIOS,
|
||||
.max_bank = ZYNQMP_GPIO_MAX_BANK,
|
||||
.bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP),
|
||||
.bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(MP),
|
||||
.bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(MP),
|
||||
.bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(MP),
|
||||
.bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(MP),
|
||||
.bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(MP),
|
||||
.bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(MP),
|
||||
.bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(MP),
|
||||
.bank_min[4] = ZYNQ_GPIO_BANK4_PIN_MIN(MP),
|
||||
.bank_max[4] = ZYNQ_GPIO_BANK4_PIN_MAX(MP),
|
||||
.bank_min[5] = ZYNQ_GPIO_BANK5_PIN_MIN(MP),
|
||||
.bank_max[5] = ZYNQ_GPIO_BANK5_PIN_MAX(MP),
|
||||
};
|
||||
|
||||
static const struct zynq_platform_data zynq_gpio_def = {
|
||||
.label = "zynq_gpio",
|
||||
.ngpio = ZYNQ_GPIO_NR_GPIOS,
|
||||
.max_bank = ZYNQ_GPIO_MAX_BANK,
|
||||
.bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
|
||||
.bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(),
|
||||
.bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(),
|
||||
.bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(),
|
||||
.bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(),
|
||||
.bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(),
|
||||
.bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(),
|
||||
.bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(),
|
||||
};
|
||||
|
||||
static const struct of_device_id zynq_gpio_of_match[] = {
|
||||
{ .compatible = "xlnx,zynq-gpio-1.0", .data = (void *)&zynq_gpio_def },
|
||||
{ .compatible = "xlnx,zynqmp-gpio-1.0",
|
||||
.data = (void *)&zynqmp_gpio_def },
|
||||
{ /* end of table */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
|
||||
|
||||
/**
|
||||
* zynq_gpio_probe - Initialization method for a zynq_gpio device
|
||||
* @pdev: platform device instance
|
||||
@ -599,11 +657,18 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
struct zynq_gpio *gpio;
|
||||
struct gpio_chip *chip;
|
||||
struct resource *res;
|
||||
const struct of_device_id *match;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "of_match_node() failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
gpio->p_data = match->data;
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@ -619,7 +684,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
/* configure the gpio chip */
|
||||
chip = &gpio->chip;
|
||||
chip->label = "zynq_gpio";
|
||||
chip->label = gpio->p_data->label;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->get = zynq_gpio_get_value;
|
||||
@ -629,7 +694,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
chip->direction_input = zynq_gpio_dir_in;
|
||||
chip->direction_output = zynq_gpio_dir_out;
|
||||
chip->base = -1;
|
||||
chip->ngpio = ZYNQ_GPIO_NR_GPIOS;
|
||||
chip->ngpio = gpio->p_data->ngpio;
|
||||
|
||||
/* Enable GPIO clock */
|
||||
gpio->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
@ -651,7 +716,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* disable interrupts for all banks */
|
||||
for (bank_num = 0; bank_num < ZYNQ_GPIO_MAX_BANK; bank_num++)
|
||||
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
|
||||
writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
|
||||
ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
|
||||
|
||||
@ -695,12 +760,6 @@ static int zynq_gpio_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id zynq_gpio_of_match[] = {
|
||||
{ .compatible = "xlnx,zynq-gpio-1.0", },
|
||||
{ /* end of table */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
|
||||
|
||||
static struct platform_driver zynq_gpio_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
|
@ -114,10 +114,11 @@ static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip,
|
||||
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
|
||||
* @pin: ACPI GPIO pin number (0-based, controller-relative)
|
||||
*
|
||||
* Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
|
||||
* error value
|
||||
* Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
|
||||
* error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO
|
||||
* controller does not have gpiochip registered at the moment. This is to
|
||||
* support probe deferral.
|
||||
*/
|
||||
|
||||
static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
@ -131,7 +132,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
||||
|
||||
chip = gpiochip_find(handle, acpi_gpiochip_find);
|
||||
if (!chip)
|
||||
return ERR_PTR(-ENODEV);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
|
||||
if (offset < 0)
|
||||
@ -307,6 +308,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
||||
acpi_walk_resources(handle, "_AEI",
|
||||
acpi_gpiochip_request_interrupt, acpi_gpio);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
|
||||
|
||||
/**
|
||||
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
|
||||
@ -346,6 +348,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
|
||||
kfree(event);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts);
|
||||
|
||||
int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
@ -514,6 +517,35 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
|
||||
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_dev_gpio_irq_get() - Find GpioInt and translate it to Linux IRQ number
|
||||
* @adev: pointer to a ACPI device to get IRQ from
|
||||
* @index: index of GpioInt resource (starting from %0)
|
||||
*
|
||||
* If the device has one or more GpioInt resources, this function can be
|
||||
* used to translate from the GPIO offset in the resource to the Linux IRQ
|
||||
* number.
|
||||
*
|
||||
* Return: Linux IRQ number (>%0) on success, negative errno on failure.
|
||||
*/
|
||||
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||
{
|
||||
int idx, i;
|
||||
|
||||
for (i = 0, idx = 0; idx <= index; i++) {
|
||||
struct acpi_gpio_info info;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
|
||||
if (IS_ERR(desc))
|
||||
break;
|
||||
if (info.gpioint && idx++ == index)
|
||||
return gpiod_to_irq(desc);
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
|
||||
|
||||
static acpi_status
|
||||
acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
||||
u32 bits, u64 *value, void *handler_context,
|
||||
|
@ -242,7 +242,7 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
{
|
||||
/*
|
||||
* We're discouraging gpio_cells < 2, since that way you'll have to
|
||||
* write your own xlate function (that will have to retrive the GPIO
|
||||
* write your own xlate function (that will have to retrieve the GPIO
|
||||
* number and the flags from a single gpio cell -- this is possible,
|
||||
* but not recommended).
|
||||
*/
|
||||
|
@ -6,14 +6,29 @@
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
static DEFINE_IDR(dirent_idr);
|
||||
#define GPIO_IRQF_TRIGGER_FALLING BIT(0)
|
||||
#define GPIO_IRQF_TRIGGER_RISING BIT(1)
|
||||
#define GPIO_IRQF_TRIGGER_BOTH (GPIO_IRQF_TRIGGER_FALLING | \
|
||||
GPIO_IRQF_TRIGGER_RISING)
|
||||
|
||||
struct gpiod_data {
|
||||
struct gpio_desc *desc;
|
||||
|
||||
/* lock protects against unexport_gpio() being called while
|
||||
* sysfs files are active.
|
||||
struct mutex mutex;
|
||||
struct kernfs_node *value_kn;
|
||||
int irq;
|
||||
unsigned char irq_flags;
|
||||
|
||||
bool direction_can_change;
|
||||
};
|
||||
|
||||
/*
|
||||
* Lock to serialise gpiod export and unexport, and prevent re-export of
|
||||
* gpiod whose chip is being unregistered.
|
||||
*/
|
||||
static DEFINE_MUTEX(sysfs_lock);
|
||||
|
||||
@ -38,38 +53,35 @@ static DEFINE_MUTEX(sysfs_lock);
|
||||
* /edge configuration
|
||||
*/
|
||||
|
||||
static ssize_t gpio_direction_show(struct device *dev,
|
||||
static ssize_t direction_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
status = -EIO;
|
||||
} else {
|
||||
gpiod_get_direction(desc);
|
||||
status = sprintf(buf, "%s\n",
|
||||
gpiod_get_direction(desc);
|
||||
status = sprintf(buf, "%s\n",
|
||||
test_bit(FLAG_IS_OUT, &desc->flags)
|
||||
? "out" : "in");
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_direction_store(struct device *dev,
|
||||
static ssize_t direction_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else if (sysfs_streq(buf, "high"))
|
||||
if (sysfs_streq(buf, "high"))
|
||||
status = gpiod_direction_output_raw(desc, 1);
|
||||
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
|
||||
status = gpiod_direction_output_raw(desc, 0);
|
||||
@ -78,43 +90,40 @@ static ssize_t gpio_direction_store(struct device *dev,
|
||||
else
|
||||
status = -EINVAL;
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status ? : size;
|
||||
}
|
||||
static DEVICE_ATTR_RW(direction);
|
||||
|
||||
static /* const */ DEVICE_ATTR(direction, 0644,
|
||||
gpio_direction_show, gpio_direction_store);
|
||||
|
||||
static ssize_t gpio_value_show(struct device *dev,
|
||||
static ssize_t value_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else
|
||||
status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
|
||||
status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_value_store(struct device *dev,
|
||||
static ssize_t value_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else if (!test_bit(FLAG_IS_OUT, &desc->flags))
|
||||
if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
|
||||
status = -EPERM;
|
||||
else {
|
||||
} else {
|
||||
long value;
|
||||
|
||||
status = kstrtol(buf, 0, &value);
|
||||
@ -124,172 +133,168 @@ static ssize_t gpio_value_store(struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(value, 0644,
|
||||
gpio_value_show, gpio_value_store);
|
||||
static DEVICE_ATTR_RW(value);
|
||||
|
||||
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
|
||||
{
|
||||
struct kernfs_node *value_sd = priv;
|
||||
struct gpiod_data *data = priv;
|
||||
|
||||
sysfs_notify_dirent(data->value_kn);
|
||||
|
||||
sysfs_notify_dirent(value_sd);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
|
||||
unsigned long gpio_flags)
|
||||
/* Caller holds gpiod-data mutex. */
|
||||
static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
|
||||
{
|
||||
struct kernfs_node *value_sd;
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
unsigned long irq_flags;
|
||||
int ret, irq, id;
|
||||
int ret;
|
||||
|
||||
if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
|
||||
return 0;
|
||||
|
||||
irq = gpiod_to_irq(desc);
|
||||
if (irq < 0)
|
||||
data->irq = gpiod_to_irq(desc);
|
||||
if (data->irq < 0)
|
||||
return -EIO;
|
||||
|
||||
id = desc->flags >> ID_SHIFT;
|
||||
value_sd = idr_find(&dirent_idr, id);
|
||||
if (value_sd)
|
||||
free_irq(irq, value_sd);
|
||||
|
||||
desc->flags &= ~GPIO_TRIGGER_MASK;
|
||||
|
||||
if (!gpio_flags) {
|
||||
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
|
||||
ret = 0;
|
||||
goto free_id;
|
||||
}
|
||||
data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value");
|
||||
if (!data->value_kn)
|
||||
return -ENODEV;
|
||||
|
||||
irq_flags = IRQF_SHARED;
|
||||
if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
|
||||
if (flags & GPIO_IRQF_TRIGGER_FALLING)
|
||||
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
|
||||
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
|
||||
if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
|
||||
if (flags & GPIO_IRQF_TRIGGER_RISING)
|
||||
irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
|
||||
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
|
||||
|
||||
if (!value_sd) {
|
||||
value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
|
||||
if (!value_sd) {
|
||||
ret = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto free_sd;
|
||||
id = ret;
|
||||
|
||||
desc->flags &= GPIO_FLAGS_MASK;
|
||||
desc->flags |= (unsigned long)id << ID_SHIFT;
|
||||
|
||||
if (desc->flags >> ID_SHIFT != id) {
|
||||
ret = -ERANGE;
|
||||
goto free_id;
|
||||
}
|
||||
}
|
||||
|
||||
ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
|
||||
"gpiolib", value_sd);
|
||||
if (ret < 0)
|
||||
goto free_id;
|
||||
|
||||
/*
|
||||
* FIXME: This should be done in the irq_request_resources callback
|
||||
* when the irq is requested, but a few drivers currently fail
|
||||
* to do so.
|
||||
*
|
||||
* Remove this redundant call (along with the corresponding
|
||||
* unlock) when those drivers have been fixed.
|
||||
*/
|
||||
ret = gpiochip_lock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
|
||||
if (ret < 0) {
|
||||
gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
|
||||
goto free_id;
|
||||
}
|
||||
if (ret < 0)
|
||||
goto err_put_kn;
|
||||
|
||||
ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags,
|
||||
"gpiolib", data);
|
||||
if (ret < 0)
|
||||
goto err_unlock;
|
||||
|
||||
data->irq_flags = flags;
|
||||
|
||||
desc->flags |= gpio_flags;
|
||||
return 0;
|
||||
|
||||
free_id:
|
||||
idr_remove(&dirent_idr, id);
|
||||
desc->flags &= GPIO_FLAGS_MASK;
|
||||
free_sd:
|
||||
if (value_sd)
|
||||
sysfs_put(value_sd);
|
||||
err_out:
|
||||
err_unlock:
|
||||
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
|
||||
err_put_kn:
|
||||
sysfs_put(data->value_kn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Caller holds gpiod-data mutex (unless called after class-device
|
||||
* deregistration).
|
||||
*/
|
||||
static void gpio_sysfs_free_irq(struct device *dev)
|
||||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
|
||||
data->irq_flags = 0;
|
||||
free_irq(data->irq, data);
|
||||
gpiochip_unlock_as_irq(desc->chip, gpio_chip_hwgpio(desc));
|
||||
sysfs_put(data->value_kn);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
unsigned long flags;
|
||||
unsigned char flags;
|
||||
} trigger_types[] = {
|
||||
{ "none", 0 },
|
||||
{ "falling", BIT(FLAG_TRIG_FALL) },
|
||||
{ "rising", BIT(FLAG_TRIG_RISE) },
|
||||
{ "both", BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) },
|
||||
{ "falling", GPIO_IRQF_TRIGGER_FALLING },
|
||||
{ "rising", GPIO_IRQF_TRIGGER_RISING },
|
||||
{ "both", GPIO_IRQF_TRIGGER_BOTH },
|
||||
};
|
||||
|
||||
static ssize_t gpio_edge_show(struct device *dev,
|
||||
static ssize_t edge_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
ssize_t status = 0;
|
||||
int i;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else {
|
||||
int i;
|
||||
|
||||
status = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
|
||||
if ((desc->flags & GPIO_TRIGGER_MASK)
|
||||
== trigger_types[i].flags) {
|
||||
status = sprintf(buf, "%s\n",
|
||||
trigger_types[i].name);
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
|
||||
if (data->irq_flags == trigger_types[i].flags) {
|
||||
status = sprintf(buf, "%s\n", trigger_types[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_edge_store(struct device *dev,
|
||||
static ssize_t edge_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
int i;
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
unsigned char flags;
|
||||
ssize_t status = size;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
|
||||
for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
|
||||
if (sysfs_streq(trigger_types[i].name, buf))
|
||||
goto found;
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
found:
|
||||
mutex_lock(&sysfs_lock);
|
||||
if (i == ARRAY_SIZE(trigger_types))
|
||||
return -EINVAL;
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else {
|
||||
status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
|
||||
flags = trigger_types[i].flags;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (flags == data->irq_flags) {
|
||||
status = size;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (data->irq_flags)
|
||||
gpio_sysfs_free_irq(dev);
|
||||
|
||||
if (flags) {
|
||||
status = gpio_sysfs_request_irq(dev, flags);
|
||||
if (!status)
|
||||
status = size;
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
out_unlock:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
static DEVICE_ATTR_RW(edge);
|
||||
|
||||
static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
|
||||
|
||||
static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
|
||||
int value)
|
||||
/* Caller holds gpiod-data mutex. */
|
||||
static int gpio_sysfs_set_active_low(struct device *dev, int value)
|
||||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
int status = 0;
|
||||
unsigned int flags = data->irq_flags;
|
||||
|
||||
if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
|
||||
return 0;
|
||||
@ -300,69 +305,59 @@ static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
|
||||
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
/* reconfigure poll(2) support if enabled on one edge only */
|
||||
if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
|
||||
!!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
|
||||
unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
|
||||
|
||||
gpio_setup_irq(desc, dev, 0);
|
||||
status = gpio_setup_irq(desc, dev, trigger_flags);
|
||||
if (flags == GPIO_IRQF_TRIGGER_FALLING ||
|
||||
flags == GPIO_IRQF_TRIGGER_RISING) {
|
||||
gpio_sysfs_free_irq(dev);
|
||||
status = gpio_sysfs_request_irq(dev, flags);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_active_low_show(struct device *dev,
|
||||
static ssize_t active_low_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
ssize_t status;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
status = -EIO;
|
||||
else
|
||||
status = sprintf(buf, "%d\n",
|
||||
status = sprintf(buf, "%d\n",
|
||||
!!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t gpio_active_low_store(struct device *dev,
|
||||
static ssize_t active_low_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
ssize_t status;
|
||||
long value;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
status = -EIO;
|
||||
} else {
|
||||
long value;
|
||||
status = kstrtol(buf, 0, &value);
|
||||
if (status == 0)
|
||||
status = gpio_sysfs_set_active_low(dev, value);
|
||||
|
||||
status = kstrtol(buf, 0, &value);
|
||||
if (status == 0)
|
||||
status = sysfs_set_active_low(desc, dev, value != 0);
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return status ? : size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(active_low, 0644,
|
||||
gpio_active_low_show, gpio_active_low_store);
|
||||
static DEVICE_ATTR_RW(active_low);
|
||||
|
||||
static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
|
||||
int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct gpio_desc *desc = dev_get_drvdata(dev);
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
struct gpio_desc *desc = data->desc;
|
||||
umode_t mode = attr->mode;
|
||||
bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
|
||||
bool show_direction = data->direction_can_change;
|
||||
|
||||
if (attr == &dev_attr_direction.attr) {
|
||||
if (!show_direction)
|
||||
@ -402,32 +397,32 @@ static const struct attribute_group *gpio_groups[] = {
|
||||
* /ngpio ... matching gpio_chip.ngpio
|
||||
*/
|
||||
|
||||
static ssize_t chip_base_show(struct device *dev,
|
||||
static ssize_t base_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", chip->base);
|
||||
}
|
||||
static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
|
||||
static DEVICE_ATTR_RO(base);
|
||||
|
||||
static ssize_t chip_label_show(struct device *dev,
|
||||
static ssize_t label_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", chip->label ? : "");
|
||||
}
|
||||
static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
|
||||
static DEVICE_ATTR_RO(label);
|
||||
|
||||
static ssize_t chip_ngpio_show(struct device *dev,
|
||||
static ssize_t ngpio_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct gpio_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", chip->ngpio);
|
||||
}
|
||||
static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
|
||||
static DEVICE_ATTR_RO(ngpio);
|
||||
|
||||
static struct attribute *gpiochip_attrs[] = {
|
||||
&dev_attr_base.attr,
|
||||
@ -552,6 +547,7 @@ static struct class gpio_class = {
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
struct gpiod_data *data;
|
||||
unsigned long flags;
|
||||
int status;
|
||||
const char *ioname = NULL;
|
||||
@ -574,9 +570,9 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
/* check if chip is being removed */
|
||||
if (!chip || !chip->exported) {
|
||||
if (!chip || !chip->cdev) {
|
||||
status = -ENODEV;
|
||||
goto fail_unlock;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
@ -588,43 +584,54 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
test_bit(FLAG_REQUESTED, &desc->flags),
|
||||
test_bit(FLAG_EXPORT, &desc->flags));
|
||||
status = -EPERM;
|
||||
goto fail_unlock;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
if (desc->chip->direction_input && desc->chip->direction_output &&
|
||||
direction_may_change) {
|
||||
set_bit(FLAG_SYSFS_DIR, &desc->flags);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
if (desc->chip->names && desc->chip->names[offset])
|
||||
ioname = desc->chip->names[offset];
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
status = -ENOMEM;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
dev = device_create_with_groups(&gpio_class, desc->chip->dev,
|
||||
MKDEV(0, 0), desc, gpio_groups,
|
||||
data->desc = desc;
|
||||
mutex_init(&data->mutex);
|
||||
if (chip->direction_input && chip->direction_output)
|
||||
data->direction_can_change = direction_may_change;
|
||||
else
|
||||
data->direction_can_change = false;
|
||||
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
if (chip->names && chip->names[offset])
|
||||
ioname = chip->names[offset];
|
||||
|
||||
dev = device_create_with_groups(&gpio_class, chip->dev,
|
||||
MKDEV(0, 0), data, gpio_groups,
|
||||
ioname ? ioname : "gpio%u",
|
||||
desc_to_gpio(desc));
|
||||
if (IS_ERR(dev)) {
|
||||
status = PTR_ERR(dev);
|
||||
goto fail_unlock;
|
||||
goto err_free_data;
|
||||
}
|
||||
|
||||
set_bit(FLAG_EXPORT, &desc->flags);
|
||||
mutex_unlock(&sysfs_lock);
|
||||
return 0;
|
||||
|
||||
fail_unlock:
|
||||
err_free_data:
|
||||
kfree(data);
|
||||
err_unlock:
|
||||
mutex_unlock(&sysfs_lock);
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_export);
|
||||
|
||||
static int match_export(struct device *dev, const void *data)
|
||||
static int match_export(struct device *dev, const void *desc)
|
||||
{
|
||||
return dev_get_drvdata(dev) == data;
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return data->desc == desc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -641,81 +648,25 @@ static int match_export(struct device *dev, const void *data)
|
||||
int gpiod_export_link(struct device *dev, const char *name,
|
||||
struct gpio_desc *desc)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
struct device *cdev;
|
||||
int ret;
|
||||
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
cdev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (!cdev)
|
||||
return -ENODEV;
|
||||
|
||||
if (test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
struct device *tdev;
|
||||
ret = sysfs_create_link(&dev->kobj, &cdev->kobj, name);
|
||||
put_device(cdev);
|
||||
|
||||
tdev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (tdev != NULL) {
|
||||
status = sysfs_create_link(&dev->kobj, &tdev->kobj,
|
||||
name);
|
||||
put_device(tdev);
|
||||
} else {
|
||||
status = -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (status)
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
|
||||
return status;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_export_link);
|
||||
|
||||
/**
|
||||
* gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
|
||||
* @gpio: gpio to change
|
||||
* @value: non-zero to use active low, i.e. inverted values
|
||||
*
|
||||
* Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
|
||||
* The GPIO does not have to be exported yet. If poll(2) support has
|
||||
* been enabled for either rising or falling edge, it will be
|
||||
* reconfigured to follow the new polarity.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
int status = -EINVAL;
|
||||
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
dev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (dev == NULL) {
|
||||
status = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
status = sysfs_set_active_low(desc, dev, value);
|
||||
put_device(dev);
|
||||
unlock:
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (status)
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
|
||||
|
||||
/**
|
||||
* gpiod_unexport - reverse effect of gpio_export()
|
||||
* @gpio: gpio to make unavailable
|
||||
@ -724,8 +675,8 @@ EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
|
||||
*/
|
||||
void gpiod_unexport(struct gpio_desc *desc)
|
||||
{
|
||||
int status = 0;
|
||||
struct device *dev = NULL;
|
||||
struct gpiod_data *data;
|
||||
struct device *dev;
|
||||
|
||||
if (!desc) {
|
||||
pr_warn("%s: invalid GPIO\n", __func__);
|
||||
@ -734,81 +685,78 @@ void gpiod_unexport(struct gpio_desc *desc)
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
|
||||
if (test_bit(FLAG_EXPORT, &desc->flags)) {
|
||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||
goto err_unlock;
|
||||
|
||||
dev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (dev) {
|
||||
gpio_setup_irq(desc, dev, 0);
|
||||
clear_bit(FLAG_SYSFS_DIR, &desc->flags);
|
||||
clear_bit(FLAG_EXPORT, &desc->flags);
|
||||
} else
|
||||
status = -ENODEV;
|
||||
}
|
||||
dev = class_find_device(&gpio_class, NULL, desc, match_export);
|
||||
if (!dev)
|
||||
goto err_unlock;
|
||||
|
||||
data = dev_get_drvdata(dev);
|
||||
|
||||
clear_bit(FLAG_EXPORT, &desc->flags);
|
||||
|
||||
device_unregister(dev);
|
||||
|
||||
/*
|
||||
* Release irq after deregistration to prevent race with edge_store.
|
||||
*/
|
||||
if (data->irq_flags)
|
||||
gpio_sysfs_free_irq(dev);
|
||||
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (dev) {
|
||||
device_unregister(dev);
|
||||
put_device(dev);
|
||||
}
|
||||
put_device(dev);
|
||||
kfree(data);
|
||||
|
||||
if (status)
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
return;
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&sysfs_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_unexport);
|
||||
|
||||
int gpiochip_export(struct gpio_chip *chip)
|
||||
int gpiochip_sysfs_register(struct gpio_chip *chip)
|
||||
{
|
||||
int status;
|
||||
struct device *dev;
|
||||
|
||||
/* Many systems register gpio chips for SOC support very early,
|
||||
/*
|
||||
* Many systems add gpio chips for SOC support very early,
|
||||
* before driver model support is available. In those cases we
|
||||
* export this later, in gpiolib_sysfs_init() ... here we just
|
||||
* register later, in gpiolib_sysfs_init() ... here we just
|
||||
* verify that _some_ field of gpio_class got initialized.
|
||||
*/
|
||||
if (!gpio_class.p)
|
||||
return 0;
|
||||
|
||||
/* use chip->base for the ID; it's already known to be unique */
|
||||
mutex_lock(&sysfs_lock);
|
||||
dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
|
||||
chip, gpiochip_groups,
|
||||
"gpiochip%d", chip->base);
|
||||
if (IS_ERR(dev))
|
||||
status = PTR_ERR(dev);
|
||||
else
|
||||
status = 0;
|
||||
chip->exported = (status == 0);
|
||||
return PTR_ERR(dev);
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
chip->cdev = dev;
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
if (status)
|
||||
chip_dbg(chip, "%s: status %d\n", __func__, status);
|
||||
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpiochip_unexport(struct gpio_chip *chip)
|
||||
void gpiochip_sysfs_unregister(struct gpio_chip *chip)
|
||||
{
|
||||
int status;
|
||||
struct device *dev;
|
||||
struct gpio_desc *desc;
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&sysfs_lock);
|
||||
dev = class_find_device(&gpio_class, NULL, chip, match_export);
|
||||
if (dev) {
|
||||
put_device(dev);
|
||||
device_unregister(dev);
|
||||
/* prevent further gpiod exports */
|
||||
chip->exported = false;
|
||||
status = 0;
|
||||
} else
|
||||
status = -ENODEV;
|
||||
mutex_unlock(&sysfs_lock);
|
||||
if (!chip->cdev)
|
||||
return;
|
||||
|
||||
if (status)
|
||||
chip_dbg(chip, "%s: status %d\n", __func__, status);
|
||||
device_unregister(chip->cdev);
|
||||
|
||||
/* prevent further gpiod exports */
|
||||
mutex_lock(&sysfs_lock);
|
||||
chip->cdev = NULL;
|
||||
mutex_unlock(&sysfs_lock);
|
||||
|
||||
/* unregister gpiod class devices owned by sysfs */
|
||||
for (i = 0; i < chip->ngpio; i++) {
|
||||
@ -836,19 +784,20 @@ static int __init gpiolib_sysfs_init(void)
|
||||
*/
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
list_for_each_entry(chip, &gpio_chips, list) {
|
||||
if (chip->exported)
|
||||
if (chip->cdev)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* TODO we yield gpio_lock here because gpiochip_export()
|
||||
* acquires a mutex. This is unsafe and needs to be fixed.
|
||||
* TODO we yield gpio_lock here because
|
||||
* gpiochip_sysfs_register() acquires a mutex. This is unsafe
|
||||
* and needs to be fixed.
|
||||
*
|
||||
* Also it would be nice to use gpiochip_find() here so we
|
||||
* can keep gpio_chips local to gpiolib.c, but the yield of
|
||||
* gpio_lock prevents us from doing this.
|
||||
*/
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
status = gpiochip_export(chip);
|
||||
status = gpiochip_sysfs_register(chip);
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
@ -290,7 +290,7 @@ int gpiochip_add(struct gpio_chip *chip)
|
||||
of_gpiochip_add(chip);
|
||||
acpi_gpiochip_add(chip);
|
||||
|
||||
status = gpiochip_export(chip);
|
||||
status = gpiochip_sysfs_register(chip);
|
||||
if (status)
|
||||
goto err_remove_chip;
|
||||
|
||||
@ -327,10 +327,12 @@ EXPORT_SYMBOL_GPL(gpiochip_add);
|
||||
*/
|
||||
void gpiochip_remove(struct gpio_chip *chip)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
unsigned long flags;
|
||||
unsigned id;
|
||||
bool requested = false;
|
||||
|
||||
gpiochip_unexport(chip);
|
||||
gpiochip_sysfs_unregister(chip);
|
||||
|
||||
gpiochip_irqchip_remove(chip);
|
||||
|
||||
@ -341,15 +343,17 @@ void gpiochip_remove(struct gpio_chip *chip)
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
for (id = 0; id < chip->ngpio; id++) {
|
||||
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
|
||||
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
|
||||
desc = &chip->desc[id];
|
||||
desc->chip = NULL;
|
||||
if (test_bit(FLAG_REQUESTED, &desc->flags))
|
||||
requested = true;
|
||||
}
|
||||
for (id = 0; id < chip->ngpio; id++)
|
||||
chip->desc[id].chip = NULL;
|
||||
|
||||
list_del(&chip->list);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
if (requested)
|
||||
dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
|
||||
|
||||
kfree(chip->desc);
|
||||
chip->desc = NULL;
|
||||
}
|
||||
@ -441,6 +445,8 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||
*/
|
||||
irq_set_handler_data(parent_irq, gpiochip);
|
||||
irq_set_chained_handler(parent_irq, parent_handler);
|
||||
|
||||
gpiochip->irq_parent = parent_irq;
|
||||
}
|
||||
|
||||
/* Set the parent IRQ for all affected IRQs */
|
||||
@ -549,6 +555,11 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
|
||||
|
||||
acpi_gpiochip_free_interrupts(gpiochip);
|
||||
|
||||
if (gpiochip->irq_parent) {
|
||||
irq_set_chained_handler(gpiochip->irq_parent, NULL);
|
||||
irq_set_handler_data(gpiochip->irq_parent, NULL);
|
||||
}
|
||||
|
||||
/* Remove all IRQ mappings and delete the domain */
|
||||
if (gpiochip->irqdomain) {
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++)
|
||||
@ -608,7 +619,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
||||
of_node = gpiochip->dev->of_node;
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
/*
|
||||
* If the gpiochip has an assigned OF node this takes precendence
|
||||
* If the gpiochip has an assigned OF node this takes precedence
|
||||
* FIXME: get rid of this and use gpiochip->dev->of_node everywhere
|
||||
*/
|
||||
if (gpiochip->of_node)
|
||||
@ -1211,7 +1222,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
|
||||
/*
|
||||
* _gpio_set_open_drain_value() - Set the open drain gpio's value.
|
||||
* @desc: gpio descriptor whose state need to be set.
|
||||
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
|
||||
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
|
||||
*/
|
||||
static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
|
||||
{
|
||||
@ -1238,7 +1249,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
|
||||
/*
|
||||
* _gpio_set_open_source_value() - Set the open source gpio's value.
|
||||
* @desc: gpio descriptor whose state need to be set.
|
||||
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
|
||||
* @value: Non-zero for setting it HIGH otherwise it will set to LOW.
|
||||
*/
|
||||
static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
|
||||
{
|
||||
@ -1300,17 +1311,16 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
|
||||
continue;
|
||||
}
|
||||
/* set outputs if the corresponding mask bit is set */
|
||||
if (__test_and_clear_bit(i, mask)) {
|
||||
if (__test_and_clear_bit(i, mask))
|
||||
chip->set(chip, i, test_bit(i, bits));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gpiod_set_array_priv(bool raw, bool can_sleep,
|
||||
unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
|
||||
unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
@ -1320,9 +1330,9 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
|
||||
unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
|
||||
int count = 0;
|
||||
|
||||
if (!can_sleep) {
|
||||
if (!can_sleep)
|
||||
WARN_ON(chip->can_sleep);
|
||||
}
|
||||
|
||||
memset(mask, 0, sizeof(mask));
|
||||
do {
|
||||
struct gpio_desc *desc = desc_array[i];
|
||||
@ -1337,24 +1347,22 @@ static void gpiod_set_array_priv(bool raw, bool can_sleep,
|
||||
* open drain and open source outputs are set individually
|
||||
*/
|
||||
if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
|
||||
_gpio_set_open_drain_value(desc,value);
|
||||
_gpio_set_open_drain_value(desc, value);
|
||||
} else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
|
||||
_gpio_set_open_source_value(desc, value);
|
||||
} else {
|
||||
__set_bit(hwgpio, mask);
|
||||
if (value) {
|
||||
if (value)
|
||||
__set_bit(hwgpio, bits);
|
||||
} else {
|
||||
else
|
||||
__clear_bit(hwgpio, bits);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
i++;
|
||||
} while ((i < array_size) && (desc_array[i]->chip == chip));
|
||||
/* push collected bits to outputs */
|
||||
if (count != 0) {
|
||||
if (count != 0)
|
||||
gpio_chip_set_multiple(chip, mask, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1403,7 +1411,7 @@ void gpiod_set_value(struct gpio_desc *desc, int value)
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_value);
|
||||
|
||||
/**
|
||||
* gpiod_set_raw_array() - assign values to an array of GPIOs
|
||||
* gpiod_set_raw_array_value() - assign values to an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be assigned
|
||||
* @value_array: array of values to assign
|
||||
@ -1414,17 +1422,18 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
|
||||
* This function should be called from contexts where we cannot sleep, and will
|
||||
* complain if the GPIO chip functions potentially sleep.
|
||||
*/
|
||||
void gpiod_set_raw_array(unsigned int array_size,
|
||||
void gpiod_set_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array)
|
||||
{
|
||||
if (!desc_array)
|
||||
return;
|
||||
gpiod_set_array_priv(true, false, array_size, desc_array, value_array);
|
||||
gpiod_set_array_value_priv(true, false, array_size, desc_array,
|
||||
value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
|
||||
|
||||
/**
|
||||
* gpiod_set_array() - assign values to an array of GPIOs
|
||||
* gpiod_set_array_value() - assign values to an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be assigned
|
||||
* @value_array: array of values to assign
|
||||
@ -1435,14 +1444,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
|
||||
* This function should be called from contexts where we cannot sleep, and will
|
||||
* complain if the GPIO chip functions potentially sleep.
|
||||
*/
|
||||
void gpiod_set_array(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array)
|
||||
void gpiod_set_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array)
|
||||
{
|
||||
if (!desc_array)
|
||||
return;
|
||||
gpiod_set_array_priv(false, false, array_size, desc_array, value_array);
|
||||
gpiod_set_array_value_priv(false, false, array_size, desc_array,
|
||||
value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_array);
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_array_value);
|
||||
|
||||
/**
|
||||
* gpiod_cansleep() - report whether gpio value access may sleep
|
||||
@ -1604,7 +1614,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
|
||||
|
||||
/**
|
||||
* gpiod_set_raw_array_cansleep() - assign values to an array of GPIOs
|
||||
* gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be assigned
|
||||
* @value_array: array of values to assign
|
||||
@ -1614,19 +1624,20 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
|
||||
*
|
||||
* This function is to be called from contexts that can sleep.
|
||||
*/
|
||||
void gpiod_set_raw_array_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
might_sleep_if(extra_checks);
|
||||
if (!desc_array)
|
||||
return;
|
||||
gpiod_set_array_priv(true, true, array_size, desc_array, value_array);
|
||||
gpiod_set_array_value_priv(true, true, array_size, desc_array,
|
||||
value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
|
||||
|
||||
/**
|
||||
* gpiod_set_array_cansleep() - assign values to an array of GPIOs
|
||||
* gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
* @desc_array: array of GPIO descriptors whose values will be assigned
|
||||
* @value_array: array of values to assign
|
||||
@ -1636,16 +1647,17 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
|
||||
*
|
||||
* This function is to be called from contexts that can sleep.
|
||||
*/
|
||||
void gpiod_set_array_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
void gpiod_set_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
might_sleep_if(extra_checks);
|
||||
if (!desc_array)
|
||||
return;
|
||||
gpiod_set_array_priv(false, true, array_size, desc_array, value_array);
|
||||
gpiod_set_array_value_priv(false, true, array_size, desc_array,
|
||||
value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_array_cansleep);
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
|
||||
|
||||
/**
|
||||
* gpiod_add_lookup_table() - register GPIO device consumers
|
||||
@ -1880,7 +1892,7 @@ EXPORT_SYMBOL_GPL(gpiod_count);
|
||||
*
|
||||
* Return the GPIO descriptor corresponding to the function con_id of device
|
||||
* dev, -ENOENT if no GPIO has been assigned to the requested function, or
|
||||
* another IS_ERR() code if an error occured while trying to acquire the GPIO.
|
||||
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
|
||||
*/
|
||||
struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
@ -1960,7 +1972,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
||||
*
|
||||
* Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the
|
||||
* requested function and/or index, or another IS_ERR() code if an error
|
||||
* occured while trying to acquire the GPIO.
|
||||
* occurred while trying to acquire the GPIO.
|
||||
*/
|
||||
struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
|
||||
const char *con_id,
|
||||
@ -2118,13 +2130,15 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
||||
|
||||
local_desc = gpiochip_request_own_desc(chip, hwnum, name);
|
||||
if (IS_ERR(local_desc)) {
|
||||
pr_debug("requesting own GPIO %s failed\n", name);
|
||||
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
|
||||
name, chip->label, hwnum);
|
||||
return PTR_ERR(local_desc);
|
||||
}
|
||||
|
||||
status = gpiod_configure_flags(desc, name, lflags, dflags);
|
||||
if (status < 0) {
|
||||
pr_debug("setup of GPIO %s failed\n", name);
|
||||
pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
|
||||
name, chip->label, hwnum);
|
||||
gpiochip_free_own_desc(desc);
|
||||
return status;
|
||||
}
|
||||
|
@ -83,20 +83,12 @@ struct gpio_desc {
|
||||
#define FLAG_IS_OUT 1
|
||||
#define FLAG_EXPORT 2 /* protected by sysfs_lock */
|
||||
#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
|
||||
#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
|
||||
#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
|
||||
#define FLAG_ACTIVE_LOW 6 /* value has active low */
|
||||
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
|
||||
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
|
||||
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
|
||||
#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */
|
||||
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
|
||||
|
||||
#define ID_SHIFT 16 /* add new flags before this one */
|
||||
|
||||
#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
|
||||
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
|
||||
|
||||
const char *label;
|
||||
};
|
||||
|
||||
@ -151,17 +143,17 @@ static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
|
||||
|
||||
#ifdef CONFIG_GPIO_SYSFS
|
||||
|
||||
int gpiochip_export(struct gpio_chip *chip);
|
||||
void gpiochip_unexport(struct gpio_chip *chip);
|
||||
int gpiochip_sysfs_register(struct gpio_chip *chip);
|
||||
void gpiochip_sysfs_unregister(struct gpio_chip *chip);
|
||||
|
||||
#else
|
||||
|
||||
static inline int gpiochip_export(struct gpio_chip *chip)
|
||||
static inline int gpiochip_sysfs_register(struct gpio_chip *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void gpiochip_unexport(struct gpio_chip *chip)
|
||||
static inline void gpiochip_sysfs_unregister(struct gpio_chip *chip)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
|
||||
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
|
||||
info->flags |= I2C_CLIENT_TEN;
|
||||
}
|
||||
} else if (info->irq < 0) {
|
||||
} else if (!info->irq) {
|
||||
struct resource r;
|
||||
|
||||
if (acpi_dev_resource_interrupt(ares, 0, &r))
|
||||
@ -134,7 +134,6 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.fwnode = acpi_fwnode_handle(adev);
|
||||
info.irq = -1;
|
||||
|
||||
INIT_LIST_HEAD(&resource_list);
|
||||
ret = acpi_dev_get_resources(adev, &resource_list,
|
||||
@ -632,8 +631,13 @@ static int i2c_device_probe(struct device *dev)
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
if (!client->irq && dev->of_node) {
|
||||
int irq = of_irq_get(dev->of_node, 0);
|
||||
if (!client->irq) {
|
||||
int irq = -ENOENT;
|
||||
|
||||
if (dev->of_node)
|
||||
irq = of_irq_get(dev->of_node, 0);
|
||||
else if (ACPI_COMPANION(dev))
|
||||
irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
|
||||
|
||||
if (irq == -EPROBE_DEFER)
|
||||
return irq;
|
||||
|
@ -35,7 +35,8 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
|
||||
for (n = 0; n < s->gpios->ndescs; n++)
|
||||
values[n] = (desired_child >> n) & 1;
|
||||
|
||||
gpiod_set_array_cansleep(s->gpios->ndescs, s->gpios->desc, values);
|
||||
gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc,
|
||||
values);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
|
||||
count++;
|
||||
}
|
||||
gpiod_set_array(count, desc_array, value_array);
|
||||
gpiod_set_array_value(count, desc_array, value_array);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
|
||||
|
||||
|
@ -128,11 +128,6 @@ static inline int gpio_export_link(struct device *dev, const char *name,
|
||||
return gpiod_export_link(dev, name, gpio_to_desc(gpio));
|
||||
}
|
||||
|
||||
static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
|
||||
{
|
||||
return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value);
|
||||
}
|
||||
|
||||
static inline void gpio_unexport(unsigned gpio)
|
||||
{
|
||||
gpiod_unexport(gpio_to_desc(gpio));
|
||||
|
@ -721,6 +721,8 @@ static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
|
||||
if (adev)
|
||||
adev->driver_gpios = NULL;
|
||||
}
|
||||
|
||||
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
|
||||
#else
|
||||
static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
const struct acpi_gpio_mapping *gpios)
|
||||
@ -728,6 +730,11 @@ static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
|
||||
|
||||
static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Device properties */
|
||||
|
@ -74,5 +74,6 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
|
||||
#define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */
|
||||
#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */
|
||||
#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3)
|
||||
#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
|
||||
|
||||
#endif /* __BASIC_MMIO_GPIO_H */
|
||||
|
@ -196,13 +196,6 @@ static inline int gpio_export_link(struct device *dev, const char *name,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline void gpio_unexport(unsigned gpio)
|
||||
{
|
||||
/* GPIO can never have been exported */
|
||||
|
@ -100,24 +100,25 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
|
||||
/* Value get/set from non-sleeping context */
|
||||
int gpiod_get_value(const struct gpio_desc *desc);
|
||||
void gpiod_set_value(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_array(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array);
|
||||
void gpiod_set_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array);
|
||||
int gpiod_get_raw_value(const struct gpio_desc *desc);
|
||||
void gpiod_set_raw_value(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_raw_array(unsigned int array_size,
|
||||
struct gpio_desc **desc_array, int *value_array);
|
||||
void gpiod_set_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
|
||||
/* Value get/set from sleeping context */
|
||||
int gpiod_get_value_cansleep(const struct gpio_desc *desc);
|
||||
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_array_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
void gpiod_set_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
|
||||
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
|
||||
void gpiod_set_raw_array_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array);
|
||||
|
||||
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
|
||||
|
||||
@ -304,9 +305,9 @@ static inline void gpiod_set_value(struct gpio_desc *desc, int value)
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
}
|
||||
static inline void gpiod_set_array(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
static inline void gpiod_set_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
@ -322,9 +323,9 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
}
|
||||
static inline void gpiod_set_raw_array(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
static inline void gpiod_set_raw_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
@ -341,7 +342,7 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
}
|
||||
static inline void gpiod_set_array_cansleep(unsigned int array_size,
|
||||
static inline void gpiod_set_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
@ -360,7 +361,7 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
|
||||
/* GPIO can never have been requested */
|
||||
WARN_ON(1);
|
||||
}
|
||||
static inline void gpiod_set_raw_array_cansleep(unsigned int array_size,
|
||||
static inline void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
int *value_array)
|
||||
{
|
||||
@ -449,7 +450,6 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
|
||||
int gpiod_export_link(struct device *dev, const char *name,
|
||||
struct gpio_desc *desc);
|
||||
int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
|
||||
void gpiod_unexport(struct gpio_desc *desc);
|
||||
|
||||
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
|
||||
@ -466,11 +466,6 @@ static inline int gpiod_export_link(struct device *dev, const char *name,
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline void gpiod_unexport(struct gpio_desc *desc)
|
||||
{
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ struct seq_file;
|
||||
* struct gpio_chip - abstract a GPIO controller
|
||||
* @label: for diagnostics
|
||||
* @dev: optional device providing the GPIOs
|
||||
* @cdev: class device used by sysfs interface (may be NULL)
|
||||
* @owner: helps prevent removal of modules exporting active GPIOs
|
||||
* @list: links gpio_chips together for traversal
|
||||
* @request: optional hook for chip-specific activation, such as
|
||||
@ -41,8 +42,12 @@ struct seq_file;
|
||||
* @dbg_show: optional routine to show contents in debugfs; default code
|
||||
* will be used when this is omitted, but custom code can show extra
|
||||
* state (such as pullup/pulldown configuration).
|
||||
* @base: identifies the first GPIO number handled by this chip; or, if
|
||||
* negative during registration, requests dynamic ID allocation.
|
||||
* @base: identifies the first GPIO number handled by this chip;
|
||||
* or, if negative during registration, requests dynamic ID allocation.
|
||||
* DEPRECATION: providing anything non-negative and nailing the base
|
||||
* base offset of GPIO chips is deprecated. Please pass -1 as base to
|
||||
* let gpiolib select the chip base in all possible cases. We want to
|
||||
* get rid of the static GPIO number space in the long run.
|
||||
* @ngpio: the number of GPIOs handled by this controller; the last GPIO
|
||||
* handled is (base + ngpio - 1).
|
||||
* @desc: array of ngpio descriptors. Private.
|
||||
@ -57,7 +62,6 @@ struct seq_file;
|
||||
* implies that if the chip supports IRQs, these IRQs need to be threaded
|
||||
* as the chip access may sleep when e.g. reading out the IRQ status
|
||||
* registers.
|
||||
* @exported: flags if the gpiochip is exported for use from sysfs. Private.
|
||||
* @irq_not_threaded: flag must be set if @can_sleep is set but the
|
||||
* IRQs don't need to be threaded
|
||||
*
|
||||
@ -74,6 +78,7 @@ struct seq_file;
|
||||
struct gpio_chip {
|
||||
const char *label;
|
||||
struct device *dev;
|
||||
struct device *cdev;
|
||||
struct module *owner;
|
||||
struct list_head list;
|
||||
|
||||
@ -109,7 +114,6 @@ struct gpio_chip {
|
||||
const char *const *names;
|
||||
bool can_sleep;
|
||||
bool irq_not_threaded;
|
||||
bool exported;
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
/*
|
||||
@ -121,6 +125,7 @@ struct gpio_chip {
|
||||
unsigned int irq_base;
|
||||
irq_flow_handler_t irq_handler;
|
||||
unsigned int irq_default_type;
|
||||
int irq_parent;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF_GPIO)
|
||||
|
@ -208,9 +208,17 @@ struct omap_gpio_platform_data {
|
||||
int (*get_context_loss_count)(struct device *dev);
|
||||
};
|
||||
|
||||
#if IS_BUILTIN(CONFIG_GPIO_OMAP)
|
||||
extern void omap2_gpio_prepare_for_idle(int off_mode);
|
||||
extern void omap2_gpio_resume_after_idle(void);
|
||||
extern void omap_set_gpio_debounce(int gpio, int enable);
|
||||
extern void omap_set_gpio_debounce_time(int gpio, int enable);
|
||||
#else
|
||||
static inline void omap2_gpio_prepare_for_idle(int off_mode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void omap2_gpio_resume_after_idle(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user