diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-04 18:34:05 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-08-04 18:34:05 -0700 |
commit | 37644cac6e8297d0908aef054caabb439c467c7d (patch) | |
tree | a17d3eec2bc18d3ad9d40165936dc9971387b6d0 /drivers/gpio/gpio-104-dio-48e.c | |
parent | 5f0848190c6dd0f5b8a2aaf0f1d900a96d96bee0 (diff) | |
parent | c4f0d16daa6d1c5d862d063379c03310387095d5 (diff) |
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
...
Diffstat (limited to 'drivers/gpio/gpio-104-dio-48e.c')
-rw-r--r-- | drivers/gpio/gpio-104-dio-48e.c | 249 |
1 files changed, 74 insertions, 175 deletions
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index f118ad9bcd33..a41551870759 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -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) { |