gpio: updates for v6.0-rc1

- remove gpio-vr41xx driver as the only platform using it got dropped too
 - add support for suspend/resume to gpio-davinci
 - improvements to the GPIO character device code
 - add support for disabling bias for in-kernel users (up until now
   only user-space could set it)
 - drop unused devm_gpio_free()
 - fix a refcount issue in gpiolib OF
 - use device match helpers where applicable
 - add support for a new model to gpio-rockchip
 - non-functional improvements in gpio-adp5588
 - improve and simplify teardown in gpio-twl4030 and gpio-ucb1400
 - modernize the gpio-74xx-mmio and gpio-adnp drivers
 - coding style improvements in gpio-xilinx, gpio-104-idi-48
 - support new model (pca9571) in gpio-pca9570
 - convert the DT bindings to YAML for gpio-mvebu and update the document
 - don't return error codes from remove() in gpio-brcmstb
 - add a library for the intel 8255 PPI interface and use it in drivers
 - reduce using magic numbers and improve code readability in several drivers
 - convert DT bindings to YAML for gpio-tpic2810
 - add new models to DT bindings for gpio-frl-imx
 - Kconfig improvements
 - other minor tweaks and improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmLruBoACgkQEacuoBRx
 13LSqA//QMdrdsYOvSp3m6Dy1swj8a2VpeInDclx/JQ51hIsv03lW6sysrRBBKfy
 gslkj0KO+kelEQbcHZdXF6f434Y2QqSU/JRCPQlQ55Uo3vSbUulvVkUtSoegdNKG
 airr5KebZtLzjBgc23n38HiTJxa1J238+3UScxYHqL9jQ6AA6sPx7Kpy2zlTwojn
 iygJ1CKuyMyHOjU1uhAWYVzCAoguVvOb58emUt5HUsOjjW42d8T+iCHxrJnjC3ST
 YWwHnkSd3GO5CLI+5w7MmLk4kaOA8KU7PGRljglwpbsNGknUQ3PFFSlqFUziBzMU
 nOG1gZ9bvzOy5xjFcLkT3p/NHZiTnyq+ugDl2RAVQB2UF31KHk2sVGrzIsRpbBgt
 kDst5Wn21oymfEO6FM269h5ln+haXouJv2eQvnayBr3rfMxaZCm8veFxjQBDRADf
 D3muvi6u/EJPsPg08owcaVrINPVYVGQIzQp5hi+UCBkzXghn+MovNuI/i07Qf1kr
 fBELOXTy+MGK22p+rO+rXsp0Cp1zUIbwSz0m8ImbhLqcYLa+Vm5bJHk31/Igvbv3
 9FMR75RmfE98EvMhd6ECarZHF9rvCVN7R1U9P1aK8+85m7X5eIVehoQ125uAZf+N
 +W49bceSCI/mGqIg8MiQCM5NIW0AXvyjd7gTNN5kr7qsMGTJI3c=
 =rGNU
 -----END PGP SIGNATURE-----

Merge tag 'gpio-updates-for-v6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio updates from Bartosz Golaszewski:
 "Here are the updates for this merge window from the GPIO subsystem.

  We have more lines removed than added thanks to dropping of a driver
  for a platform that's no longer supported. Otherwise the changes are
  pretty straightforward: support for some new models, various
  improvements to existing drivers, some tweaks to the core library code
  and DT bindings updates.

  Summary:

   - remove gpio-vr41xx driver as the only platform using it got dropped
     too

   - add support for suspend/resume to gpio-davinci

   - improvements to the GPIO character device code

   - add support for disabling bias for in-kernel users (up until now
     only user-space could set it)

   - drop unused devm_gpio_free()

   - fix a refcount issue in gpiolib OF

   - use device match helpers where applicable

   - add support for a new model to gpio-rockchip

   - non-functional improvements in gpio-adp5588

   - improve and simplify teardown in gpio-twl4030 and gpio-ucb1400

   - modernize the gpio-74xx-mmio and gpio-adnp drivers

   - coding style improvements in gpio-xilinx, gpio-104-idi-48

   - support new model (pca9571) in gpio-pca9570

   - convert the DT bindings to YAML for gpio-mvebu and update the
     document

   - don't return error codes from remove() in gpio-brcmstb

   - add a library for the intel 8255 PPI interface and use it in
     drivers

   - reduce using magic numbers and improve code readability in several
     drivers

   - convert DT bindings to YAML for gpio-tpic2810

   - add new models to DT bindings for gpio-frl-imx

   - Kconfig improvements

   - other minor tweaks and improvements"

* tag 'gpio-updates-for-v6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (52 commits)
  dt-bindings: gpio: fsl-imx-gpio: Add i.MXRT compatibles
  gpio: 74xx-mmio: Use bits instead of plain numbers for flags
  gpio: xilinx: add missing blank line after declarations
  MAINTAINERS: Update Intel 8255 GPIO driver file list
  gpio: gpio-mm: Implement and utilize register structures
  gpio: 104-idi-48: Implement and utilize register structures
  gpio: 104-dio-48e: Implement and utilize register structures
  gpio: i8255: Introduce the Intel 8255 interface library module
  gpio: 104-idio-16: Implement and utilize register structures
  gpio: ws16c48: Implement and utilize register structures
  gpio: remove VR41XX related gpio driver
  dt-bindings: gpio: add pull-disable flag
  gpiolib: acpi: support bias pull disable
  gpiolib: of: support bias pull disable
  gpiolib: add support for bias pull disable
  gpio: 74xx-mmio: use bits.h macros for all masks
  gpio: 74xx-mmio: Check MMIO_74XX_DIR_IN flag in mmio_74xx_dir_in()
  gpio: 74xx-mmio: Make use of device properties
  gpiolib: cdev: compile out HTE unless CONFIG_HTE selected
  gpiolib: cdev: consolidate edge detector configuration flags
  ...
This commit is contained in:
Linus Torvalds 2022-08-04 18:34:05 -07:00
commit 37644cac6e
47 changed files with 1197 additions and 1452 deletions

View File

@ -72,7 +72,7 @@ mpp19 19 gpio, uart0(rxd), sdio(pw_off)
GPIO:
-----
For common binding part and usage, refer to
Documentation/devicetree/bindings/gpio/gpio-mvebu.txt.
Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml.
Required properties:

View File

@ -156,7 +156,7 @@ GPIO:
-----
For common binding part and usage, refer to
Documentation/devicetree/bindings/gpio/gpio-mvebu.txt.
Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml.
Required properties:

View File

@ -37,6 +37,8 @@ properties:
- fsl,imx8mp-gpio
- fsl,imx8mq-gpio
- fsl,imx8qxp-gpio
- fsl,imxrt1050-gpio
- fsl,imxrt1170-gpio
- const: fsl,imx35-gpio
reg:

View File

@ -1,93 +0,0 @@
* Marvell EBU GPIO controller
Required properties:
- compatible : Should be "marvell,orion-gpio", "marvell,mv78200-gpio",
"marvell,armadaxp-gpio" or "marvell,armada-8k-gpio".
"marvell,orion-gpio" should be used for Orion, Kirkwood, Dove,
Discovery (except MV78200) and Armada 370. "marvell,mv78200-gpio"
should be used for the Discovery MV78200.
"marvel,armadaxp-gpio" should be used for all Armada XP SoCs
(MV78230, MV78260, MV78460).
"marvell,armada-8k-gpio" should be used for the Armada 7K and 8K
SoCs (either from AP or CP), see
Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt
for specific details about the offset property.
- reg: Address and length of the register set for the device. Only one
entry is expected, except for the "marvell,armadaxp-gpio" variant
for which two entries are expected: one for the general registers,
one for the per-cpu registers. Not used for marvell,armada-8k-gpio.
- interrupts: The list of interrupts that are used for all the pins
managed by this GPIO bank. There can be more than one interrupt
(example: 1 interrupt per 8 pins on Armada XP, which means 4
interrupts per bank of 32 GPIOs).
- interrupt-controller: identifies the node as an interrupt controller
- #interrupt-cells: specifies the number of cells needed to encode an
interrupt source. Should be two.
The first cell is the GPIO number.
The second cell is used to specify flags:
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.
- gpio-controller: marks the device node as a gpio controller
- ngpios: number of GPIOs this controller has
- #gpio-cells: Should be two. The first cell is the pin number. The
second cell is reserved for flags, unused at the moment.
Optional properties:
In order to use the GPIO lines in PWM mode, some additional optional
properties are required.
- compatible: Must contain "marvell,armada-370-gpio"
- reg: an additional register set is needed, for the GPIO Blink
Counter on/off registers.
- reg-names: Must contain an entry "pwm" corresponding to the
additional register range needed for PWM operation.
- #pwm-cells: Should be two. The first cell is the GPIO line number. The
second cell is the period in nanoseconds.
- clocks: Must be a phandle to the clock for the GPIO controller.
Example:
gpio0: gpio@d0018100 {
compatible = "marvell,armadaxp-gpio";
reg = <0xd0018100 0x40>,
<0xd0018800 0x30>;
ngpios = <32>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <16>, <17>, <18>, <19>;
};
gpio1: gpio@18140 {
compatible = "marvell,armada-370-gpio";
reg = <0x18140 0x40>, <0x181c8 0x08>;
reg-names = "gpio", "pwm";
ngpios = <17>;
gpio-controller;
#gpio-cells = <2>;
#pwm-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <87>, <88>, <89>;
clocks = <&coreclk 0>;
};

View File

@ -0,0 +1,146 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/gpio-mvebu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell EBU GPIO controller
maintainers:
- Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
- Andrew Lunn <andrew@lunn.ch>
properties:
compatible:
oneOf:
- enum:
- marvell,armada-8k-gpio
- marvell,orion-gpio
- items:
- enum:
- marvell,mv78200-gpio
- marvell,armada-370-gpio
- const: marvell,orion-gpio
- description: Deprecated binding
items:
- const: marvell,armadaxp-gpio
- const: marvell,orion-gpio
deprecated: true
reg:
description: |
Address and length of the register set for the device. Not used for
marvell,armada-8k-gpio.
A second entry can be provided, for the PWM function using the GPIO Blink
Counter on/off registers.
minItems: 1
maxItems: 2
reg-names:
items:
- const: gpio
- const: pwm
minItems: 1
offset:
$ref: /schemas/types.yaml#/definitions/uint32
description: Offset in the register map for the gpio registers (in bytes)
interrupts:
description: |
The list of interrupts that are used for all the pins managed by this
GPIO bank. There can be more than one interrupt (example: 1 interrupt
per 8 pins on Armada XP, which means 4 interrupts per bank of 32
GPIOs).
minItems: 1
maxItems: 4
interrupt-controller: true
"#interrupt-cells":
const: 2
gpio-controller: true
ngpios:
minimum: 1
maximum: 32
"#gpio-cells":
const: 2
marvell,pwm-offset:
$ref: /schemas/types.yaml#/definitions/uint32
description: Offset in the register map for the pwm registers (in bytes)
"#pwm-cells":
description:
The first cell is the GPIO line number. The second cell is the period
in nanoseconds.
const: 2
clocks:
description:
Clock(s) used for PWM function.
items:
- description: Core clock
- description: AXI bus clock
minItems: 1
clock-names:
items:
- const: core
- const: axi
minItems: 1
required:
- compatible
- gpio-controller
- ngpios
- "#gpio-cells"
allOf:
- if:
properties:
compatible:
contains:
const: marvell,armada-8k-gpio
then:
required:
- offset
else:
required:
- reg
unevaluatedProperties: true
examples:
- |
gpio@d0018100 {
compatible = "marvell,armadaxp-gpio", "marvell,orion-gpio";
reg = <0xd0018100 0x40>, <0xd0018800 0x30>;
ngpios = <32>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <16>, <17>, <18>, <19>;
};
- |
gpio@18140 {
compatible = "marvell,armada-370-gpio", "marvell,orion-gpio";
reg = <0x18140 0x40>, <0x181c8 0x08>;
reg-names = "gpio", "pwm";
ngpios = <17>;
gpio-controller;
#gpio-cells = <2>;
#pwm-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <87>, <88>, <89>;
clocks = <&coreclk 0>;
};

View File

@ -13,6 +13,7 @@ properties:
compatible:
enum:
- nxp,pca9570
- nxp,pca9571
reg:
maxItems: 1

View File

@ -1,16 +0,0 @@
TPIC2810 GPIO controller bindings
Required properties:
- compatible : Should be "ti,tpic2810".
- reg : The I2C address of the device
- gpio-controller : Marks the device node as a GPIO controller.
- #gpio-cells : Should be two. For consumer use see gpio.txt.
Example:
gpio@60 {
compatible = "ti,tpic2810";
reg = <0x60>;
gpio-controller;
#gpio-cells = <2>;
};

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/gpio-tpic2810.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TPIC2810 GPIO controller bindings
maintainers:
- Aswath Govindraju <a-govindraju@ti.com>
properties:
compatible:
enum:
- ti,tpic2810
reg:
maxItems: 1
gpio-controller: true
"#gpio-cells":
const: 2
gpio-line-names:
minItems: 1
maxItems: 32
required:
- compatible
- reg
- gpio-controller
- "#gpio-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
gpio@60 {
compatible = "ti,tpic2810";
reg = <0x60>;
gpio-controller;
#gpio-cells = <2>;
gpio-line-names = "LED A", "LED B", "LED C";
};
};

View File

@ -48,11 +48,9 @@ properties:
- renesas,gpio-r8a77995 # R-Car D3
- const: renesas,rcar-gen3-gpio # R-Car Gen3 or RZ/G2
- items:
- const: renesas,gpio-r8a779a0 # R-Car V3U
- items:
- enum:
- renesas,gpio-r8a779a0 # R-Car V3U
- renesas,gpio-r8a779f0 # R-Car S4-8
- const: renesas,rcar-gen4-gpio # R-Car Gen4

View File

@ -27,6 +27,8 @@ properties:
- description: APB interface clock source
- description: GPIO debounce reference clock source
gpio-ranges: true
gpio-controller: true
gpio-line-names: true

View File

@ -277,7 +277,6 @@ GPIO
devm_gpiochip_add_data()
devm_gpio_request()
devm_gpio_request_one()
devm_gpio_free()
I2C
devm_i2c_new_dummy_device()

View File

