diff options
Diffstat (limited to 'drivers/gpio/gpio-sx150x.c')
-rw-r--r-- | drivers/gpio/gpio-sx150x.c | 248 |
1 files changed, 147 insertions, 101 deletions
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index bce6c6108f20..88012e2b5b15 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -23,23 +23,51 @@ #include <linux/mutex.h> #include <linux/slab.h> #include <linux/i2c/sx150x.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> #define NO_UPDATE_PENDING -1 +/* The chip models of sx150x */ +#define SX150X_456 0 +#define SX150X_789 1 + +struct sx150x_456_pri { + u8 reg_pld_mode; + u8 reg_pld_table0; + u8 reg_pld_table1; + u8 reg_pld_table2; + u8 reg_pld_table3; + u8 reg_pld_table4; + u8 reg_advance; +}; + +struct sx150x_789_pri { + u8 reg_drain; + u8 reg_polarity; + u8 reg_clock; + u8 reg_misc; + u8 reg_reset; + u8 ngpios; +}; + struct sx150x_device_data { + u8 model; u8 reg_pullup; u8 reg_pulldn; - u8 reg_drain; - u8 reg_polarity; u8 reg_dir; u8 reg_data; u8 reg_irq_mask; u8 reg_irq_src; u8 reg_sense; - u8 reg_clock; - u8 reg_misc; - u8 reg_reset; u8 ngpios; + union { + struct sx150x_456_pri x456; + struct sx150x_789_pri x789; + } pri; }; struct sx150x_chip { @@ -59,44 +87,78 @@ struct sx150x_chip { static const struct sx150x_device_data sx150x_devices[] = { [0] = { /* sx1508q */ - .reg_pullup = 0x03, - .reg_pulldn = 0x04, - .reg_drain = 0x05, - .reg_polarity = 0x06, - .reg_dir = 0x07, - .reg_data = 0x08, - .reg_irq_mask = 0x09, - .reg_irq_src = 0x0c, - .reg_sense = 0x0b, - .reg_clock = 0x0f, - .reg_misc = 0x10, - .reg_reset = 0x7d, - .ngpios = 8 + .model = SX150X_789, + .reg_pullup = 0x03, + .reg_pulldn = 0x04, + .reg_dir = 0x07, + .reg_data = 0x08, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0c, + .reg_sense = 0x0b, + .pri.x789 = { + .reg_drain = 0x05, + .reg_polarity = 0x06, + .reg_clock = 0x0f, + .reg_misc = 0x10, + .reg_reset = 0x7d, + }, + .ngpios = 8, }, [1] = { /* sx1509q */ - .reg_pullup = 0x07, - .reg_pulldn = 0x09, - .reg_drain = 0x0b, - .reg_polarity = 0x0d, - .reg_dir = 0x0f, - .reg_data = 0x11, - .reg_irq_mask = 0x13, - .reg_irq_src = 0x19, - .reg_sense = 0x17, - .reg_clock = 0x1e, - .reg_misc = 0x1f, - .reg_reset = 0x7d, - .ngpios = 16 + .model = SX150X_789, + .reg_pullup = 0x07, + .reg_pulldn = 0x09, + .reg_dir = 0x0f, + .reg_data = 0x11, + .reg_irq_mask = 0x13, + .reg_irq_src = 0x19, + .reg_sense = 0x17, + .pri.x789 = { + .reg_drain = 0x0b, + .reg_polarity = 0x0d, + .reg_clock = 0x1e, + .reg_misc = 0x1f, + .reg_reset = 0x7d, + }, + .ngpios = 16 + }, + [2] = { /* sx1506q */ + .model = SX150X_456, + .reg_pullup = 0x05, + .reg_pulldn = 0x07, + .reg_dir = 0x03, + .reg_data = 0x01, + .reg_irq_mask = 0x09, + .reg_irq_src = 0x0f, + .reg_sense = 0x0d, + .pri.x456 = { + .reg_pld_mode = 0x21, + .reg_pld_table0 = 0x23, + .reg_pld_table1 = 0x25, + .reg_pld_table2 = 0x27, + .reg_pld_table3 = 0x29, + .reg_pld_table4 = 0x2b, + .reg_advance = 0xad, + }, + .ngpios = 16 }, }; static const struct i2c_device_id sx150x_id[] = { {"sx1508q", 0}, {"sx1509q", 1}, + {"sx1506q", 2}, {} }; MODULE_DEVICE_TABLE(i2c, sx150x_id); +static const struct of_device_id sx150x_dt_id[] = { + { .compatible = "semtech,sx1508q" }, + { .compatible = "semtech,sx1509q" }, + { .compatible = "semtech,sx1506q" }, + {}, +}; + static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val) { s32 err = i2c_smbus_write_byte_data(client, reg, val); @@ -191,7 +253,7 @@ static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset) static void sx150x_set_oscio(struct sx150x_chip *chip, int val) { sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_clock, + chip->dev_cfg->pri.x789.reg_clock, (val ? 0x1f : 0x10)); } @@ -293,27 +355,11 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc, return status; } -static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct sx150x_chip *chip; - - chip = container_of(gc, struct sx150x_chip, gpio_chip); - - if (offset >= chip->dev_cfg->ngpios) - return -EINVAL; - - if (chip->irq_base < 0) - return -EINVAL; - - return chip->irq_base + offset; -} - static void sx150x_irq_mask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked |= (1 << n); chip->irq_update = n; } @@ -321,9 +367,8 @@ static void sx150x_irq_mask(struct irq_data *d) static void sx150x_irq_unmask(struct irq_data *d) { struct sx150x_chip *chip = irq_data_get_irq_chip_data(d); - unsigned n; + unsigned n = d->hwirq; - n = d->irq - chip->irq_base; chip->irq_masked &= ~(1 << n); chip->irq_update = n; } @@ -336,7 +381,7 @@ static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) return -EINVAL; - n = d->irq - chip->irq_base; + n = d->hwirq; if (flow_type & IRQ_TYPE_EDGE_RISING) val |= 0x1; @@ -371,7 +416,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id) val); for (n = 0; n < 8; ++n) { if (val & (1 << n)) { - sub_irq = chip->irq_base + (i * 8) + n; + sub_irq = irq_find_mapping( + chip->gpio_chip.irqdomain, + (i * 8) + n); handle_nested_irq(sub_irq); ++nhandled; } @@ -401,7 +448,7 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d) /* Avoid updates if nothing changed */ if (chip->dev_sense == chip->irq_sense && - chip->dev_sense == chip->irq_masked) + chip->dev_masked == chip->irq_masked) goto out; chip->dev_sense = chip->irq_sense; @@ -428,15 +475,17 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->client = client; chip->dev_cfg = &sx150x_devices[driver_data]; + chip->gpio_chip.dev = &client->dev; chip->gpio_chip.label = client->name; chip->gpio_chip.direction_input = sx150x_gpio_direction_input; chip->gpio_chip.direction_output = sx150x_gpio_direction_output; chip->gpio_chip.get = sx150x_gpio_get; chip->gpio_chip.set = sx150x_gpio_set; - chip->gpio_chip.to_irq = sx150x_gpio_to_irq; chip->gpio_chip.base = pdata->gpio_base; chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; + chip->gpio_chip.of_node = client->dev.of_node; + chip->gpio_chip.of_gpio_n_cells = 2; if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; @@ -470,13 +519,13 @@ static int sx150x_reset(struct sx150x_chip *chip) int err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x12); if (err < 0) return err; err = i2c_smbus_write_byte_data(chip->client, - chip->dev_cfg->reg_reset, + chip->dev_cfg->pri.x789.reg_reset, 0x34); return err; } @@ -492,9 +541,14 @@ static int sx150x_init_hw(struct sx150x_chip *chip, return err; } - err = sx150x_i2c_write(chip->client, - chip->dev_cfg->reg_misc, - 0x01); + if (chip->dev_cfg->model == SX150X_789) + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x789.reg_misc, + 0x01); + else + err = sx150x_i2c_write(chip->client, + chip->dev_cfg->pri.x456.reg_advance, + 0x04); if (err < 0) return err; @@ -508,15 +562,27 @@ static int sx150x_init_hw(struct sx150x_chip *chip, if (err < 0) return err; - err = sx150x_init_io(chip, chip->dev_cfg->reg_drain, - pdata->io_open_drain_ena); - if (err < 0) - return err; + if (chip->dev_cfg->model == SX150X_789) { + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_drain, + pdata->io_open_drain_ena); + if (err < 0) + return err; + + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x789.reg_polarity, + pdata->io_polarity); + if (err < 0) + return err; + } else { + /* Set all pins to work in normal mode */ + err = sx150x_init_io(chip, + chip->dev_cfg->pri.x456.reg_pld_mode, + 0); + if (err < 0) + return err; + } - err = sx150x_init_io(chip, chip->dev_cfg->reg_polarity, - pdata->io_polarity); - if (err < 0) - return err; if (pdata->oscio_is_gpo) sx150x_set_oscio(chip, 0); @@ -529,31 +595,24 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, int irq_base) { int err; - unsigned n; - unsigned irq; chip->irq_summary = irq_summary; chip->irq_base = irq_base; - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = irq_base + n; - irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &chip->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 + /* Add gpio chip to irq subsystem */ + err = gpiochip_irqchip_add(&chip->gpio_chip, + &chip->irq_chip, chip->irq_base, + handle_edge_irq, IRQ_TYPE_EDGE_BOTH); + if (err) { + dev_err(&chip->client->dev, + "could not connect irqchip to gpiochip\n"); + return err; } err = devm_request_threaded_irq(&chip->client->dev, - irq_summary, - NULL, - sx150x_irq_thread_fn, - IRQF_SHARED | IRQF_TRIGGER_FALLING, - chip->irq_chip.name, - chip); + irq_summary, NULL, sx150x_irq_thread_fn, + IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING, + chip->irq_chip.name, chip); if (err < 0) { chip->irq_summary = -1; chip->irq_base = -1; @@ -562,17 +621,6 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, return err; } -static void sx150x_remove_irq_chip(struct sx150x_chip *chip) -{ - unsigned n; - unsigned irq; - - for (n = 0; n < chip->dev_cfg->ngpios; ++n) { - irq = chip->irq_base + n; - irq_set_chip_and_handler(irq, NULL, NULL); - } -} - static int sx150x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -626,16 +674,14 @@ static int sx150x_remove(struct i2c_client *client) chip = i2c_get_clientdata(client); gpiochip_remove(&chip->gpio_chip); - if (chip->irq_summary >= 0) - sx150x_remove_irq_chip(chip); - return 0; } static struct i2c_driver sx150x_driver = { .driver = { .name = "sx150x", - .owner = THIS_MODULE + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sx150x_dt_id), }, .probe = sx150x_probe, .remove = sx150x_remove, |