diff options
Diffstat (limited to 'drivers/gpio/gpio-max732x.c')
| -rw-r--r-- | drivers/gpio/gpio-max732x.c | 337 |
1 files changed, 180 insertions, 157 deletions
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index d4b51b163b03..a61d670ceeda 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -1,27 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MAX732x I2C Port Expander with 8/16 I/O * * Copyright (C) 2007 Marvell International Ltd. * Copyright (C) 2008 Jack Ren <jack.ren@marvell.com> * Copyright (C) 2008 Eric Miao <eric.miao@marvell.com> + * Copyright (C) 2015 Linus Walleij <linus.walleij@linaro.org> * * Derived from drivers/gpio/pca953x.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. */ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/interrupt.h> -#include <linux/irq.h> #include <linux/i2c.h> -#include <linux/i2c/max732x.h> - +#include <linux/platform_data/max732x.h> /* * Each port of MAX732x (including MAX7319) falls into one of the @@ -116,6 +112,20 @@ static const struct i2c_device_id max732x_id[] = { }; MODULE_DEVICE_TABLE(i2c, max732x_id); +static const struct of_device_id max732x_of_table[] = { + { .compatible = "maxim,max7319" }, + { .compatible = "maxim,max7320" }, + { .compatible = "maxim,max7321" }, + { .compatible = "maxim,max7322" }, + { .compatible = "maxim,max7323" }, + { .compatible = "maxim,max7324" }, + { .compatible = "maxim,max7325" }, + { .compatible = "maxim,max7326" }, + { .compatible = "maxim,max7327" }, + { } +}; +MODULE_DEVICE_TABLE(of, max732x_of_table); + struct max732x_chip { struct gpio_chip gpio_chip; @@ -132,13 +142,12 @@ struct max732x_chip { uint8_t reg_out[2]; #ifdef CONFIG_GPIO_MAX732X_IRQ - struct mutex irq_lock; - int irq_base; - uint8_t irq_mask; - uint8_t irq_mask_cur; - uint8_t irq_trig_raise; - uint8_t irq_trig_fall; - uint8_t irq_features; + struct mutex irq_lock; + uint8_t irq_mask; + uint8_t irq_mask_cur; + uint8_t irq_trig_raise; + uint8_t irq_trig_fall; + uint8_t irq_features; #endif }; @@ -180,31 +189,28 @@ static inline int is_group_a(struct max732x_chip *chip, unsigned off) static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = gpiochip_get_data(gc); uint8_t reg_val; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - ret = max732x_readb(chip, is_group_a(chip, off), ®_val); if (ret < 0) - return 0; + return ret; - return reg_val & (1u << (off & 0x7)); + return !!(reg_val & (1u << (off & 0x7))); } -static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask, + int val) { - struct max732x_chip *chip; - uint8_t reg_out, mask = 1u << (off & 0x7); + struct max732x_chip *chip = gpiochip_get_data(gc); + uint8_t reg_out; int ret; - chip = container_of(gc, struct max732x_chip, gpio_chip); - mutex_lock(&chip->lock); reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0]; - reg_out = (val) ? reg_out | mask : reg_out & ~mask; + reg_out = (reg_out & ~mask) | (val & mask); ret = max732x_writeb(chip, is_group_a(chip, off), reg_out); if (ret < 0) @@ -219,13 +225,36 @@ out: mutex_unlock(&chip->lock); } +static int max732x_gpio_set_value(struct gpio_chip *gc, unsigned int off, + int val) +{ + unsigned base = off & ~0x7; + uint8_t mask = 1u << (off & 0x7); + + max732x_gpio_set_mask(gc, base, mask, val << (off & 0x7)); + + return 0; +} + +static int max732x_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + unsigned mask_lo = mask[0] & 0xff; + unsigned mask_hi = (mask[0] >> 8) & 0xff; + + if (mask_lo) + max732x_gpio_set_mask(gc, 0, mask_lo, bits[0] & 0xff); + if (mask_hi) + max732x_gpio_set_mask(gc, 8, mask_hi, (bits[0] >> 8) & 0xff); + + return 0; +} + static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { - struct max732x_chip *chip; + struct max732x_chip *chip = gpiochip_get_data(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_input) == 0) { dev_dbg(&chip->client->dev, "%s port %d is output only\n", chip->client->name, off); @@ -245,11 +274,9 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off) static int max732x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { - struct max732x_chip *chip; + struct max732x_chip *chip = gpiochip_get_data(gc); unsigned int mask = 1u << off; - chip = container_of(gc, struct max732x_chip, gpio_chip); - if ((mask & chip->dir_output) == 0) { dev_dbg(&chip->client->dev, "%s port %d is input only\n", chip->client->name, off); @@ -319,31 +346,28 @@ static void max732x_irq_update_mask(struct max732x_chip *chip) mutex_unlock(&chip->lock); } -static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off) -{ - struct max732x_chip *chip; - - chip = container_of(gc, struct max732x_chip, gpio_chip); - return chip->irq_base + off; -} - static void max732x_irq_mask(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = gpiochip_get_data(gc); - chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask_cur &= ~(1 << d->hwirq); + gpiochip_disable_irq(gc, irqd_to_hwirq(d)); } static void max732x_irq_unmask(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = gpiochip_get_data(gc); - chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base); + gpiochip_enable_irq(gc, irqd_to_hwirq(d)); + chip->irq_mask_cur |= 1 << d->hwirq; } static void max732x_irq_bus_lock(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = gpiochip_get_data(gc); mutex_lock(&chip->irq_lock); chip->irq_mask_cur = chip->irq_mask; @@ -351,16 +375,28 @@ static void max732x_irq_bus_lock(struct irq_data *d) static void max732x_irq_bus_sync_unlock(struct irq_data *d) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = gpiochip_get_data(gc); + uint16_t new_irqs; + uint16_t level; max732x_irq_update_mask(chip); + + new_irqs = chip->irq_trig_fall | chip->irq_trig_raise; + while (new_irqs) { + level = __ffs(new_irqs); + max732x_gpio_direction_input(&chip->gpio_chip, level); + new_irqs &= ~(1 << level); + } + mutex_unlock(&chip->irq_lock); } static int max732x_irq_set_type(struct irq_data *d, unsigned int type) { - struct max732x_chip *chip = irq_data_get_irq_chip_data(d); - uint16_t off = d->irq - chip->irq_base; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct max732x_chip *chip = gpiochip_get_data(gc); + uint16_t off = d->hwirq; uint16_t mask = 1 << off; if (!(mask & chip->dir_input)) { @@ -385,16 +421,27 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type) else chip->irq_trig_raise &= ~mask; - return max732x_gpio_direction_input(&chip->gpio_chip, off); + return 0; } -static struct irq_chip max732x_irq_chip = { +static int max732x_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct max732x_chip *chip = irq_data_get_irq_chip_data(data); + + irq_set_irq_wake(chip->client->irq, on); + return 0; +} + +static const struct irq_chip max732x_irq_chip = { .name = "max732x", .irq_mask = max732x_irq_mask, .irq_unmask = max732x_irq_unmask, .irq_bus_lock = max732x_irq_bus_lock, .irq_bus_sync_unlock = max732x_irq_bus_sync_unlock, .irq_set_type = max732x_irq_set_type, + .irq_set_wake = max732x_irq_set_wake, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static uint8_t max732x_irq_pending(struct max732x_chip *chip) @@ -441,7 +488,8 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain, + level)); pending &= ~(1 << level); } while (pending); @@ -453,77 +501,53 @@ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { struct i2c_client *client = chip->client; - struct max732x_platform_data *pdata = client->dev.platform_data; int has_irq = max732x_features[id->driver_data] >> 32; + int irq_base = 0; int ret; - if (pdata->irq_base && has_irq != INT_NONE) { - int lvl; + if (client->irq && has_irq != INT_NONE) { + struct gpio_irq_chip *girq; - chip->irq_base = pdata->irq_base; chip->irq_features = has_irq; mutex_init(&chip->irq_lock); - for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { - int irq = lvl + chip->irq_base; - - if (!(chip->dir_input & (1 << lvl))) - continue; - - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &max732x_irq_chip, - handle_edge_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - } - - ret = request_threaded_irq(client->irq, - NULL, - max732x_irq_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(&client->dev), chip); + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, max732x_irq_handler, IRQF_ONESHOT | + IRQF_TRIGGER_FALLING | IRQF_SHARED, + dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - goto out_failed; + return ret; } - chip->gpio_chip.to_irq = max732x_gpio_to_irq; + girq = &chip->gpio_chip.irq; + gpio_irq_chip_set_chip(girq, &max732x_irq_chip); + /* This will let us handle the parent IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + girq->threaded = true; + girq->first = irq_base; /* FIXME: get rid of this */ } return 0; - -out_failed: - chip->irq_base = 0; - return ret; } -static void max732x_irq_teardown(struct max732x_chip *chip) -{ - if (chip->irq_base) - free_irq(chip->client->irq, chip); -} #else /* CONFIG_GPIO_MAX732X_IRQ */ static int max732x_irq_setup(struct max732x_chip *chip, const struct i2c_device_id *id) { struct i2c_client *client = chip->client; - struct max732x_platform_data *pdata = client->dev.platform_data; int has_irq = max732x_features[id->driver_data] >> 32; - if (pdata->irq_base && has_irq != INT_NONE) + if (client->irq && has_irq != INT_NONE) dev_warn(&client->dev, "interrupt support not compiled in\n"); return 0; } - -static void max732x_irq_teardown(struct max732x_chip *chip) -{ -} #endif static int max732x_setup_gpio(struct max732x_chip *chip, @@ -562,40 +586,61 @@ static int max732x_setup_gpio(struct max732x_chip *chip, if (chip->dir_output) { gc->direction_output = max732x_gpio_direction_output; gc->set = max732x_gpio_set_value; + gc->set_multiple = max732x_gpio_set_multiple; } gc->get = max732x_gpio_get_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = gpio_start; gc->ngpio = port; gc->label = chip->client->name; + gc->parent = &chip->client->dev; gc->owner = THIS_MODULE; return port; } -static int max732x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static struct max732x_platform_data *of_gpio_max732x(struct device *dev) +{ + struct max732x_platform_data *pdata; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->gpio_base = -1; + + return pdata; +} + +static int max732x_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct max732x_platform_data *pdata; + struct device_node *node; struct max732x_chip *chip; struct i2c_client *c; uint16_t addr_a, addr_b; int ret, nr_port; - pdata = client->dev.platform_data; - if (pdata == NULL) { + pdata = dev_get_platdata(&client->dev); + node = client->dev.of_node; + + if (!pdata && node) + pdata = of_gpio_max732x(&client->dev); + + if (!pdata) { dev_dbg(&client->dev, "no platform data\n"); return -EINVAL; } - chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip), - GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->client = client; nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base); + chip->gpio_chip.parent = &client->dev; addr_a = (client->addr & 0x0f) | 0x60; addr_b = (client->addr & 0x0f) | 0x50; @@ -604,92 +649,70 @@ static int max732x_probe(struct i2c_client *client, case 0x60: chip->client_group_a = client; if (nr_port > 8) { - c = i2c_new_dummy(client->adapter, addr_b); + c = devm_i2c_new_dummy_device(&client->dev, + client->adapter, addr_b); + if (IS_ERR(c)) { + dev_err(&client->dev, + "Failed to allocate I2C device\n"); + return PTR_ERR(c); + } chip->client_group_b = chip->client_dummy = c; } break; case 0x50: chip->client_group_b = client; if (nr_port > 8) { - c = i2c_new_dummy(client->adapter, addr_a); + c = devm_i2c_new_dummy_device(&client->dev, + client->adapter, addr_a); + if (IS_ERR(c)) { + dev_err(&client->dev, + "Failed to allocate I2C device\n"); + return PTR_ERR(c); + } chip->client_group_a = chip->client_dummy = c; } break; default: dev_err(&client->dev, "invalid I2C address specified %02x\n", client->addr); - ret = -EINVAL; - goto out_failed; + return -EINVAL; } - mutex_init(&chip->lock); - - max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); - if (nr_port > 8) - max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); - - ret = max732x_irq_setup(chip, id); - if (ret) - goto out_failed; - - ret = gpiochip_add(&chip->gpio_chip); - if (ret) - goto out_failed; - - if (pdata->setup) { - ret = pdata->setup(client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); - if (ret < 0) - dev_warn(&client->dev, "setup failed, %d\n", ret); + if (nr_port > 8 && !chip->client_dummy) { + dev_err(&client->dev, + "Failed to allocate second group I2C device\n"); + return -ENODEV; } - i2c_set_clientdata(client, chip); - return 0; - -out_failed: - max732x_irq_teardown(chip); - return ret; -} - -static int max732x_remove(struct i2c_client *client) -{ - struct max732x_platform_data *pdata = client->dev.platform_data; - struct max732x_chip *chip = i2c_get_clientdata(client); - int ret; + mutex_init(&chip->lock); - if (pdata->teardown) { - ret = pdata->teardown(client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); - if (ret < 0) { - dev_err(&client->dev, "%s failed, %d\n", - "teardown", ret); + ret = max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); + if (ret) + return ret; + if (nr_port > 8) { + ret = max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); + if (ret) return ret; - } } - ret = gpiochip_remove(&chip->gpio_chip); - if (ret) { - dev_err(&client->dev, "%s failed, %d\n", - "gpiochip_remove()", ret); + ret = max732x_irq_setup(chip, id); + if (ret) return ret; - } - - max732x_irq_teardown(chip); - /* unregister any dummy i2c_client */ - if (chip->client_dummy) - i2c_unregister_device(chip->client_dummy); + ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip); + if (ret) + return ret; + i2c_set_clientdata(client, chip); return 0; } static struct i2c_driver max732x_driver = { .driver = { - .name = "max732x", - .owner = THIS_MODULE, + .name = "max732x", + .of_match_table = max732x_of_table, }, .probe = max732x_probe, - .remove = max732x_remove, .id_table = max732x_id, }; |