@ -10045,6 +10045,13 @@ L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/fbdev/i810/
INTEL 8255 GPIO DRIVER
M: William Breathitt Gray <william.gray@linaro.org>
L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-i8255.c
F: drivers/gpio/gpio-i8255.h
INTEL ASoC DRIVERS
M: Cezary Rojewski <cezary.rojewski@intel.com>
M: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
@ -16503,7 +16510,7 @@ L: linux-pwm@vger.kernel.org
S: Maintained
Q: https://patchwork.ozlabs.org/project/linux-pwm/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
F: Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
F: Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml
F: Documentation/devicetree/bindings/pwm/
F: Documentation/driver-api/pwm.rst
F: drivers/gpio/gpio-mvebu.c

View File

@ -544,6 +544,7 @@ config GPIO_SAMA5D2_PIOBU
tristate "SAMA5D2 PIOBU GPIO support"
depends on MFD_SYSCON
depends on OF_GPIO
depends on ARCH_AT91 || COMPILE_TEST
select GPIO_SYSCON
help
Say yes here to use the PIOBU pins as GPIOs.
@ -690,12 +691,6 @@ config GPIO_VISCONTI
help
Say yes here to support GPIO on Tohisba Visconti.
config GPIO_VR41XX
tristate "NEC VR4100 series General-purpose I/O Unit support"
depends on CPU_VR41XX
help
Say yes here to support the NEC VR4100 series General-purpose I/O Unit.
config GPIO_VX855
tristate "VIA VX855/VX875 GPIO"
depends on (X86 || COMPILE_TEST) && PCI
@ -829,11 +824,24 @@ endmenu
menu "Port-mapped I/O GPIO drivers"
depends on X86 # Unconditional I/O space access
config GPIO_I8255
tristate
help
Enables support for the i8255 interface library functions. The i8255
interface library provides functions to facilitate communication with
interfaces compatible with the venerable Intel 8255 Programmable
Peripheral Interface (PPI). The Intel 8255 PPI chip was first released
in the early 1970s but compatible interfaces are nowadays typically
found embedded in larger VLSI processing chips and FPGA components.
If built as a module its name will be gpio-i8255.
config GPIO_104_DIO_48E
tristate "ACCES 104-DIO-48E GPIO support"
depends on PC104
select ISA_BUS_API
select GPIOLIB_IRQCHIP
select GPIO_I8255
help
Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E,
104-DIO-24E). The base port addresses for the devices may be
@ -857,6 +865,7 @@ config GPIO_104_IDI_48
depends on PC104
select ISA_BUS_API
select GPIOLIB_IRQCHIP
select GPIO_I8255
help
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for
@ -877,6 +886,7 @@ config GPIO_GPIO_MM
tristate "Diamond Systems GPIO-MM GPIO support"
depends on PC104
select ISA_BUS_API
select GPIO_I8255
help
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.

View File

@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o
obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o
obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
obj-$(CONFIG_GPIO_I8255) += gpio-i8255.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
@ -169,7 +170,6 @@ obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o
obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o
obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o

View File

@ -6,8 +6,7 @@
* This driver supports the following ACCES devices: 104-DIO-48E and
* 104-DIO-24E.
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@ -20,6 +19,11 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include "gpio-i8255.h"
MODULE_IMPORT_NS(I8255);
#define DIO48E_EXTENT 16
#define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT)
@ -33,34 +37,54 @@ static unsigned int irq[MAX_NUM_DIO48E];
module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
#define DIO48E_NUM_PPI 2
/**
* struct dio48e_reg - device register structure
* @ppi: Programmable Peripheral Interface groups
* @enable_buffer: Enable/Disable Buffer groups
* @unused1: Unused
* @enable_interrupt: Write: Enable Interrupt
* Read: Disable Interrupt
* @unused2: Unused
* @enable_counter: Write: Enable Counter/Timer Addressing
* Read: Disable Counter/Timer Addressing
* @unused3: Unused
* @clear_interrupt: Clear Interrupt
*/
struct dio48e_reg {
struct i8255 ppi[DIO48E_NUM_PPI];
u8 enable_buffer[DIO48E_NUM_PPI];
u8 unused1;
u8 enable_interrupt;
u8 unused2;
u8 enable_counter;
u8 unused3;
u8 clear_interrupt;
};
/**
* struct dio48e_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @io_state: bit I/O state (whether bit is set to input or output)
* @out_state: output bits state
* @control: Control registers state
* @lock: synchronization lock to prevent I/O race conditions
* @base: base port address of the GPIO device
* @irq_mask: I/O bits affected by interrupts
* @chip: instance of the gpio_chip
* @ppi_state: PPI device states
* @lock: synchronization lock to prevent I/O race conditions
* @reg: I/O address offset for the device registers
* @irq_mask: I/O bits affected by interrupts
*/
struct dio48e_gpio {
struct gpio_chip chip;
unsigned char io_state[6];
unsigned char out_state[6];
unsigned char control[2];
struct i8255_state ppi_state[DIO48E_NUM_PPI];
raw_spinlock_t lock;
void __iomem *base;
struct dio48e_reg __iomem *reg;
unsigned char irq_mask;
};
static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned int port = offset / 8;
const unsigned int mask = BIT(offset % 8);
if (dio48egpio->io_state[port] & mask)
return GPIO_LINE_DIRECTION_IN;
if (i8255_get_direction(dio48egpio->ppi_state, offset))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
}
@ -68,38 +92,9 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset
static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned int io_port = offset / 8;
const unsigned int control_port = io_port / 3;
void __iomem *const control_addr = dio48egpio->base + 3 + control_port * 4;
unsigned long flags;
unsigned int control;
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
/* Check if configuring Port C */
if (io_port == 2 || io_port == 5) {
/* Port C can be configured by nibble */
if (offset % 8 > 3) {
dio48egpio->io_state[io_port] |= 0xF0;
dio48egpio->control[control_port] |= BIT(3);
} else {
dio48egpio->io_state[io_port] |= 0x0F;
dio48egpio->control[control_port] |= BIT(0);
}
} else {
dio48egpio->io_state[io_port] |= 0xFF;
if (io_port == 0 || io_port == 3)
dio48egpio->control[control_port] |= BIT(4);
else
dio48egpio->control[control_port] |= BIT(1);
}
control = BIT(7) | dio48egpio->control[control_port];
iowrite8(control, control_addr);
control &= ~BIT(7);
iowrite8(control, control_addr);
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state,
offset);
return 0;
}
@ -108,48 +103,9 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off
int value)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned int io_port = offset / 8;
const unsigned int control_port = io_port / 3;
const unsigned int mask = BIT(offset % 8);
void __iomem *const control_addr = dio48egpio->base + 3 + control_port * 4;
const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
unsigned long flags;
unsigned int control;
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
/* Check if configuring Port C */
if (io_port == 2 || io_port == 5) {
/* Port C can be configured by nibble */
if (offset % 8 > 3) {
dio48egpio->io_state[io_port] &= 0x0F;
dio48egpio->control[control_port] &= ~BIT(3);
} else {
dio48egpio->io_state[io_port] &= 0xF0;
dio48egpio->control[control_port] &= ~BIT(0);
}
} else {
dio48egpio->io_state[io_port] &= 0x00;
if (io_port == 0 || io_port == 3)
dio48egpio->control[control_port] &= ~BIT(4);
else
dio48egpio->control[control_port] &= ~BIT(1);
}
if (value)
dio48egpio->out_state[io_port] |= mask;
else
dio48egpio->out_state[io_port] &= ~mask;
control = BIT(7) | dio48egpio->control[control_port];
iowrite8(control, control_addr);
iowrite8(dio48egpio->out_state[io_port], dio48egpio->base + out_port);
control &= ~BIT(7);
iowrite8(control, control_addr);
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state,
offset, value);
return 0;
}
@ -157,47 +113,16 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off
static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned int port = offset / 8;
const unsigned int mask = BIT(offset % 8);
const unsigned int in_port = (port > 2) ? port + 1 : port;
unsigned long flags;
unsigned int port_state;
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
/* ensure that GPIO is set for input */
if (!(dio48egpio->io_state[port] & mask)) {
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
return -EINVAL;
}
port_state = ioread8(dio48egpio->base + in_port);
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
return !!(port_state & mask);
return i8255_get(dio48egpio->reg->ppi, offset);
}
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
void __iomem *port_addr;
unsigned long port_state;
/* clear bits array to a clean slate */
bitmap_zero(bits, chip->ngpio);
for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
port_addr = dio48egpio->base + ports[offset / 8];
port_state = ioread8(port_addr) & gpio_mask;
bitmap_set_value8(bits, port_state, offset);
}
i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio);
return 0;
}
@ -205,49 +130,17 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
const unsigned int port = offset / 8;
const unsigned int mask = BIT(offset % 8);
const unsigned int out_port = (port > 2) ? port + 1 : port;
unsigned long flags;
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
if (value)
dio48egpio->out_state[port] |= mask;
else
dio48egpio->out_state[port] &= ~mask;
iowrite8(dio48egpio->out_state[port], dio48egpio->base + out_port);
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value);
}
static void dio48e_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
size_t index;
void __iomem *port_addr;
unsigned long bitmask;
unsigned long flags;
for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
index = offset / 8;
port_addr = dio48egpio->base + ports[index];
bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
/* update output state data and set device gpio register */
dio48egpio->out_state[index] &= ~gpio_mask;
dio48egpio->out_state[index] |= bitmask;
iowrite8(dio48egpio->out_state[index], port_addr);
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
}
i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask,
bits, chip->ngpio);
}
static void dio48e_irq_ack(struct irq_data *data)
@ -274,7 +167,7 @@ static void dio48e_irq_mask(struct irq_data *data)
if (!dio48egpio->irq_mask)
/* disable interrupts */
ioread8(dio48egpio->base + 0xB);
ioread8(&dio48egpio->reg->enable_interrupt);
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
}
@ -294,8 +187,8 @@ static void dio48e_irq_unmask(struct irq_data *data)
if (!dio48egpio->irq_mask) {
/* enable interrupts */
iowrite8(0x00, dio48egpio->base + 0xF);
iowrite8(0x00, dio48egpio->base + 0xB);
iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
iowrite8(0x00, &dio48egpio->reg->enable_interrupt);
}
if (offset == 19)
@ -341,7 +234,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
raw_spin_lock(&dio48egpio->lock);
iowrite8(0x00, dio48egpio->base + 0xF);
iowrite8(0x00, &dio48egpio->reg->clear_interrupt);
raw_spin_unlock(&dio48egpio->lock);
@ -373,11 +266,26 @@ static int dio48e_irq_init_hw(struct gpio_chip *gc)
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc);
/* Disable IRQ by default */
ioread8(dio48egpio->base + 0xB);
ioread8(&dio48egpio->reg->enable_interrupt);
return 0;
}
static void dio48e_init_ppi(struct i8255 __iomem *const ppi,
struct i8255_state *const ppi_state)
{
const unsigned long ngpio = 24;
const unsigned long mask = GENMASK(ngpio - 1, 0);
const unsigned long bits = 0;
unsigned long i;
/* Initialize all GPIO to output 0 */
for (i = 0; i < DIO48E_NUM_PPI; i++) {
i8255_mode0_output(&ppi[i]);
i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
}
}
static int dio48e_probe(struct device *dev, unsigned int id)
{
struct dio48e_gpio *dio48egpio;
@ -395,8 +303,8 @@ static int dio48e_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
dio48egpio->base = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
if (!dio48egpio->base)
dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
if (!dio48egpio->reg)
return -ENOMEM;
dio48egpio->chip.label = name;
@ -425,17 +333,8 @@ static int dio48e_probe(struct device *dev, unsigned int id)
raw_spin_lock_init(&dio48egpio->lock);
/* initialize all GPIO as output */
iowrite8(0x80, dio48egpio->base + 3);
iowrite8(0x00, dio48egpio->base);
iowrite8(0x00, dio48egpio->base + 1);
iowrite8(0x00, dio48egpio->base + 2);
iowrite8(0x00, dio48egpio->base + 3);
iowrite8(0x80, dio48egpio->base + 7);
iowrite8(0x00, dio48egpio->base + 4);
iowrite8(0x00, dio48egpio->base + 5);
iowrite8(0x00, dio48egpio->base + 6);
iowrite8(0x00, dio48egpio->base + 7);
i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI);
dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state);
err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio);
if (err) {

View File

@ -6,8 +6,7 @@
* This driver supports the following ACCES devices: 104-IDI-48A,
* 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@ -20,6 +19,11 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include "gpio-i8255.h"
MODULE_IMPORT_NS(I8255);
#define IDI_48_EXTENT 8
#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
@ -33,73 +37,62 @@ static unsigned int irq[MAX_NUM_IDI_48];
module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
/**
* struct idi_48_reg - device register structure
* @port0: Port 0 Inputs
* @unused: Unused
* @port1: Port 1 Inputs
* @irq: Read: IRQ Status Register/IRQ Clear
* Write: IRQ Enable/Disable
*/
struct idi_48_reg {
u8 port0[3];
u8 unused;
u8 port1[3];
u8 irq;
};
/**
* struct idi_48_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @ack_lock: synchronization lock to prevent IRQ handler race conditions
* @irq_mask: input bits affected by interrupts
* @base: base port address of the GPIO device
* @reg: I/O address offset for the device registers
* @cos_enb: Change-Of-State IRQ enable boundaries mask
*/
struct idi_48_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
spinlock_t ack_lock;
spinlock_t lock;
unsigned char irq_mask[6];
void __iomem *base;
struct idi_48_reg __iomem *reg;
unsigned char cos_enb;
};
static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
return GPIO_LINE_DIRECTION_IN;
}
static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
return 0;
}
static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
unsigned i;
static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 };
void __iomem *port_addr;
unsigned mask;
void __iomem *const ppi = idi48gpio->reg;
for (i = 0; i < 48; i += 8)
if (offset < i + 8) {
port_addr = idi48gpio->base + register_offset[i / 8];
mask = BIT(offset - i);
return !!(ioread8(port_addr) & mask);
}
/* The following line should never execute since offset < 48 */
return 0;
return i8255_get(ppi, offset);
}
static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
void __iomem *port_addr;
unsigned long port_state;
void __iomem *const ppi = idi48gpio->reg;
/* clear bits array to a clean slate */
bitmap_zero(bits, chip->ngpio);
for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
port_addr = idi48gpio->base + ports[offset / 8];
port_state = ioread8(port_addr) & gpio_mask;
bitmap_set_value8(bits, port_state, offset);
}
i8255_get_multiple(ppi, mask, bits, chip->ngpio);
return 0;
}
@ -112,67 +105,56 @@ static void idi_48_irq_mask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
const unsigned offset = irqd_to_hwirq(data);
unsigned i;
unsigned mask;
unsigned boundary;
const unsigned int offset = irqd_to_hwirq(data);
const unsigned long boundary = offset / 8;
const unsigned long mask = BIT(offset % 8);
unsigned long flags;
for (i = 0; i < 48; i += 8)
if (offset < i + 8) {
mask = BIT(offset - i);
boundary = i / 8;
spin_lock_irqsave(&idi48gpio->lock, flags);
idi48gpio->irq_mask[boundary] &= ~mask;
idi48gpio->irq_mask[boundary] &= ~mask;
if (!idi48gpio->irq_mask[boundary]) {
idi48gpio->cos_enb &= ~BIT(boundary);
/* Exit early if there are still input lines with IRQ unmasked */
if (idi48gpio->irq_mask[boundary])
goto exit;
raw_spin_lock_irqsave(&idi48gpio->lock, flags);
idi48gpio->cos_enb &= ~BIT(boundary);
iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7);
iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
}
return;
}
exit:
spin_unlock_irqrestore(&idi48gpio->lock, flags);
}
static void idi_48_irq_unmask(struct irq_data *data)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
const unsigned offset = irqd_to_hwirq(data);
unsigned i;
unsigned mask;
unsigned boundary;
unsigned prev_irq_mask;
const unsigned int offset = irqd_to_hwirq(data);
const unsigned long boundary = offset / 8;
const unsigned long mask = BIT(offset % 8);
unsigned int prev_irq_mask;
unsigned long flags;
for (i = 0; i < 48; i += 8)
if (offset < i + 8) {
mask = BIT(offset - i);
boundary = i / 8;
prev_irq_mask = idi48gpio->irq_mask[boundary];
spin_lock_irqsave(&idi48gpio->lock, flags);
idi48gpio->irq_mask[boundary] |= mask;
prev_irq_mask = idi48gpio->irq_mask[boundary];
if (!prev_irq_mask) {
idi48gpio->cos_enb |= BIT(boundary);
idi48gpio->irq_mask[boundary] |= mask;
raw_spin_lock_irqsave(&idi48gpio->lock, flags);
/* Exit early if IRQ was already unmasked for this boundary */
if (prev_irq_mask)
goto exit;
iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7);
idi48gpio->cos_enb |= BIT(boundary);
raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
}
iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq);
return;
}
exit:
spin_unlock_irqrestore(&idi48gpio->lock, flags);
}
static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type)
static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type)
{
/* The only valid irq types are none and both-edges */
if (flow_type != IRQ_TYPE_NONE &&
@ -200,17 +182,13 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
unsigned long gpio;
struct gpio_chip *const chip = &idi48gpio->chip;
spin_lock(&idi48gpio->ack_lock);
spin_lock(&idi48gpio->lock);
raw_spin_lock(&idi48gpio->lock);
cos_status = ioread8(idi48gpio->base + 7);
raw_spin_unlock(&idi48gpio->lock);
cos_status = ioread8(&idi48gpio->reg->irq);
/* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
if (cos_status & BIT(6)) {
spin_unlock(&idi48gpio->ack_lock);
spin_unlock(&idi48gpio->lock);
return IRQ_NONE;
}
@ -228,7 +206,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
}
}
spin_unlock(&idi48gpio->ack_lock);
spin_unlock(&idi48gpio->lock);
return IRQ_HANDLED;
}
@ -250,8 +228,8 @@ static int idi_48_irq_init_hw(struct gpio_chip *gc)
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
/* Disable IRQ by default */
iowrite8(0, idi48gpio->base + 7);
ioread8(idi48gpio->base + 7);
iowrite8(0, &idi48gpio->reg->irq);
ioread8(&idi48gpio->reg->irq);
return 0;
}
@ -273,8 +251,8 @@ static int idi_48_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
idi48gpio->base = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
if (!idi48gpio->base)
idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
if (!idi48gpio->reg)
return -ENOMEM;
idi48gpio->chip.label = name;
@ -298,8 +276,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
girq->handler = handle_edge_irq;
girq->init_hw = idi_48_irq_init_hw;
raw_spin_lock_init(&idi48gpio->lock);
spin_lock_init(&idi48gpio->ack_lock);
spin_lock_init(&idi48gpio->lock);
err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
if (err) {

View File

@ -6,7 +6,7 @@
* This driver supports the following ACCES devices: 104-IDIO-16,
* 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
*/
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#define IDIO_16_EXTENT 8
#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
@ -32,19 +33,42 @@ static unsigned int irq[MAX_NUM_IDIO_16];
module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
/**
* struct idio_16_reg - device registers structure
* @out0_7: Read: N/A
* Write: FET Drive Outputs 0-7
* @in0_7: Read: Isolated Inputs 0-7
* Write: Clear Interrupt
* @irq_ctl: Read: Enable IRQ
* Write: Disable IRQ
* @unused: N/A
* @out8_15: Read: N/A
* Write: FET Drive Outputs 8-15
* @in8_15: Read: Isolated Inputs 8-15
* Write: N/A
*/
struct idio_16_reg {
u8 out0_7;
u8 in0_7;
u8 irq_ctl;
u8 unused;
u8 out8_15;
u8 in8_15;
};
/**
* struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts
* @base: base port address of the GPIO device
* @reg: I/O address offset for the device registers
* @out_state: output bits state
*/
struct idio_16_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
unsigned long irq_mask;
void __iomem *base;
struct idio_16_reg __iomem *reg;
unsigned int out_state;
};
@ -79,9 +103,9 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
return -EINVAL;
if (offset < 24)
return !!(ioread8(idio16gpio->base + 1) & mask);
return !!(ioread8(&idio16gpio->reg->in0_7) & mask);
return !!(ioread8(idio16gpio->base + 5) & (mask>>8));
return !!(ioread8(&idio16gpio->reg->in8_15) & (mask>>8));
}
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
@ -91,9 +115,9 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
*bits = 0;
if (*mask & GENMASK(23, 16))
*bits |= (unsigned long)ioread8(idio16gpio->base + 1) << 16;
*bits |= (unsigned long)ioread8(&idio16gpio->reg->in0_7) << 16;
if (*mask & GENMASK(31, 24))
*bits |= (unsigned long)ioread8(idio16gpio->base + 5) << 24;
*bits |= (unsigned long)ioread8(&idio16gpio->reg->in8_15) << 24;
return 0;
}
@ -116,9 +140,9 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
idio16gpio->out_state &= ~mask;
if (offset > 7)
iowrite8(idio16gpio->out_state >> 8, idio16gpio->base + 4);
iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
else
iowrite8(idio16gpio->out_state, idio16gpio->base);
iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@ -135,9 +159,9 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
idio16gpio->out_state |= *mask & *bits;
if (*mask & 0xFF)
iowrite8(idio16gpio->out_state, idio16gpio->base);
iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
if ((*mask >> 8) & 0xFF)
iowrite8(idio16gpio->out_state >> 8, idio16gpio->base + 4);
iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@ -158,7 +182,7 @@ static void idio_16_irq_mask(struct irq_data *data)
if (!idio16gpio->irq_mask) {
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
iowrite8(0, idio16gpio->base + 2);
iowrite8(0, &idio16gpio->reg->irq_ctl);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@ -177,7 +201,7 @@ static void idio_16_irq_unmask(struct irq_data *data)
if (!prev_irq_mask) {
raw_spin_lock_irqsave(&idio16gpio->lock, flags);
ioread8(idio16gpio->base + 2);
ioread8(&idio16gpio->reg->irq_ctl);
raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
}
@ -212,7 +236,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
raw_spin_lock(&idio16gpio->lock);
iowrite8(0, idio16gpio->base + 1);
iowrite8(0, &idio16gpio->reg->in0_7);
raw_spin_unlock(&idio16gpio->lock);
@ -232,8 +256,8 @@ static int idio_16_irq_init_hw(struct gpio_chip *gc)
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
/* Disable IRQ by default */
iowrite8(0, idio16gpio->base + 2);
iowrite8(0, idio16gpio->base + 1);
iowrite8(0, &idio16gpio->reg->irq_ctl);
iowrite8(0, &idio16gpio->reg->in0_7);
return 0;
}
@ -255,8 +279,8 @@ static int idio_16_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
idio16gpio->base = devm_ioport_map(dev, base[id], IDIO_16_EXTENT);
if (!idio16gpio->base)
idio16gpio->reg = devm_ioport_map(dev, base[id], IDIO_16_EXTENT);
if (!idio16gpio->reg)
return -ENOMEM;
idio16gpio->chip.label = name;

