diff options
Diffstat (limited to 'drivers/gpio/gpio-gpio-mm.c')
| -rw-r--r-- | drivers/gpio/gpio-gpio-mm.c | 289 |
1 files changed, 36 insertions, 253 deletions
diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index b89b8c5ff1f5..fb7c510bf2fa 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -6,18 +6,19 @@ * 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> -#include <linux/io.h> #include <linux/ioport.h> #include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/spinlock.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include "gpio-i8255.h" + +MODULE_IMPORT_NS("I8255"); #define GPIOMM_EXTENT 8 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) @@ -27,218 +28,24 @@ 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"); -/** - * 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 - */ -struct gpiomm_gpio { - struct gpio_chip chip; - unsigned char io_state[6]; - unsigned char out_state[6]; - unsigned char control[2]; - spinlock_t lock; - unsigned int base; -}; - -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) - return GPIO_LINE_DIRECTION_IN; - - return GPIO_LINE_DIRECTION_OUT; -} - -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; - const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4; - 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]; - outb(control, control_addr); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - - return 0; -} - -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 control_addr = gpiommgpio->base + 3 + control_port*4; - 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]; - outb(control, control_addr); - - outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - - return 0; -} - -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 = inb(gpiommgpio->base + in_port); +#define GPIOMM_NUM_PPI 2 - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - - return !!(port_state & mask); -} - -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; - unsigned int 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 = inb(port_addr) & gpio_mask; - - bitmap_set_value8(bits, port_state, offset); - } - - return 0; -} - -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; - - outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); -} - -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; - unsigned int 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; - outb(gpiommgpio->out_state[index], port_addr); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - } -} +static const struct regmap_range gpiomm_volatile_ranges[] = { + i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4), +}; +static const struct regmap_access_table gpiomm_volatile_table = { + .yes_ranges = gpiomm_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(gpiomm_volatile_ranges), +}; +static const struct regmap_config gpiomm_regmap_config = { + .reg_bits = 8, + .reg_stride = 1, + .val_bits = 8, + .io_port = true, + .max_register = 0x7, + .volatile_table = &gpiomm_volatile_table, + .cache_type = REGCACHE_FLAT, +}; #define GPIOMM_NGPIO 48 static const char *gpiomm_names[GPIOMM_NGPIO] = { @@ -254,13 +61,9 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = { static int gpiomm_probe(struct device *dev, unsigned int id) { - struct gpiomm_gpio *gpiommgpio; const char *const name = dev_name(dev); - int err; - - gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL); - if (!gpiommgpio) - return -ENOMEM; + struct i8255_regmap_config config = {}; + void __iomem *regs; if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -268,40 +71,20 @@ static int gpiomm_probe(struct device *dev, unsigned int id) return -EBUSY; } - gpiommgpio->chip.label = name; - gpiommgpio->chip.parent = dev; - gpiommgpio->chip.owner = THIS_MODULE; - gpiommgpio->chip.base = -1; - gpiommgpio->chip.ngpio = GPIOMM_NGPIO; - gpiommgpio->chip.names = gpiomm_names; - gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction; - gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input; - gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output; - gpiommgpio->chip.get = gpiomm_gpio_get; - gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple; - gpiommgpio->chip.set = gpiomm_gpio_set; - gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; - gpiommgpio->base = base[id]; - - spin_lock_init(&gpiommgpio->lock); + regs = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); + if (!regs) + return -ENOMEM; - err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); - return err; - } + config.map = devm_regmap_init_mmio(dev, regs, &gpiomm_regmap_config); + if (IS_ERR(config.map)) + return dev_err_probe(dev, PTR_ERR(config.map), + "Unable to initialize register map\n"); - /* initialize all GPIO as output */ - outb(0x80, base[id] + 3); - outb(0x00, base[id]); - outb(0x00, base[id] + 1); - outb(0x00, base[id] + 2); - outb(0x80, base[id] + 7); - outb(0x00, base[id] + 4); - outb(0x00, base[id] + 5); - outb(0x00, base[id] + 6); + config.parent = dev; + config.num_ppi = GPIOMM_NUM_PPI; + config.names = gpiomm_names; - return 0; + return devm_i8255_regmap_register(dev, &config); } static struct isa_driver gpiomm_driver = { |