View File

@ -5,15 +5,17 @@
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
*/
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/gpio/driver.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#define MMIO_74XX_DIR_IN (0 << 8)
#define MMIO_74XX_DIR_OUT (1 << 8)
#define MMIO_74XX_BIT_CNT(x) ((x) & 0xff)
#define MMIO_74XX_DIR_IN BIT(8)
#define MMIO_74XX_DIR_OUT BIT(9)
#define MMIO_74XX_BIT_CNT(x) ((x) & GENMASK(7, 0))
struct mmio_74xx_gpio_priv {
struct gpio_chip gc;
@ -87,7 +89,10 @@ static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc);
return (priv->flags & MMIO_74XX_DIR_OUT) ? -ENOTSUPP : 0;
if (priv->flags & MMIO_74XX_DIR_IN)
return 0;
return -ENOTSUPP;
}
static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
@ -112,7 +117,7 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->flags = (uintptr_t)of_device_get_match_data(&pdev->dev);
priv->flags = (uintptr_t)device_get_match_data(&pdev->dev);
dat = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dat))

View File

@ -6,8 +6,9 @@
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/property.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@ -485,22 +486,17 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios,
return 0;
}
static int adnp_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int adnp_i2c_probe(struct i2c_client *client)
{
struct device_node *np = client->dev.of_node;
struct device *dev = &client->dev;
struct adnp *adnp;
u32 num_gpios;
int err;
err = of_property_read_u32(np, "nr-gpios", &num_gpios);
err = device_property_read_u32(dev, "nr-gpios", &num_gpios);
if (err < 0)
return err;
client->irq = irq_of_parse_and_map(np, 0);
if (!client->irq)
return -EPROBE_DEFER;
adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL);
if (!adnp)
return -ENOMEM;
@ -508,8 +504,7 @@ static int adnp_i2c_probe(struct i2c_client *client,
mutex_init(&adnp->i2c_lock);
adnp->client = client;
err = adnp_gpio_setup(adnp, num_gpios,
of_property_read_bool(np, "interrupt-controller"));
err = adnp_gpio_setup(adnp, num_gpios, device_property_read_bool(dev, "interrupt-controller"));
if (err)
return err;
@ -535,7 +530,7 @@ static struct i2c_driver adnp_i2c_driver = {
.name = "gpio-adnp",
.of_match_table = adnp_of_match,
},
.probe = adnp_i2c_probe,
.probe_new = adnp_i2c_probe,
.id_table = adnp_i2c_id,
};
module_i2c_driver(adnp_i2c_driver);

View File

@ -6,20 +6,18 @@
* Copyright 2009-2010 Analog Devices Inc.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of_device.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_data/adp5588.h>
#define DRV_NAME "adp5588-gpio"
/*
* Early pre 4.0 Silicon required to delay readout by at least 25ms,
* since the Event Counter Register updated 25ms after the interrupt
@ -422,23 +420,21 @@ static int adp5588_gpio_remove(struct i2c_client *client)
}
static const struct i2c_device_id adp5588_gpio_id[] = {
{DRV_NAME, 0},
{ "adp5588-gpio" },
{}
};
MODULE_DEVICE_TABLE(i2c, adp5588_gpio_id);
#ifdef CONFIG_OF
static const struct of_device_id adp5588_gpio_of_id[] = {
{ .compatible = "adi," DRV_NAME, },
{},
{ .compatible = "adi,adp5588-gpio" },
{}
};
MODULE_DEVICE_TABLE(of, adp5588_gpio_of_id);
#endif
static struct i2c_driver adp5588_gpio_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(adp5588_gpio_of_id),
.name = "adp5588-gpio",
.of_match_table = adp5588_gpio_of_id,
},
.probe_new = adp5588_gpio_probe,
.remove = adp5588_gpio_remove,

View File

@ -375,12 +375,7 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
{
struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
struct brcmstb_gpio_bank *bank;
int offset, ret = 0, virq;
if (!priv) {
dev_err(&pdev->dev, "called %s without drvdata!\n", __func__);
return -EFAULT;
}
int offset, virq;
if (priv->parent_irq > 0)
irq_set_chained_handler_and_data(priv->parent_irq, NULL, NULL);
@ -401,7 +396,7 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
list_for_each_entry(bank, &priv->bank_list, node)
gpiochip_remove(&bank->gc);
return ret;
return 0;
}
static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,

View File

@ -22,6 +22,7 @@
#include <linux/platform_data/gpio-davinci.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/spinlock.h>
#include <linux/pm_runtime.h>
#include <asm-generic/gpio.h>
@ -62,6 +63,8 @@ struct davinci_gpio_controller {
void __iomem *regs[MAX_REGS_BANKS];
int gpio_unbanked;
int irqs[MAX_INT_PER_BANK];
struct davinci_gpio_regs context[MAX_REGS_BANKS];
u32 binten_context;
};
static inline u32 __gpio_mask(unsigned gpio)
@ -622,6 +625,85 @@ done:
return 0;
}
static void davinci_gpio_save_context(struct davinci_gpio_controller *chips,
u32 nbank)
{
struct davinci_gpio_regs __iomem *g;
struct davinci_gpio_regs *context;
u32 bank;
void __iomem *base;
base = chips->regs[0] - offset_array[0];
chips->binten_context = readl_relaxed(base + BINTEN);
for (bank = 0; bank < nbank; bank++) {
g = chips->regs[bank];
context = &chips->context[bank];
context->dir = readl_relaxed(&g->dir);
context->set_data = readl_relaxed(&g->set_data);
context->set_rising = readl_relaxed(&g->set_rising);
context->set_falling = readl_relaxed(&g->set_falling);
}
/* Clear Bank interrupt enable bit */
writel_relaxed(0, base + BINTEN);
/* Clear all interrupt status registers */
writel_relaxed(GENMASK(31, 0), &g->intstat);
}
static void davinci_gpio_restore_context(struct davinci_gpio_controller *chips,
u32 nbank)
{
struct davinci_gpio_regs __iomem *g;
struct davinci_gpio_regs *context;
u32 bank;
void __iomem *base;
base = chips->regs[0] - offset_array[0];
if (readl_relaxed(base + BINTEN) != chips->binten_context)
writel_relaxed(chips->binten_context, base + BINTEN);
for (bank = 0; bank < nbank; bank++) {
g = chips->regs[bank];
context = &chips->context[bank];
if (readl_relaxed(&g->dir) != context->dir)
writel_relaxed(context->dir, &g->dir);
if (readl_relaxed(&g->set_data) != context->set_data)
writel_relaxed(context->set_data, &g->set_data);
if (readl_relaxed(&g->set_rising) != context->set_rising)
writel_relaxed(context->set_rising, &g->set_rising);
if (readl_relaxed(&g->set_falling) != context->set_falling)
writel_relaxed(context->set_falling, &g->set_falling);
}
}
static int davinci_gpio_suspend(struct device *dev)
{
struct davinci_gpio_controller *chips = dev_get_drvdata(dev);
struct davinci_gpio_platform_data *pdata = dev_get_platdata(dev);
u32 nbank = DIV_ROUND_UP(pdata->ngpio, 32);
davinci_gpio_save_context(chips, nbank);
return 0;
}
static int davinci_gpio_resume(struct device *dev)
{
struct davinci_gpio_controller *chips = dev_get_drvdata(dev);
struct davinci_gpio_platform_data *pdata = dev_get_platdata(dev);
u32 nbank = DIV_ROUND_UP(pdata->ngpio, 32);
davinci_gpio_restore_context(chips, nbank);
return 0;
}
DEFINE_SIMPLE_DEV_PM_OPS(davinci_gpio_dev_pm_ops, davinci_gpio_suspend,
davinci_gpio_resume);
static const struct of_device_id davinci_gpio_ids[] = {
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
{ .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip},
@ -634,6 +716,7 @@ static struct platform_driver davinci_gpio_driver = {
.probe = davinci_gpio_probe,
.driver = {
.name = "davinci_gpio",
.pm = pm_sleep_ptr(&davinci_gpio_dev_pm_ops),
.of_match_table = of_match_ptr(davinci_gpio_ids),
},
};

View File

@ -6,8 +6,6 @@
* This driver supports the following Diamond Systems devices: GPIO-MM and
* GPIO-MM-12.
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@ -17,7 +15,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include "gpio-i8255.h"
MODULE_IMPORT_NS(I8255);
#define GPIOMM_EXTENT 8
#define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
@ -27,32 +28,26 @@ static unsigned int num_gpiomm;
module_param_hw_array(base, uint, ioport, &num_gpiomm, 0);
MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
#define GPIOMM_NUM_PPI 2
/**
* struct gpiomm_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @io_state: bit I/O state (whether bit is set to input or output)
* @out_state: output bits state
* @control: Control registers state
* @lock: synchronization lock to prevent I/O race conditions
* @base: base port address of the GPIO device
* @chip: instance of the gpio_chip
* @ppi_state: Programmable Peripheral Interface group states
* @ppi: Programmable Peripheral Interface groups
*/
struct gpiomm_gpio {
struct gpio_chip chip;
unsigned char io_state[6];
unsigned char out_state[6];
unsigned char control[2];
spinlock_t lock;
void __iomem *base;
struct i8255_state ppi_state[GPIOMM_NUM_PPI];
struct i8255 __iomem *ppi;
};
static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
const unsigned int port = offset / 8;
const unsigned int mask = BIT(offset % 8);
if (gpiommgpio->io_state[port] & mask)
if (i8255_get_direction(gpiommgpio->ppi_state, offset))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
@ -62,35 +57,8 @@ static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
const unsigned int io_port = offset / 8;
const unsigned int control_port = io_port / 3;
unsigned long flags;
unsigned int control;
spin_lock_irqsave(&gpiommgpio->lock, flags);
/* Check if configuring Port C */
if (io_port == 2 || io_port == 5) {
/* Port C can be configured by nibble */
if (offset % 8 > 3) {
gpiommgpio->io_state[io_port] |= 0xF0;
gpiommgpio->control[control_port] |= BIT(3);
} else {
gpiommgpio->io_state[io_port] |= 0x0F;
gpiommgpio->control[control_port] |= BIT(0);
}
} else {
gpiommgpio->io_state[io_port] |= 0xFF;
if (io_port == 0 || io_port == 3)
gpiommgpio->control[control_port] |= BIT(4);
else
gpiommgpio->control[control_port] |= BIT(1);
}
control = BIT(7) | gpiommgpio->control[control_port];
iowrite8(control, gpiommgpio->base + 3 + control_port*4);
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset);
return 0;
}
@ -99,44 +67,9 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
const unsigned int io_port = offset / 8;
const unsigned int control_port = io_port / 3;
const unsigned int mask = BIT(offset % 8);
const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
unsigned long flags;
unsigned int control;
spin_lock_irqsave(&gpiommgpio->lock, flags);
/* Check if configuring Port C */
if (io_port == 2 || io_port == 5) {
/* Port C can be configured by nibble */
if (offset % 8 > 3) {
gpiommgpio->io_state[io_port] &= 0x0F;
gpiommgpio->control[control_port] &= ~BIT(3);
} else {
gpiommgpio->io_state[io_port] &= 0xF0;
gpiommgpio->control[control_port] &= ~BIT(0);
}
} else {
gpiommgpio->io_state[io_port] &= 0x00;
if (io_port == 0 || io_port == 3)
gpiommgpio->control[control_port] &= ~BIT(4);
else
gpiommgpio->control[control_port] &= ~BIT(1);
}
if (value)
gpiommgpio->out_state[io_port] |= mask;
else
gpiommgpio->out_state[io_port] &= ~mask;
control = BIT(7) | gpiommgpio->control[control_port];
iowrite8(control, gpiommgpio->base + 3 + control_port*4);
iowrite8(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset,
value);
return 0;
}
@ -144,47 +77,16 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
const unsigned int port = offset / 8;
const unsigned int mask = BIT(offset % 8);
const unsigned int in_port = (port > 2) ? port + 1 : port;
unsigned long flags;
unsigned int port_state;
spin_lock_irqsave(&gpiommgpio->lock, flags);
/* ensure that GPIO is set for input */
if (!(gpiommgpio->io_state[port] & mask)) {
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
return -EINVAL;
}
port_state = ioread8(gpiommgpio->base + in_port);
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
return !!(port_state & mask);
return i8255_get(gpiommgpio->ppi, offset);
}
static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
void __iomem *port_addr;
unsigned long port_state;
/* clear bits array to a clean slate */
bitmap_zero(bits, chip->ngpio);
for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
port_addr = gpiommgpio->base + ports[offset / 8];
port_state = ioread8(port_addr) & gpio_mask;
bitmap_set_value8(bits, port_state, offset);
}
i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio);
return 0;
}
@ -193,49 +95,17 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
const unsigned int port = offset / 8;
const unsigned int mask = BIT(offset % 8);
const unsigned int out_port = (port > 2) ? port + 1 : port;
unsigned long flags;
spin_lock_irqsave(&gpiommgpio->lock, flags);
if (value)
gpiommgpio->out_state[port] |= mask;
else
gpiommgpio->out_state[port] &= ~mask;
iowrite8(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value);
}
static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
size_t index;
void __iomem *port_addr;
unsigned long bitmask;
unsigned long flags;
for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
index = offset / 8;
port_addr = gpiommgpio->base + ports[index];
bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
spin_lock_irqsave(&gpiommgpio->lock, flags);
/* update output state data and set device gpio register */
gpiommgpio->out_state[index] &= ~gpio_mask;
gpiommgpio->out_state[index] |= bitmask;
iowrite8(gpiommgpio->out_state[index], port_addr);
spin_unlock_irqrestore(&gpiommgpio->lock, flags);
}
i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits,
chip->ngpio);
}
#define GPIOMM_NGPIO 48
@ -250,6 +120,21 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = {
"Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
};
static void gpiomm_init_dio(struct i8255 __iomem *const ppi,
struct i8255_state *const ppi_state)
{
const unsigned long ngpio = 24;
const unsigned long mask = GENMASK(ngpio - 1, 0);
const unsigned long bits = 0;
unsigned long i;
/* Initialize all GPIO to output 0 */
for (i = 0; i < GPIOMM_NUM_PPI; i++) {
i8255_mode0_output(&ppi[i]);
i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio);
}
}
static int gpiomm_probe(struct device *dev, unsigned int id)
{
struct gpiomm_gpio *gpiommgpio;
@ -266,8 +151,8 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
gpiommgpio->base = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
if (!gpiommgpio->base)
gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT);
if (!gpiommgpio->ppi)
return -ENOMEM;
gpiommgpio->chip.label = name;
@ -284,7 +169,8 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
gpiommgpio->chip.set = gpiomm_gpio_set;
gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
spin_lock_init(&gpiommgpio->lock);
i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI);
gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state);
err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
if (err) {
@ -292,16 +178,6 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
return err;
}
/* initialize all GPIO as output */
iowrite8(0x80, gpiommgpio->base + 3);
iowrite8(0x00, gpiommgpio->base);
iowrite8(0x00, gpiommgpio->base + 1);
iowrite8(0x00, gpiommgpio->base + 2);
iowrite8(0x80, gpiommgpio->base + 7);
iowrite8(0x00, gpiommgpio->base + 4);
iowrite8(0x00, gpiommgpio->base + 5);
iowrite8(0x00, gpiommgpio->base + 6);
return 0;
}

287
drivers/gpio/gpio-i8255.c Normal file
View File

@ -0,0 +1,287 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Intel 8255 Programmable Peripheral Interface
* Copyright (C) 2022 William Breathitt Gray
*/
#include <linux/bitmap.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include "gpio-i8255.h"
#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0)
#define I8255_CONTROL_PORTB_DIRECTION BIT(1)
#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3)
#define I8255_CONTROL_PORTA_DIRECTION BIT(4)
#define I8255_CONTROL_MODE_SET BIT(7)
#define I8255_PORTA 0
#define I8255_PORTB 1
#define I8255_PORTC 2
static int i8255_get_port(struct i8255 __iomem *const ppi,
const unsigned long io_port, const unsigned long mask)
{
const unsigned long bank = io_port / 3;
const unsigned long ppi_port = io_port % 3;
return ioread8(&ppi[bank].port[ppi_port]) & mask;
}
static u8 i8255_direction_mask(const unsigned long offset)
{
const unsigned long port_offset = offset % 8;
const unsigned long io_port = offset / 8;
const unsigned long ppi_port = io_port % 3;
switch (ppi_port) {
case I8255_PORTA:
return I8255_CONTROL_PORTA_DIRECTION;
case I8255_PORTB:
return I8255_CONTROL_PORTB_DIRECTION;
case I8255_PORTC:
/* Port C can be configured by nibble */
if (port_offset >= 4)
return I8255_CONTROL_PORTC_UPPER_DIRECTION;
return I8255_CONTROL_PORTC_LOWER_DIRECTION;
default:
/* Should never reach this path */
return 0;
}
}
static void i8255_set_port(struct i8255 __iomem *const ppi,
struct i8255_state *const state,
const unsigned long io_port,
const unsigned long mask, const unsigned long bits)
{
const unsigned long bank = io_port / 3;
const unsigned long ppi_port = io_port % 3;
unsigned long flags;
unsigned long out_state;
spin_lock_irqsave(&state[bank].lock, flags);
out_state = ioread8(&ppi[bank].port[ppi_port]);
out_state = (out_state & ~mask) | (bits & mask);
iowrite8(out_state, &ppi[bank].port[ppi_port]);
spin_unlock_irqrestore(&state[bank].lock, flags);
}
/**
* i8255_direction_input - configure signal offset as input
* @ppi: Intel 8255 Programmable Peripheral Interface banks
* @state: devices states of the respective PPI banks
* @offset: signal offset to configure as input
*
* Configures a signal @offset as input for the respective Intel 8255
* Programmable Peripheral Interface (@ppi) banks. The @state control_state
* values are updated to reflect the new configuration.
*/
void i8255_direction_input(struct i8255 __iomem *const ppi,
struct i8255_state *const state,
const unsigned long offset)
{
const unsigned long io_port = offset / 8;
const unsigned long bank = io_port / 3;
unsigned long flags;
spin_lock_irqsave(&state[bank].lock, flags);
state[bank].control_state |= I8255_CONTROL_MODE_SET;
state[bank].control_state |= i8255_direction_mask(offset);
iowrite8(state[bank].control_state, &ppi[bank].control);
spin_unlock_irqrestore(&state[bank].lock, flags);
}
EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255);
/**
* i8255_direction_output - configure signal offset as output
* @ppi: Intel 8255 Programmable Peripheral Interface banks
* @state: devices states of the respective PPI banks
* @offset: signal offset to configure as output
* @value: signal value to output
*
* Configures a signal @offset as output for the respective Intel 8255
* Programmable Peripheral Interface (@ppi) banks and sets the respective signal
* output to the desired @value. The @state control_state values are updated to
* reflect the new configuration.
*/
void i8255_direction_output(struct i8255 __iomem *const ppi,
struct i8255_state *const state,
const unsigned long offset,
const unsigned long value)
{
const unsigned long io_port = offset / 8;
const unsigned long bank = io_port / 3;
unsigned long flags;
spin_lock_irqsave(&state[bank].lock, flags);
state[bank].control_state |= I8255_CONTROL_MODE_SET;
state[bank].control_state &= ~i8255_direction_mask(offset);
iowrite8(state[bank].control_state, &ppi[bank].control);
spin_unlock_irqrestore(&state[bank].lock, flags);
i8255_set(ppi, state, offset, value);
}
EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255);
/**
* i8255_get - get signal value at signal offset
* @ppi: Intel 8255 Programmable Peripheral Interface banks
* @offset: offset of signal to get
*
* Returns the signal value (0=low, 1=high) for the signal at @offset for the
* respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
*/
int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset)
{
const unsigned long io_port = offset / 8;
const unsigned long offset_mask = BIT(offset % 8);
return !!i8255_get_port(ppi, io_port, offset_mask);
}
EXPORT_SYMBOL_NS_GPL(i8255_get, I8255);
/**
* i8255_get_direction - get the I/O direction for a signal offset
* @state: devices states of the respective PPI banks
* @offset: offset of signal to get direction
*
* Returns the signal direction (0=output, 1=input) for the signal at @offset.
*/
int i8255_get_direction(const struct i8255_state *const state,
const unsigned long offset)
{
const unsigned long io_port = offset / 8;
const unsigned long bank = io_port / 3;
return !!(state[bank].control_state & i8255_direction_mask(offset));
}
EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255);
/**
* i8255_get_multiple - get multiple signal values at multiple signal offsets
* @ppi: Intel 8255 Programmable Peripheral Interface banks
* @mask: mask of signals to get
* @bits: bitmap to store signal values
* @ngpio: number of GPIO signals of the respective PPI banks
*
* Stores in @bits the values (0=low, 1=high) for the signals defined by @mask
* for the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
*/
void i8255_get_multiple(struct i8255 __iomem *const ppi,
const unsigned long *const mask,
unsigned long *const bits, const unsigned long ngpio)
{
unsigned long offset;
unsigned long port_mask;
unsigned long io_port;
unsigned long port_state;
bitmap_zero(bits, ngpio);
for_each_set_clump8(offset, port_mask, mask, ngpio) {
io_port = offset / 8;
port_state = i8255_get_port(ppi, io_port, port_mask);
bitmap_set_value8(bits, port_state, offset);
}
}
EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255);
/**
* i8255_mode0_output - configure all PPI ports to MODE 0 output mode
* @ppi: Intel 8255 Programmable Peripheral Interface bank
*
* Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to
* MODE 0 (Basic Input/Output) output mode.
*/
void i8255_mode0_output(struct i8255 __iomem *const ppi)
{
iowrite8(I8255_CONTROL_MODE_SET, &ppi->control);
}
EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255);
/**
* i8255_set - set signal value at signal offset
* @ppi: Intel 8255 Programmable Peripheral Interface banks
* @state: devices states of the respective PPI banks
* @offset: offset of signal to set
* @value: value of signal to set
*
* Assigns output @value for the signal at @offset for the respective Intel 8255
* Programmable Peripheral Interface (@ppi) banks.
*/
void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state,
const unsigned long offset, const unsigned long value)
{
const unsigned long io_port = offset / 8;
const unsigned long port_offset = offset % 8;
const unsigned long mask = BIT(port_offset);
const unsigned long bits = value << port_offset;
i8255_set_port(ppi, state, io_port, mask, bits);
}
EXPORT_SYMBOL_NS_GPL(i8255_set, I8255);
/**
* i8255_set_multiple - set signal values at multiple signal offsets
* @ppi: Intel 8255 Programmable Peripheral Interface banks
* @state: devices states of the respective PPI banks
* @mask: mask of signals to set
* @bits: bitmap of signal output values
* @ngpio: number of GPIO signals of the respective PPI banks
*
* Assigns output values defined by @bits for the signals defined by @mask for
* the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks.
*/
void i8255_set_multiple(struct i8255 __iomem *const ppi,
struct i8255_state *const state,
const unsigned long *const mask,
const unsigned long *const bits,
const unsigned long ngpio)
{
unsigned long offset;
unsigned long port_mask;
unsigned long io_port;
unsigned long value;
for_each_set_clump8(offset, port_mask, mask, ngpio) {
io_port = offset / 8;
value = bitmap_get_value8(bits, offset);
i8255_set_port(ppi, state, io_port, port_mask, value);
}
}
EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255);
/**
* i8255_state_init - initialize i8255_state structure
* @state: devices states of the respective PPI banks
* @nbanks: number of Intel 8255 Programmable Peripheral Interface banks
*
* Initializes the @state of each Intel 8255 Programmable Peripheral Interface
* bank for use in i8255 library functions.
*/
void i8255_state_init(struct i8255_state *const state,
const unsigned long nbanks)
{
unsigned long bank;
for (bank = 0; bank < nbanks; bank++)
spin_lock_init(&state[bank].lock);
}
EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255);
MODULE_AUTHOR("William Breathitt Gray");
MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface");
MODULE_LICENSE("GPL");

46
drivers/gpio/gpio-i8255.h Normal file
View File

@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright 2022 William Breathitt Gray */
#ifndef _I8255_H_
#define _I8255_H_
#include <linux/spinlock.h>
#include <linux/types.h>
/**
* struct i8255 - Intel 8255 register structure
* @port: Port A, B, and C
* @control: Control register
*/
struct i8255 {
u8 port[3];
u8 control;
};
/**
* struct i8255_state - Intel 8255 state structure
* @lock: synchronization lock for accessing device state
* @control_state: Control register state
*/
struct i8255_state {
spinlock_t lock;
u8 control_state;
};
void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state,
unsigned long offset);
void i8255_direction_output(struct i8255 __iomem *ppi,
struct i8255_state *state, unsigned long offset,
unsigned long value);
int i8255_get(struct i8255 __iomem *ppi, unsigned long offset);
int i8255_get_direction(const struct i8255_state *state, unsigned long offset);
void i8255_get_multiple(struct i8255 __iomem *ppi, const unsigned long *mask,
unsigned long *bits, unsigned long ngpio);
void i8255_mode0_output(struct i8255 __iomem *const ppi);
void i8255_set(struct i8255 __iomem *ppi, struct i8255_state *state,
unsigned long offset, unsigned long value);
void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *state,
const unsigned long *mask, const unsigned long *bits,
unsigned long ngpio);
void i8255_state_init(struct i8255_state *const state, unsigned long nbanks);
#endif /* _I8255_H_ */

View File

@ -42,7 +42,7 @@ struct lp3943_gpio {
u16 input_mask; /* 1 = GPIO is input direction, 0 = output */
};
static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
static int lp3943_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
@ -54,7 +54,7 @@ static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
return 0;
}
static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset)
static void lp3943_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
@ -72,7 +72,7 @@ static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset,
val << mux[offset].shift);
}
static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
@ -82,7 +82,7 @@ static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
}
static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio,
struct gpio_chip *chip, unsigned offset)
struct gpio_chip *chip, unsigned int offset)
{
u8 addr, read;
int err;
@ -107,7 +107,7 @@ static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio,
}
static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio,
struct gpio_chip *chip, unsigned offset)
struct gpio_chip *chip, unsigned int offset)
{
struct lp3943 *lp3943 = lp3943_gpio->lp3943;
const struct lp3943_reg_cfg *mux = lp3943->mux_cfg;
@ -128,7 +128,7 @@ static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio,
return -EINVAL;
}
static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
static int lp3943_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
@ -147,7 +147,7 @@ static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset);
}
static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static void lp3943_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);
u8 data;
@ -160,7 +160,7 @@ static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
lp3943_gpio_set_mode(lp3943_gpio, offset, data);
}
static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip);

View File

@ -121,12 +121,14 @@ static int pca9570_probe(struct i2c_client *client)
static const struct i2c_device_id pca9570_id_table[] = {
{ "pca9570", 4 },
{ "pca9571", 8 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
static const struct of_device_id pca9570_of_match_table[] = {
{ .compatible = "nxp,pca9570", .data = (void *)4 },
{ .compatible = "nxp,pca9571", .data = (void *)8 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pca9570_of_match_table);

View File

@ -37,6 +37,11 @@ struct pch_regs {
u32 reset;
};
#define PCI_DEVICE_ID_INTEL_EG20T_PCH 0x8803
#define PCI_DEVICE_ID_ROHM_ML7223m_IOH 0x8014
#define PCI_DEVICE_ID_ROHM_ML7223n_IOH 0x8043
#define PCI_DEVICE_ID_ROHM_EG20T_PCH 0x8803
enum pch_type_t {
INTEL_EG20T_PCH,
OKISEMI_ML7223m_IOH, /* LAPIS Semiconductor ML7223 IOH PCIe Bus-m */
@ -357,16 +362,12 @@ static int pch_gpio_probe(struct pci_dev *pdev,
chip->dev = dev;
ret = pcim_enable_device(pdev);
if (ret) {
dev_err(dev, "pci_enable_device FAILED");
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to enable PCI device\n");
ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME);
if (ret) {
dev_err(dev, "pci_request_regions FAILED-%d", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to request and map PCI regions\n");
chip->base = pcim_iomap_table(pdev)[1];
chip->ioh = id->driver_data;
@ -376,10 +377,8 @@ static int pch_gpio_probe(struct pci_dev *pdev,
pch_gpio_setup(chip);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
if (ret) {
dev_err(dev, "PCH gpio: Failed to register GPIO\n");
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to register GPIO\n");
irq_base = devm_irq_alloc_descs(dev, -1, 0,
gpio_pins[chip->ioh], NUMA_NO_NODE);
@ -396,10 +395,8 @@ static int pch_gpio_probe(struct pci_dev *pdev,
ret = devm_request_irq(dev, pdev->irq, pch_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (ret) {
dev_err(dev, "request_irq failed\n");
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to request IRQ\n");
return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
}
@ -433,15 +430,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume);
static const struct pci_device_id pch_gpio_pcidev_id[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803),
.driver_data = INTEL_EG20T_PCH },
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014),
.driver_data = OKISEMI_ML7223m_IOH },
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043),
.driver_data = OKISEMI_ML7223n_IOH },
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803),
.driver_data = INTEL_EG20T_PCH },
{ 0, }
{ PCI_DEVICE_DATA(INTEL, EG20T_PCH, INTEL_EG20T_PCH) },
{ PCI_DEVICE_DATA(ROHM, ML7223m_IOH, OKISEMI_ML7223m_IOH) },
{ PCI_DEVICE_DATA(ROHM, ML7223n_IOH, OKISEMI_ML7223n_IOH) },
{ PCI_DEVICE_DATA(ROHM, EG20T_PCH, INTEL_EG20T_PCH) },
{ }
};
MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);

View File

@ -27,6 +27,7 @@
#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */
#define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */
#define GPIO_TYPE_V2_1 (0x0101157C) /* GPIO Version ID 0x0101157C */
static const struct rockchip_gpio_regs gpio_regs_v1 = {
.port_dr = 0x00,
@ -664,7 +665,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
id = readl(bank->reg_base + gpio_regs_v2.version_id);
/* If not gpio v2, that is default to v1. */
if (id == GPIO_TYPE_V2) {
if (id == GPIO_TYPE_V2 || id == GPIO_TYPE_V2_1) {
bank->gpio_regs = &gpio_regs_v2;
bank->gpio_type = GPIO_TYPE_V2;
bank->db_clk = of_clk_get(bank->of_node, 1);

View File

@ -593,27 +593,13 @@ out:
/* Cannot use as gpio_twl4030_probe() calls us */
static int gpio_twl4030_remove(struct platform_device *pdev)
{
struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
int status;
if (pdata && pdata->teardown) {
status = pdata->teardown(&pdev->dev, priv->gpio_chip.base,
TWL4030_GPIO_MAX);
if (status) {
dev_dbg(&pdev->dev, "teardown --> %d\n", status);
return status;
}
}
gpiochip_remove(&priv->gpio_chip);
if (is_module())
return 0;
/* REVISIT no support yet for deregistering all the IRQs */
WARN_ON(1);
return -EIO;
WARN_ON(!is_module());
return 0;
}
static const struct of_device_id twl_gpio_match[] = {

View File

@ -64,34 +64,14 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
ucb->gc.can_sleep = true;
err = devm_gpiochip_add_data(&dev->dev, &ucb->gc, ucb);
if (err)
goto err;
if (ucb->gpio_setup)
err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio);
err:
return err;
}
static int ucb1400_gpio_remove(struct platform_device *dev)
{
int err = 0;
struct ucb1400_gpio *ucb = platform_get_drvdata(dev);
if (ucb && ucb->gpio_teardown) {
err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio);
if (err)
return err;
}
return err;
}
static struct platform_driver ucb1400_gpio_driver = {
.probe = ucb1400_gpio_probe,
.remove = ucb1400_gpio_remove,
.driver = {
.name = "ucb1400_gpio"
},

View File

@ -1,541 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for NEC VR4100 series General-purpose I/O Unit.
*
* Copyright (C) 2002 MontaVista Software Inc.
* Author: Yoichi Yuasa <source@mvista.com>
* Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org>
*/
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/vr41xx/giu.h>
#include <asm/vr41xx/irq.h>
#include <asm/vr41xx/vr41xx.h>
MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
MODULE_LICENSE("GPL");
#define GIUIOSELL 0x00
#define GIUIOSELH 0x02
#define GIUPIODL 0x04
#define GIUPIODH 0x06
#define GIUINTSTATL 0x08
#define GIUINTSTATH 0x0a
#define GIUINTENL 0x0c
#define GIUINTENH 0x0e
#define GIUINTTYPL 0x10
#define GIUINTTYPH 0x12
#define GIUINTALSELL 0x14
#define GIUINTALSELH 0x16
#define GIUINTHTSELL 0x18
#define GIUINTHTSELH 0x1a
#define GIUPODATL 0x1c
#define GIUPODATEN 0x1c
#define GIUPODATH 0x1e
#define PIOEN0 0x0100
#define PIOEN1 0x0200
#define GIUPODAT 0x1e
#define GIUFEDGEINHL 0x20
#define GIUFEDGEINHH 0x22
#define GIUREDGEINHL 0x24
#define GIUREDGEINHH 0x26
#define GIUUSEUPDN 0x1e0
#define GIUTERMUPDN 0x1e2
#define GPIO_HAS_PULLUPDOWN_IO 0x0001
#define GPIO_HAS_OUTPUT_ENABLE 0x0002
#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
enum {
GPIO_INPUT,
GPIO_OUTPUT,
};
static DEFINE_SPINLOCK(giu_lock);
static unsigned long giu_flags;
static void __iomem *giu_base;
static struct gpio_chip vr41xx_gpio_chip;
#define giu_read(offset) readw(giu_base + (offset))
#define giu_write(offset, value) writew((value), giu_base + (offset))
#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE)
#define GIUINT_HIGH_OFFSET 16
#define GIUINT_HIGH_MAX 32
static inline u16 giu_set(u16 offset, u16 set)
{
u16 data;
data = giu_read(offset);
data |= set;
giu_write(offset, data);
return data;
}
static inline u16 giu_clear(u16 offset, u16 clear)
{
u16 data;
data = giu_read(offset);
data &= ~clear;
giu_write(offset, data);
return data;
}
static void ack_giuint_low(struct irq_data *d)
{
giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
static void mask_giuint_low(struct irq_data *d)
{
giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
static void mask_ack_giuint_low(struct irq_data *d)
{
unsigned int pin;
pin = GPIO_PIN_OF_IRQ(d->irq);
giu_clear(GIUINTENL, 1 << pin);
giu_write(GIUINTSTATL, 1 << pin);
}
static void unmask_giuint_low(struct irq_data *d)
{
giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
static unsigned int startup_giuint(struct irq_data *data)
{
int ret;
ret = gpiochip_lock_as_irq(&vr41xx_gpio_chip, irqd_to_hwirq(data));
if (ret) {
dev_err(vr41xx_gpio_chip.parent,
"unable to lock HW IRQ %lu for IRQ\n",
data->hwirq);
return ret;
}
/* Satisfy the .enable semantics by unmasking the line */
unmask_giuint_low(data);
return 0;
}
static void shutdown_giuint(struct irq_data *data)
{
mask_giuint_low(data);
gpiochip_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq);
}
static struct irq_chip giuint_low_irq_chip = {
.name = "GIUINTL",
.irq_ack = ack_giuint_low,
.irq_mask = mask_giuint_low,
.irq_mask_ack = mask_ack_giuint_low,
.irq_unmask = unmask_giuint_low,
.irq_startup = startup_giuint,
.irq_shutdown = shutdown_giuint,
};
static void ack_giuint_high(struct irq_data *d)
{
giu_write(GIUINTSTATH,
1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
}
static void mask_giuint_high(struct irq_data *d)
{
giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
}
static void mask_ack_giuint_high(struct irq_data *d)
{
unsigned int pin;
pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET;
giu_clear(GIUINTENH, 1 << pin);
giu_write(GIUINTSTATH, 1 << pin);
}
static void unmask_giuint_high(struct irq_data *d)
{
giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET));
}
static struct irq_chip giuint_high_irq_chip = {
.name = "GIUINTH",
.irq_ack = ack_giuint_high,
.irq_mask = mask_giuint_high,
.irq_mask_ack = mask_ack_giuint_high,
.irq_unmask = unmask_giuint_high,
};
static int giu_get_irq(unsigned int irq)
{
u16 pendl, pendh, maskl, maskh;
int i;
pendl = giu_read(GIUINTSTATL);
pendh = giu_read(GIUINTSTATH);
maskl = giu_read(GIUINTENL);
maskh = giu_read(GIUINTENH);
maskl &= pendl;
maskh &= pendh;
if (maskl) {
for (i = 0; i < 16; i++) {
if (maskl & (1 << i))
return GIU_IRQ(i);
}
} else if (maskh) {
for (i = 0; i < 16; i++) {
if (maskh & (1 << i))
return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
}
}
printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
maskl, pendl, maskh, pendh);
return -EINVAL;
}
void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
irq_signal_t signal)
{
u16 mask;
if (pin < GIUINT_HIGH_OFFSET) {
mask = 1 << pin;
if (trigger != IRQ_TRIGGER_LEVEL) {
giu_set(GIUINTTYPL, mask);
if (signal == IRQ_SIGNAL_HOLD)
giu_set(GIUINTHTSELL, mask);
else
giu_clear(GIUINTHTSELL, mask);
if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
switch (trigger) {
case IRQ_TRIGGER_EDGE_FALLING:
giu_set(GIUFEDGEINHL, mask);
giu_clear(GIUREDGEINHL, mask);
break;
case IRQ_TRIGGER_EDGE_RISING:
giu_clear(GIUFEDGEINHL, mask);
giu_set(GIUREDGEINHL, mask);
break;
default:
giu_set(GIUFEDGEINHL, mask);
giu_set(GIUREDGEINHL, mask);
break;
}
}
irq_set_chip_and_handler(GIU_IRQ(pin),
&giuint_low_irq_chip,
handle_edge_irq);
} else {
giu_clear(GIUINTTYPL, mask);
giu_clear(GIUINTHTSELL, mask);
irq_set_chip_and_handler(GIU_IRQ(pin),
&giuint_low_irq_chip,
handle_level_irq);
}
giu_write(GIUINTSTATL, mask);
} else if (pin < GIUINT_HIGH_MAX) {
mask = 1 << (pin - GIUINT_HIGH_OFFSET);
if (trigger != IRQ_TRIGGER_LEVEL) {
giu_set(GIUINTTYPH, mask);
if (signal == IRQ_SIGNAL_HOLD)
giu_set(GIUINTHTSELH, mask);
else
giu_clear(GIUINTHTSELH, mask);
if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
switch (trigger) {
case IRQ_TRIGGER_EDGE_FALLING:
giu_set(GIUFEDGEINHH, mask);
giu_clear(GIUREDGEINHH, mask);
break;
case IRQ_TRIGGER_EDGE_RISING:
giu_clear(GIUFEDGEINHH, mask);
giu_set(GIUREDGEINHH, mask);
break;
default:
giu_set(GIUFEDGEINHH, mask);
giu_set(GIUREDGEINHH, mask);
break;
}
}
irq_set_chip_and_handler(GIU_IRQ(pin),
&giuint_high_irq_chip,
handle_edge_irq);
} else {
giu_clear(GIUINTTYPH, mask);
giu_clear(GIUINTHTSELH, mask);
irq_set_chip_and_handler(GIU_IRQ(pin),
&giuint_high_irq_chip,
handle_level_irq);
}
giu_write(GIUINTSTATH, mask);
}
}
EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
{
u16 mask;
if (pin < GIUINT_HIGH_OFFSET) {
mask = 1 << pin;
if (level == IRQ_LEVEL_HIGH)
giu_set(GIUINTALSELL, mask);
else
giu_clear(GIUINTALSELL, mask);
giu_write(GIUINTSTATL, mask);
} else if (pin < GIUINT_HIGH_MAX) {
mask = 1 << (pin - GIUINT_HIGH_OFFSET);
if (level == IRQ_LEVEL_HIGH)
giu_set(GIUINTALSELH, mask);
else
giu_clear(GIUINTALSELH, mask);
giu_write(GIUINTSTATH, mask);
}
}
EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
{
u16 offset, mask, reg;
unsigned long flags;
if (pin >= chip->ngpio)
return -EINVAL;
if (pin < 16) {
offset = GIUIOSELL;
mask = 1 << pin;
} else if (pin < 32) {
offset = GIUIOSELH;
mask = 1 << (pin - 16);
} else {
if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
offset = GIUPODATEN;
mask = 1 << (pin - 32);
} else {
switch (pin) {
case 48:
offset = GIUPODATH;
mask = PIOEN0;
break;
case 49:
offset = GIUPODATH;
mask = PIOEN1;
break;
default:
return -EINVAL;
}
}
}
spin_lock_irqsave(&giu_lock, flags);
reg = giu_read(offset);
if (dir == GPIO_OUTPUT)
reg |= mask;
else
reg &= ~mask;
giu_write(offset, reg);
spin_unlock_irqrestore(&giu_lock, flags);
return 0;
}
static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
{
u16 reg, mask;
if (pin >= chip->ngpio)
return -EINVAL;
if (pin < 16) {
reg = giu_read(GIUPIODL);
mask = 1 << pin;
} else if (pin < 32) {
reg = giu_read(GIUPIODH);
mask = 1 << (pin - 16);
} else if (pin < 48) {
reg = giu_read(GIUPODATL);
mask = 1 << (pin - 32);
} else {
reg = giu_read(GIUPODATH);
mask = 1 << (pin - 48);
}
if (reg & mask)
return 1;
return 0;
}
static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
int value)
{
u16 offset, mask, reg;
unsigned long flags;
if (pin >= chip->ngpio)
return;
if (pin < 16) {
offset = GIUPIODL;
mask = 1 << pin;
} else if (pin < 32) {
offset = GIUPIODH;
mask = 1 << (pin - 16);
} else if (pin < 48) {
offset = GIUPODATL;
mask = 1 << (pin - 32);
} else {
offset = GIUPODATH;
mask = 1 << (pin - 48);
}
spin_lock_irqsave(&giu_lock, flags);
reg = giu_read(offset);
if (value)
reg |= mask;
else
reg &= ~mask;
giu_write(offset, reg);
spin_unlock_irqrestore(&giu_lock, flags);
}
static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
return giu_set_direction(chip, offset, GPIO_INPUT);
}
static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
vr41xx_gpio_set(chip, offset, value);
return giu_set_direction(chip, offset, GPIO_OUTPUT);
}
static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
if (offset >= chip->ngpio)
return -EINVAL;
return GIU_IRQ_BASE + offset;
}
static struct gpio_chip vr41xx_gpio_chip = {
.label = "vr41xx",
.owner = THIS_MODULE,
.direction_input = vr41xx_gpio_direction_input,
.get = vr41xx_gpio_get,
.direction_output = vr41xx_gpio_direction_output,
.set = vr41xx_gpio_set,
.to_irq = vr41xx_gpio_to_irq,
};
static int giu_probe(struct platform_device *pdev)
{
unsigned int trigger, i, pin;
struct irq_chip *chip;
int irq;
switch (pdev->id) {
case GPIO_50PINS_PULLUPDOWN:
giu_flags = GPIO_HAS_PULLUPDOWN_IO;
vr41xx_gpio_chip.ngpio = 50;
break;
case GPIO_36PINS:
vr41xx_gpio_chip.ngpio = 36;
break;
case GPIO_48PINS_EDGE_SELECT:
giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
vr41xx_gpio_chip.ngpio = 48;
break;
default:
dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
return -ENODEV;
}
giu_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(giu_base))
return PTR_ERR(giu_base);
vr41xx_gpio_chip.parent = &pdev->dev;
if (gpiochip_add_data(&vr41xx_gpio_chip, NULL))
return -ENODEV;
giu_write(GIUINTENL, 0);
giu_write(GIUINTENH, 0);
trigger = giu_read(GIUINTTYPH) << 16;
trigger |= giu_read(GIUINTTYPL);
for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
pin = GPIO_PIN_OF_IRQ(i);
if (pin < GIUINT_HIGH_OFFSET)
chip = &giuint_low_irq_chip;
else
chip = &giuint_high_irq_chip;
if (trigger & (1 << pin))
irq_set_chip_and_handler(i, chip, handle_edge_irq);
else
irq_set_chip_and_handler(i, chip, handle_level_irq);
}
irq = platform_get_irq(pdev, 0);
if (irq < 0 || irq >= nr_irqs)
return -EBUSY;
return cascade_irq(irq, giu_get_irq);
}
static int giu_remove(struct platform_device *pdev)
{
if (giu_base) {
giu_base = NULL;
}
return 0;
}
static struct platform_driver giu_device_driver = {
.probe = giu_probe,
.remove = giu_remove,
.driver = {
.name = "GIU",
},
};
module_platform_driver(giu_device_driver);

View File

@ -4,7 +4,6 @@
* Copyright (C) 2016 William Breathitt Gray
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@ -17,8 +16,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#define WS16C48_EXTENT 16
#define WS16C48_EXTENT 10
#define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT)
static unsigned int base[MAX_NUM_WS16C48];
@ -30,6 +30,20 @@ static unsigned int irq[MAX_NUM_WS16C48];
module_param_hw_array(irq, uint, irq, NULL, 0);
MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
/**
* struct ws16c48_reg - device register structure
* @port: Port 0 through 5 I/O
* @int_pending: Interrupt Pending
* @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0)
* @pol_enab_int_id: Interrupt polarity, enable, and ID
*/
struct ws16c48_reg {
u8 port[6];
u8 int_pending;
u8 page_lock;
u8 pol_enab_int_id[3];
};
/**
* struct ws16c48_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
@ -38,7 +52,7 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
* @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts
* @flow_mask: IRQ flow type mask for the respective I/O bits
* @base: base port address of the GPIO device
* @reg: I/O address offset for the device registers
*/
struct ws16c48_gpio {
struct gpio_chip chip;
@ -47,7 +61,7 @@ struct ws16c48_gpio {
raw_spinlock_t lock;
unsigned long irq_mask;
unsigned long flow_mask;
void __iomem *base;
struct ws16c48_reg __iomem *reg;
};
static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@ -73,7 +87,7 @@ static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
ws16c48gpio->io_state[port] |= mask;
ws16c48gpio->out_state[port] &= ~mask;
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@ -95,7 +109,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
ws16c48gpio->out_state[port] |= mask;
else
ws16c48gpio->out_state[port] &= ~mask;
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@ -118,7 +132,7 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
port_state = ioread8(ws16c48gpio->base + port);
port_state = ioread8(ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@ -131,14 +145,16 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
unsigned long offset;
unsigned long gpio_mask;
void __iomem *port_addr;
size_t index;
u8 __iomem *port_addr;
unsigned long port_state;
/* clear bits array to a clean slate */
bitmap_zero(bits, chip->ngpio);
for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
port_addr = ws16c48gpio->base + offset / 8;
index = offset / 8;
port_addr = ws16c48gpio->reg->port + index;
port_state = ioread8(port_addr) & gpio_mask;
bitmap_set_value8(bits, port_state, offset);
@ -166,7 +182,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
ws16c48gpio->out_state[port] |= mask;
else
ws16c48gpio->out_state[port] &= ~mask;
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port);
iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@ -178,13 +194,13 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
unsigned long offset;
unsigned long gpio_mask;
size_t index;
void __iomem *port_addr;
u8 __iomem *port_addr;
unsigned long bitmask;
unsigned long flags;
for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
index = offset / 8;
port_addr = ws16c48gpio->base + index;
port_addr = ws16c48gpio->reg->port + index;
/* mask out GPIO configured for input */
gpio_mask &= ~ws16c48gpio->io_state[index];
@ -219,10 +235,15 @@ static void ws16c48_irq_ack(struct irq_data *data)
port_state = ws16c48gpio->irq_mask >> (8*port);
iowrite8(0x80, ws16c48gpio->base + 7);
iowrite8(port_state & ~mask, ws16c48gpio->base + 8 + port);
iowrite8(port_state | mask, ws16c48gpio->base + 8 + port);
iowrite8(0xC0, ws16c48gpio->base + 7);
/* Select Register Page 2; Unlock all I/O ports */
iowrite8(0x80, &ws16c48gpio->reg->page_lock);
/* Clear pending interrupt */
iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port);
iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port);
/* Select Register Page 3; Unlock all I/O ports */
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@ -235,6 +256,7 @@ static void ws16c48_irq_mask(struct irq_data *data)
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
unsigned long port_state;
/* only the first 3 ports support interrupts */
if (port > 2)
@ -243,10 +265,16 @@ static void ws16c48_irq_mask(struct irq_data *data)
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->irq_mask &= ~mask;
port_state = ws16c48gpio->irq_mask >> (8 * port);
iowrite8(0x80, ws16c48gpio->base + 7);
iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
iowrite8(0xC0, ws16c48gpio->base + 7);
/* Select Register Page 2; Unlock all I/O ports */
iowrite8(0x80, &ws16c48gpio->reg->page_lock);
/* Disable interrupt */
iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
/* Select Register Page 3; Unlock all I/O ports */
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@ -259,6 +287,7 @@ static void ws16c48_irq_unmask(struct irq_data *data)
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
unsigned long port_state;
/* only the first 3 ports support interrupts */
if (port > 2)
@ -267,10 +296,16 @@ static void ws16c48_irq_unmask(struct irq_data *data)
raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
ws16c48gpio->irq_mask |= mask;
port_state = ws16c48gpio->irq_mask >> (8 * port);
iowrite8(0x80, ws16c48gpio->base + 7);
iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port);
iowrite8(0xC0, ws16c48gpio->base + 7);
/* Select Register Page 2; Unlock all I/O ports */
iowrite8(0x80, &ws16c48gpio->reg->page_lock);
/* Enable interrupt */
iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
/* Select Register Page 3; Unlock all I/O ports */
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
}
@ -283,6 +318,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
const unsigned long mask = BIT(offset);
const unsigned port = offset / 8;
unsigned long flags;
unsigned long port_state;
/* only the first 3 ports support interrupts */
if (port > 2)
@ -304,9 +340,16 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
return -EINVAL;
}
iowrite8(0x40, ws16c48gpio->base + 7);
iowrite8(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port);
iowrite8(0xC0, ws16c48gpio->base + 7);
port_state = ws16c48gpio->flow_mask >> (8 * port);
/* Select Register Page 1; Unlock all I/O ports */
iowrite8(0x40, &ws16c48gpio->reg->page_lock);
/* Set interrupt polarity */
iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
/* Select Register Page 3; Unlock all I/O ports */
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
@ -325,25 +368,26 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
{
struct ws16c48_gpio *const ws16c48gpio = dev_id;
struct gpio_chip *const chip = &ws16c48gpio->chip;
struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg;
unsigned long int_pending;
unsigned long port;
unsigned long int_id;
unsigned long gpio;
int_pending = ioread8(ws16c48gpio->base + 6) & 0x7;
int_pending = ioread8(&reg->int_pending) & 0x7;
if (!int_pending)
return IRQ_NONE;
/* loop until all pending interrupts are handled */
do {
for_each_set_bit(port, &int_pending, 3) {
int_id = ioread8(ws16c48gpio->base + 8 + port);
int_id = ioread8(reg->pol_enab_int_id + port);
for_each_set_bit(gpio, &int_id, 8)
generic_handle_domain_irq(chip->irq.domain,
gpio + 8*port);
}
int_pending = ioread8(ws16c48gpio->base + 6) & 0x7;
int_pending = ioread8(&reg->int_pending) & 0x7;
} while (int_pending);
return IRQ_HANDLED;
@ -369,12 +413,16 @@ static int ws16c48_irq_init_hw(struct gpio_chip *gc)
{
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc);
/* Disable IRQ by default */
iowrite8(0x80, ws16c48gpio->base + 7);
iowrite8(0, ws16c48gpio->base + 8);
iowrite8(0, ws16c48gpio->base + 9);
iowrite8(0, ws16c48gpio->base + 10);
iowrite8(0xC0, ws16c48gpio->base + 7);
/* Select Register Page 2; Unlock all I/O ports */
iowrite8(0x80, &ws16c48gpio->reg->page_lock);
/* Disable interrupts for all lines */
iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]);
iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]);
iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]);
/* Select Register Page 3; Unlock all I/O ports */
iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
return 0;
}
@ -396,8 +444,8 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
return -EBUSY;
}
ws16c48gpio->base = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
if (!ws16c48gpio->base)
ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
if (!ws16c48gpio->reg)
return -ENOMEM;
ws16c48gpio->chip.label = name;

View File

@ -281,11 +281,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
static int iproc_gpio_remove(struct platform_device *pdev)
{
struct iproc_gpio_chip *chip;
chip = platform_get_drvdata(pdev);
if (!chip)
return -ENODEV;
struct iproc_gpio_chip *chip = platform_get_drvdata(pdev);
if (chip->intr) {
u32 val;

View File

@ -117,12 +117,14 @@ static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch)
static void xgpio_read_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a)
{
void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32);
xgpio_set_value32(a, bit, xgpio_readreg(addr));
}
static void xgpio_write_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a)
{
void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32);
xgpio_writereg(addr, xgpio_get_value32(a, bit));
}

View File

@ -687,6 +687,9 @@ int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
case ACPI_PIN_CONFIG_PULLDOWN:
*lookupflags |= GPIO_PULL_DOWN;
break;
case ACPI_PIN_CONFIG_NOPULL:
*lookupflags |= GPIO_PULL_DISABLE;
break;
default:
break;
}

View File

@ -434,12 +434,15 @@ struct line {
struct linereq *req;
unsigned int irq;
/*
* eflags is set by edge_detector_setup(), edge_detector_stop() and
* edge_detector_update(), which are themselves mutually exclusive,
* and is accessed by edge_irq_thread() and debounce_work_func(),
* which can both live with a slightly stale value.
* The flags for the active edge detector configuration.
*
* edflags is set by linereq_create(), linereq_free(), and
* linereq_set_config_unlocked(), which are themselves mutually
* exclusive, and is accessed by edge_irq_thread(),
* process_hw_ts_thread() and debounce_work_func(),
* which can all live with a slightly stale value.
*/
u64 eflags;
u64 edflags;
/*
* timestamp_ns and req_seqno are accessed only by
* edge_irq_handler() and edge_irq_thread(), which are themselves
@ -469,9 +472,7 @@ struct line {
* stale value.
*/
unsigned int level;
/*
* -- hte specific fields --
*/
#ifdef CONFIG_HTE
struct hte_ts_desc hdesc;
/*
* HTE provider sets line level at the time of event. The valid
@ -488,6 +489,7 @@ struct line {
* last sequence number before debounce period expires.
*/
u32 last_seqno;
#endif /* CONFIG_HTE */
};
/**
@ -545,6 +547,12 @@ struct linereq {
GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \
GPIO_V2_LINE_BIAS_FLAGS)
/* subset of flags relevant for edge detector configuration */
#define GPIO_V2_LINE_EDGE_DETECTOR_FLAGS \
(GPIO_V2_LINE_FLAG_ACTIVE_LOW | \
GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \
GPIO_V2_LINE_EDGE_FLAGS)
static void linereq_put_event(struct linereq *lr,
struct gpio_v2_line_event *le)
{
@ -567,19 +575,28 @@ static u64 line_event_timestamp(struct line *line)
{
if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags))
return ktime_get_real_ns();
else if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags))
else if (IS_ENABLED(CONFIG_HTE) &&
test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags))
return line->timestamp_ns;
return ktime_get_ns();
}
static u32 line_event_id(int level)
{
return level ? GPIO_V2_LINE_EVENT_RISING_EDGE :
GPIO_V2_LINE_EVENT_FALLING_EDGE;
}
#ifdef CONFIG_HTE
static enum hte_return process_hw_ts_thread(void *p)
{
struct line *line;
struct linereq *lr;
struct gpio_v2_line_event le;
u64 edflags;
int level;
u64 eflags;
if (!p)
return HTE_CB_HANDLED;
@ -590,29 +607,26 @@ static enum hte_return process_hw_ts_thread(void *p)
memset(&le, 0, sizeof(le));
le.timestamp_ns = line->timestamp_ns;
eflags = READ_ONCE(line->eflags);
edflags = READ_ONCE(line->edflags);
if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) {
if (line->raw_level >= 0) {
if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags))
level = !line->raw_level;
else
level = line->raw_level;
} else {
level = gpiod_get_value_cansleep(line->desc);
}
switch (edflags & GPIO_V2_LINE_EDGE_FLAGS) {
case GPIO_V2_LINE_FLAG_EDGE_BOTH:
level = (line->raw_level >= 0) ?
line->raw_level :
gpiod_get_raw_value_cansleep(line->desc);
if (level)
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
else
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
/* Emit low-to-high event */
if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW)
level = !level;
le.id = line_event_id(level);
break;
case GPIO_V2_LINE_FLAG_EDGE_RISING:
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
/* Emit high-to-low event */
break;
case GPIO_V2_LINE_FLAG_EDGE_FALLING:
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
} else {
break;
default:
return HTE_CB_HANDLED;
}
le.line_seqno = line->line_seqno;
@ -659,12 +673,47 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p)
return HTE_CB_HANDLED;
}
static int hte_edge_setup(struct line *line, u64 eflags)
{
int ret;
unsigned long flags = 0;
struct hte_ts_desc *hdesc = &line->hdesc;
if (eflags & GPIO_V2_LINE_FLAG_EDGE_RISING)
flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
HTE_FALLING_EDGE_TS :
HTE_RISING_EDGE_TS;
if (eflags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
HTE_RISING_EDGE_TS :
HTE_FALLING_EDGE_TS;
line->total_discard_seq = 0;
hte_init_line_attr(hdesc, desc_to_gpio(line->desc), flags, NULL,
line->desc);
ret = hte_ts_get(NULL, hdesc, 0);
if (ret)
return ret;
return hte_request_ts_ns(hdesc, process_hw_ts, process_hw_ts_thread,
line);
}
#else
static int hte_edge_setup(struct line *line, u64 eflags)
{
return 0;
}
#endif /* CONFIG_HTE */
static irqreturn_t edge_irq_thread(int irq, void *p)
{
struct line *line = p;
struct linereq *lr = line->req;
struct gpio_v2_line_event le;
u64 eflags;
/* Do not leak kernel stack to userspace */
memset(&le, 0, sizeof(le));
@ -683,23 +732,17 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
}
line->timestamp_ns = 0;
eflags = READ_ONCE(line->eflags);
if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) {
int level = gpiod_get_value_cansleep(line->desc);
if (level)
/* Emit low-to-high event */
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
else
/* Emit high-to-low event */
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
/* Emit low-to-high event */
switch (READ_ONCE(line->edflags) & GPIO_V2_LINE_EDGE_FLAGS) {
case GPIO_V2_LINE_FLAG_EDGE_BOTH:
le.id = line_event_id(gpiod_get_value_cansleep(line->desc));
break;
case GPIO_V2_LINE_FLAG_EDGE_RISING:
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
} else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
/* Emit high-to-low event */
break;
case GPIO_V2_LINE_FLAG_EDGE_FALLING:
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
} else {
break;
default:
return IRQ_NONE;
}
line->line_seqno++;
@ -764,16 +807,16 @@ static void debounce_work_func(struct work_struct *work)
struct gpio_v2_line_event le;
struct line *line = container_of(work, struct line, work.work);
struct linereq *lr;
int level, diff_seqno;
u64 eflags;
u64 eflags, edflags = READ_ONCE(line->edflags);
int level = -1;
#ifdef CONFIG_HTE
int diff_seqno;
if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) {
if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)
level = line->raw_level;
if (level < 0)
level = gpiod_get_raw_value_cansleep(line->desc);
} else {
#endif
if (level < 0)
level = gpiod_get_raw_value_cansleep(line->desc);
}
if (level < 0) {
pr_debug_ratelimited("debouncer failed to read line value\n");
return;
@ -785,12 +828,12 @@ static void debounce_work_func(struct work_struct *work)
WRITE_ONCE(line->level, level);
/* -- edge detection -- */
eflags = READ_ONCE(line->eflags);
eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS;
if (!eflags)
return;
/* switch from physical level to logical - if they differ */
if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags))
if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW)
level = !level;
/* ignore edges that are not being monitored */
@ -804,7 +847,8 @@ static void debounce_work_func(struct work_struct *work)
lr = line->req;
le.timestamp_ns = line_event_timestamp(line);
le.offset = gpio_chip_hwgpio(line->desc);
if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) {
#ifdef CONFIG_HTE
if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) {
/* discard events except the last one */
line->total_discard_seq -= 1;
diff_seqno = line->last_seqno - line->total_discard_seq -
@ -813,51 +857,21 @@ static void debounce_work_func(struct work_struct *work)
le.line_seqno = line->line_seqno;
le.seqno = (lr->num_lines == 1) ?
le.line_seqno : atomic_add_return(diff_seqno, &lr->seqno);
} else {
} else
#endif /* CONFIG_HTE */
{
line->line_seqno++;
le.line_seqno = line->line_seqno;
le.seqno = (lr->num_lines == 1) ?
le.line_seqno : atomic_inc_return(&lr->seqno);
}
if (level)
/* Emit low-to-high event */
le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
else
/* Emit high-to-low event */
le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
le.id = line_event_id(level);
linereq_put_event(lr, &le);
}
static int hte_edge_setup(struct line *line, u64 eflags)
{
int ret;
unsigned long flags = 0;
struct hte_ts_desc *hdesc = &line->hdesc;
if (eflags & GPIO_V2_LINE_FLAG_EDGE_RISING)
flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
HTE_FALLING_EDGE_TS : HTE_RISING_EDGE_TS;
if (eflags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ?
HTE_RISING_EDGE_TS : HTE_FALLING_EDGE_TS;
line->total_discard_seq = 0;
hte_init_line_attr(hdesc, desc_to_gpio(line->desc), flags,
NULL, line->desc);
ret = hte_ts_get(NULL, hdesc, 0);
if (ret)
return ret;
return hte_request_ts_ns(hdesc, process_hw_ts,
process_hw_ts_thread, line);
}
static int debounce_setup(struct line *line,
unsigned int debounce_period_us, bool hte_req)
static int debounce_setup(struct line *line, unsigned int debounce_period_us)
{
unsigned long irqflags;
int ret, level, irq;
@ -877,7 +891,8 @@ static int debounce_setup(struct line *line,
if (level < 0)
return level;
if (!hte_req) {
if (!(IS_ENABLED(CONFIG_HTE) &&
test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags))) {
irq = gpiod_to_irq(line->desc);
if (irq < 0)
return -ENXIO;
@ -889,9 +904,7 @@ static int debounce_setup(struct line *line,
return ret;
line->irq = irq;
} else {
ret = hte_edge_setup(line,
GPIO_V2_LINE_FLAG_EDGE_RISING |
GPIO_V2_LINE_FLAG_EDGE_FALLING);
ret = hte_edge_setup(line, GPIO_V2_LINE_FLAG_EDGE_BOTH);
if (ret)
return ret;
}
@ -930,19 +943,21 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc,
return 0;
}
static void edge_detector_stop(struct line *line, bool hte_en)
static void edge_detector_stop(struct line *line)
{
if (line->irq && !hte_en) {
if (line->irq) {
free_irq(line->irq, line);
line->irq = 0;
}
if (hte_en)
#ifdef CONFIG_HTE
if (READ_ONCE(line->edflags) & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)
hte_ts_put(&line->hdesc);
#endif
cancel_delayed_work_sync(&line->work);
WRITE_ONCE(line->sw_debounced, 0);
WRITE_ONCE(line->eflags, 0);
WRITE_ONCE(line->edflags, 0);
if (line->desc)
WRITE_ONCE(line->desc->debounce_period_us, 0);
/* do not change line->level - see comment in debounced_value() */
@ -950,23 +965,23 @@ static void edge_detector_stop(struct line *line, bool hte_en)
static int edge_detector_setup(struct line *line,
struct gpio_v2_line_config *lc,
unsigned int line_idx,
u64 eflags, bool hte_req)
unsigned int line_idx, u64 edflags)
{
u32 debounce_period_us;
unsigned long irqflags = 0;
u64 eflags;
int irq, ret;
eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS;
if (eflags && !kfifo_initialized(&line->req->events)) {
ret = kfifo_alloc(&line->req->events,
line->req->event_buffer_size, GFP_KERNEL);
if (ret)
return ret;
}
WRITE_ONCE(line->eflags, eflags);
if (gpio_v2_line_config_debounced(lc, line_idx)) {
debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx);
ret = debounce_setup(line, debounce_period_us, hte_req);
ret = debounce_setup(line, debounce_period_us);
if (ret)
return ret;
WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
@ -976,8 +991,9 @@ static int edge_detector_setup(struct line *line,
if (!eflags || READ_ONCE(line->sw_debounced))
return 0;
if (hte_req)
return hte_edge_setup(line, eflags);
if (IS_ENABLED(CONFIG_HTE) &&
(edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE))
return hte_edge_setup(line, edflags);
irq = gpiod_to_irq(line->desc);
if (irq < 0)
@ -1003,35 +1019,29 @@ static int edge_detector_setup(struct line *line,
static int edge_detector_update(struct line *line,
struct gpio_v2_line_config *lc,
unsigned int line_idx,
u64 flags, bool polarity_change,
bool prev_hte_flag)
unsigned int line_idx, u64 edflags)
{
u64 eflags = flags & GPIO_V2_LINE_EDGE_FLAGS;
u64 active_edflags = READ_ONCE(line->edflags);
unsigned int debounce_period_us =
gpio_v2_line_config_debounce_period(lc, line_idx);
bool hte_change = (prev_hte_flag !=
((flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) != 0));
if ((READ_ONCE(line->eflags) == eflags) && !polarity_change &&
(READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)
&& !hte_change)
if ((active_edflags == edflags) &&
(READ_ONCE(line->desc->debounce_period_us) == debounce_period_us))
return 0;
/* sw debounced and still will be...*/
if (debounce_period_us && READ_ONCE(line->sw_debounced)) {
WRITE_ONCE(line->eflags, eflags);
WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
return 0;
}
/* reconfiguring edge detection or sw debounce being disabled */
if ((line->irq && !READ_ONCE(line->sw_debounced)) || prev_hte_flag ||
if ((line->irq && !READ_ONCE(line->sw_debounced)) ||
(active_edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) ||
(!debounce_period_us && READ_ONCE(line->sw_debounced)))
edge_detector_stop(line, prev_hte_flag);
edge_detector_stop(line);
return edge_detector_setup(line, lc, line_idx, eflags,
flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE);
return edge_detector_setup(line, lc, line_idx, edflags);
}
static u64 gpio_v2_line_config_flags(struct gpio_v2_line_config *lc,
@ -1067,6 +1077,11 @@ static int gpio_v2_line_flags_validate(u64 flags)
/* Return an error if an unknown flag is set */
if (flags & ~GPIO_V2_LINE_VALID_FLAGS)
return -EINVAL;
if (!IS_ENABLED(CONFIG_HTE) &&
(flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE))
return -EOPNOTSUPP;
/*
* Do not allow both INPUT and OUTPUT flags to be set as they are
* contradictory.
@ -1076,7 +1091,8 @@ static int gpio_v2_line_flags_validate(u64 flags)
return -EINVAL;
/* Only allow one event clock source */
if ((flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME) &&
if (IS_ENABLED(CONFIG_HTE) &&
(flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME) &&
(flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE))
return -EINVAL;
@ -1300,22 +1316,17 @@ static long linereq_set_config_unlocked(struct linereq *lr,
struct gpio_v2_line_config *lc)
{
struct gpio_desc *desc;
struct line *line;
unsigned int i;
u64 flags;
bool polarity_change;
bool prev_hte_flag;
u64 flags, edflags;
int ret;
for (i = 0; i < lr->num_lines; i++) {
line = &lr->lines[i];
desc = lr->lines[i].desc;
flags = gpio_v2_line_config_flags(lc, i);
polarity_change =
(!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) !=
((flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) != 0));
prev_hte_flag = !!test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags);
gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags);
edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS;
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
@ -1323,7 +1334,7 @@ static long linereq_set_config_unlocked(struct linereq *lr,
if (flags & GPIO_V2_LINE_FLAG_OUTPUT) {
int val = gpio_v2_line_config_output_value(lc, i);
edge_detector_stop(&lr->lines[i], prev_hte_flag);
edge_detector_stop(line);
ret = gpiod_direction_output(desc, val);
if (ret)
return ret;
@ -1332,12 +1343,13 @@ static long linereq_set_config_unlocked(struct linereq *lr,
if (ret)
return ret;
ret = edge_detector_update(&lr->lines[i], lc, i,
flags, polarity_change, prev_hte_flag);
ret = edge_detector_update(line, lc, i, edflags);
if (ret)
return ret;
}
WRITE_ONCE(line->edflags, edflags);
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIO_V2_LINE_CHANGED_CONFIG,
desc);
@ -1464,15 +1476,12 @@ static ssize_t linereq_read(struct file *file,
static void linereq_free(struct linereq *lr)
{
unsigned int i;
bool hte = false;
for (i = 0; i < lr->num_lines; i++) {
if (lr->lines[i].desc)
hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
&lr->lines[i].desc->flags);
edge_detector_stop(&lr->lines[i], hte);
if (lr->lines[i].desc)
if (lr->lines[i].desc) {
edge_detector_stop(&lr->lines[i]);
gpiod_free(lr->lines[i].desc);
}
}
kfifo_free(&lr->events);
kfree(lr->label);
@ -1506,7 +1515,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
struct gpio_v2_line_config *lc;
struct linereq *lr;
struct file *file;
u64 flags;
u64 flags, edflags;
unsigned int i;
int fd, ret;
@ -1580,6 +1589,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
if (ret < 0)
goto out_free_linereq;
edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS;
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
@ -1596,12 +1606,13 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
goto out_free_linereq;
ret = edge_detector_setup(&lr->lines[i], lc, i,
flags & GPIO_V2_LINE_EDGE_FLAGS,
flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE);
edflags);
if (ret)
goto out_free_linereq;
}
lr->lines[i].edflags = edflags;
blocking_notifier_call_chain(&desc->gdev->notifier,
GPIO_V2_LINE_CHANGED_REQUESTED, desc);

View File

@ -375,9 +375,6 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
}
EXPORT_SYMBOL_GPL(devm_gpiod_put_array);
static void devm_gpio_release(struct device *dev, void *res)
{
unsigned *gpio = res;
@ -385,13 +382,6 @@ static void devm_gpio_release(struct device *dev, void *res)
gpio_free(*gpio);
}
static int devm_gpio_match(struct device *dev, void *res, void *data)
{
unsigned *this = res, *gpio = data;
return *this == *gpio;
}
/**
* devm_gpio_request - request a GPIO for a managed device
* @dev: device to request the GPIO for
@ -402,11 +392,7 @@ static int devm_gpio_match(struct device *dev, void *res, void *data)
* same arguments and performs the same function as
* gpio_request(). GPIOs requested with this function will be
* automatically freed on driver detach.
*
* If an GPIO allocated with this function needs to be freed
* separately, devm_gpio_free() must be used.
*/
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
{
unsigned *dr;
@ -459,24 +445,6 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
}
EXPORT_SYMBOL_GPL(devm_gpio_request_one);
/**
* devm_gpio_free - free a GPIO
* @dev: device to free GPIO for
* @gpio: GPIO to free
*
* Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as gpio_free().
* This function instead of gpio_free() should be used to manually
* free GPIOs allocated with devm_gpio_request().
*/
void devm_gpio_free(struct device *dev, unsigned int gpio)
{
WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
&gpio));
}
EXPORT_SYMBOL_GPL(devm_gpio_free);
static void devm_gpio_chip_release(void *data)
{
struct gpio_chip *gc = data;

View File

@ -354,6 +354,9 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
if (flags & OF_GPIO_PULL_DOWN)
lflags |= GPIO_PULL_DOWN;
if (flags & OF_GPIO_PULL_DISABLE)
lflags |= GPIO_PULL_DISABLE;
ret = gpiod_configure_flags(desc, propname, lflags, dflags);
if (ret < 0) {
gpiod_put(desc);
@ -556,6 +559,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
*flags |= GPIO_PULL_UP;
if (of_flags & OF_GPIO_PULL_DOWN)
*flags |= GPIO_PULL_DOWN;
if (of_flags & OF_GPIO_PULL_DISABLE)
*flags |= GPIO_PULL_DISABLE;
return desc;
}
@ -621,6 +626,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
*lflags |= GPIO_PULL_UP;
if (xlate_flags & OF_GPIO_PULL_DOWN)
*lflags |= GPIO_PULL_DOWN;
if (xlate_flags & OF_GPIO_PULL_DISABLE)
*lflags |= GPIO_PULL_DISABLE;
if (of_property_read_bool(np, "input"))
*dflags |= GPIOD_IN;
@ -720,7 +727,7 @@ static void of_gpiochip_remove_hog(struct gpio_chip *chip,
static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
{
return chip->gpiodev->dev.of_node == data;
return device_match_of_node(&chip->gpiodev->dev, data);
}
static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
@ -860,7 +867,8 @@ int of_mm_gpiochip_add_data(struct device_node *np,
if (mm_gc->save_regs)
mm_gc->save_regs(mm_gc);
mm_gc->gc.of_node = np;
of_node_put(mm_gc->gc.of_node);
mm_gc->gc.of_node = of_node_get(np);
ret = gpiochip_add_data(gc, data);
if (ret)
@ -868,6 +876,7 @@ int of_mm_gpiochip_add_data(struct device_node *np,
return 0;
err2:
of_node_put(np);
iounmap(mm_gc->regs);
err1:
kfree(gc->label);

View File

@ -3942,9 +3942,11 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
if (lflags & GPIO_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
if ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) {
if (((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) ||
((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DISABLE)) ||
((lflags & GPIO_PULL_DOWN) && (lflags & GPIO_PULL_DISABLE))) {
gpiod_err(desc,
"both pull-up and pull-down enabled, invalid configuration\n");
"multiple pull-up, pull-down or pull-disable enabled, invalid configuration\n");
return -EINVAL;
}
@ -3952,6 +3954,8 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
set_bit(FLAG_PULL_UP, &desc->flags);
else if (lflags & GPIO_PULL_DOWN)
set_bit(FLAG_PULL_DOWN, &desc->flags);
else if (lflags & GPIO_PULL_DISABLE)
set_bit(FLAG_BIAS_DISABLE, &desc->flags);
ret = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
if (ret < 0)

View File

@ -72,11 +72,9 @@ static int ucb1400_core_probe(struct device *dev)
/* GPIO */
ucb_gpio.ac97 = ac97;
if (pdata) {
ucb_gpio.gpio_setup = pdata->gpio_setup;
ucb_gpio.gpio_teardown = pdata->gpio_teardown;
if (pdata)
ucb_gpio.gpio_offset = pdata->gpio_offset;
}
ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1);
if (!ucb->ucb1400_gpio) {
err = -ENOMEM;

View File

@ -39,4 +39,7 @@
/* Bit 5 express pull down */
#define GPIO_PULL_DOWN 32
/* Bit 6 express pull disable */
#define GPIO_PULL_DISABLE 64
#endif

View File

@ -95,7 +95,6 @@ struct device;
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
int devm_gpio_request_one(struct device *dev, unsigned gpio,
unsigned long flags, const char *label);
void devm_gpio_free(struct device *dev, unsigned int gpio);
#else /* ! CONFIG_GPIOLIB */
@ -240,11 +239,6 @@ static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
return -EINVAL;
}
static inline void devm_gpio_free(struct device *dev, unsigned int gpio)
{
WARN_ON(1);
}
#endif /* ! CONFIG_GPIOLIB */
#endif /* __LINUX_GPIO_H */

View File

@ -14,6 +14,7 @@ enum gpio_lookup_flags {
GPIO_TRANSITORY = (1 << 3),
GPIO_PULL_UP = (1 << 4),
GPIO_PULL_DOWN = (1 << 5),
GPIO_PULL_DISABLE = (1 << 6),
GPIO_LOOKUP_FLAGS_DEFAULT = GPIO_ACTIVE_HIGH | GPIO_PERSISTENT,
};

View File

@ -594,8 +594,6 @@ struct twl4030_gpio_platform_data {
int (*setup)(struct device *dev,
unsigned gpio, unsigned ngpio);
int (*teardown)(struct device *dev,
unsigned gpio, unsigned ngpio);
};
struct twl4030_madc_platform_data {

View File

@ -29,6 +29,7 @@ enum of_gpio_flags {
OF_GPIO_TRANSITORY = 0x8,
OF_GPIO_PULL_UP = 0x10,
OF_GPIO_PULL_DOWN = 0x20,
OF_GPIO_PULL_DISABLE = 0x40,
};
#ifdef CONFIG_OF_GPIO

View File

@ -84,8 +84,6 @@ struct ucb1400_gpio {
struct gpio_chip gc;
struct snd_ac97 *ac97;
int gpio_offset;
int (*gpio_setup)(struct device *dev, int ngpio);
int (*gpio_teardown)(struct device *dev, int ngpio);
};
struct ucb1400_ts {