diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpiolib.c | 129 | ||||
-rw-r--r-- | drivers/gpio/mcp23s08.c | 3 | ||||
-rw-r--r-- | drivers/gpio/pca953x.c | 30 | ||||
-rw-r--r-- | drivers/gpio/pcf857x.c | 37 |
4 files changed, 145 insertions, 54 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d8db2f8ee41..beaf6b3a37d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -43,6 +43,7 @@ struct gpio_desc { /* flag symbols are bit numbers */ #define FLAG_REQUESTED 0 #define FLAG_IS_OUT 1 +#define FLAG_RESERVED 2 #ifdef CONFIG_DEBUG_FS const char *label; @@ -68,6 +69,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc)); desc_set_label(desc, "[auto]"); + if (!try_module_get(desc->chip->owner)) + pr_err("GPIO-%d: module can't be gotten \n", + (int)(desc - gpio_desc)); } } @@ -77,6 +81,76 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) return gpio_desc[gpio].chip; } +/* dynamic allocation of GPIOs, e.g. on a hotplugged device */ +static int gpiochip_find_base(int ngpio) +{ + int i; + int spare = 0; + int base = -ENOSPC; + + for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { + struct gpio_desc *desc = &gpio_desc[i]; + struct gpio_chip *chip = desc->chip; + + if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) { + spare++; + if (spare == ngpio) { + base = i; + break; + } + } else { + spare = 0; + if (chip) + i -= chip->ngpio - 1; + } + } + + if (gpio_is_valid(base)) + pr_debug("%s: found new base at %d\n", __func__, base); + return base; +} + +/** + * gpiochip_reserve() - reserve range of gpios to use with platform code only + * @start: starting gpio number + * @ngpio: number of gpios to reserve + * Context: platform init, potentially before irqs or kmalloc will work + * + * Returns a negative errno if any gpio within the range is already reserved + * or registered, else returns zero as a success code. Use this function + * to mark a range of gpios as unavailable for dynamic gpio number allocation, + * for example because its driver support is not yet loaded. + */ +int __init gpiochip_reserve(int start, int ngpio) +{ + int ret = 0; + unsigned long flags; + int i; + + if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1)) + return -EINVAL; + + spin_lock_irqsave(&gpio_lock, flags); + + for (i = start; i < start + ngpio; i++) { + struct gpio_desc *desc = &gpio_desc[i]; + + if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) { + ret = -EBUSY; + goto err; + } + + set_bit(FLAG_RESERVED, &desc->flags); + } + + pr_debug("%s: reserved gpios from %d to %d\n", + __func__, start, start + ngpio - 1); +err: + spin_unlock_irqrestore(&gpio_lock, flags); + + return ret; +} + /** * gpiochip_add() - register a gpio_chip * @chip: the chip to register, with chip->base initialized @@ -85,44 +159,55 @@ static inline struct gpio_chip *gpio_to_chip(unsigned gpio) * Returns a negative errno if the chip can't be registered, such as * because the chip->base is invalid or already associated with a * different chip. Otherwise it returns zero as a success code. + * + * If chip->base is negative, this requests dynamic assignment of + * a range of valid GPIOs. */ int gpiochip_add(struct gpio_chip *chip) { unsigned long flags; int status = 0; unsigned id; + int base = chip->base; - /* NOTE chip->base negative is reserved to mean a request for - * dynamic allocation. We don't currently support that. - */ - - if (chip->base < 0 || (chip->base + chip->ngpio) >= ARCH_NR_GPIOS) { + if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) + && base >= 0) { status = -EINVAL; goto fail; } spin_lock_irqsave(&gpio_lock, flags); + if (base < 0) { + base = gpiochip_find_base(chip->ngpio); + if (base < 0) { + status = base; + goto fail_unlock; + } + chip->base = base; + } + /* these GPIO numbers must not be managed by another gpio_chip */ - for (id = chip->base; id < chip->base + chip->ngpio; id++) { + for (id = base; id < base + chip->ngpio; id++) { if (gpio_desc[id].chip != NULL) { status = -EBUSY; break; } } if (status == 0) { - for (id = chip->base; id < chip->base + chip->ngpio; id++) { + for (id = base; id < base + chip->ngpio; id++) { gpio_desc[id].chip = chip; gpio_desc[id].flags = 0; } } +fail_unlock: spin_unlock_irqrestore(&gpio_lock, flags); fail: /* failures here can mean systems won't boot... */ if (status) pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n", - chip->base, chip->base + chip->ngpio, + chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); return status; } @@ -171,12 +256,15 @@ int gpio_request(unsigned gpio, const char *label) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto done; desc = &gpio_desc[gpio]; if (desc->chip == NULL) goto done; + if (!try_module_get(desc->chip->owner)) + goto done; + /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled. */ @@ -184,8 +272,10 @@ int gpio_request(unsigned gpio, const char *label) if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { desc_set_label(desc, label ? : "?"); status = 0; - } else + } else { status = -EBUSY; + module_put(desc->chip->owner); + } done: if (status) @@ -201,7 +291,7 @@ void gpio_free(unsigned gpio) unsigned long flags; struct gpio_desc *desc; - if (gpio >= ARCH_NR_GPIOS) { + if (!gpio_is_valid(gpio)) { WARN_ON(extra_checks); return; } @@ -209,9 +299,10 @@ void gpio_free(unsigned gpio) spin_lock_irqsave(&gpio_lock, flags); desc = &gpio_desc[gpio]; - if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) + if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) { desc_set_label(desc, NULL); - else + module_put(desc->chip->owner); + } else WARN_ON(extra_checks); spin_unlock_irqrestore(&gpio_lock, flags); @@ -236,7 +327,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) { unsigned gpio = chip->base + offset; - if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip) + if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip) return NULL; if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0) return NULL; @@ -267,7 +358,7 @@ int gpio_direction_input(unsigned gpio) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto fail; chip = desc->chip; if (!chip || !chip->get || !chip->direction_input) @@ -291,7 +382,7 @@ fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) pr_debug("%s: gpio-%d status %d\n", - __FUNCTION__, gpio, status); + __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_direction_input); @@ -305,7 +396,7 @@ int gpio_direction_output(unsigned gpio, int value) spin_lock_irqsave(&gpio_lock, flags); - if (gpio >= ARCH_NR_GPIOS) + if (!gpio_is_valid(gpio)) goto fail; chip = desc->chip; if (!chip || !chip->set || !chip->direction_output) @@ -329,7 +420,7 @@ fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) pr_debug("%s: gpio-%d status %d\n", - __FUNCTION__, gpio, status); + __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_direction_output); @@ -522,7 +613,7 @@ static int gpiolib_show(struct seq_file *s, void *unused) /* REVISIT this isn't locked against gpio_chip removal ... */ - for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) { + for (gpio = 0; gpio_is_valid(gpio); gpio++) { if (chip == gpio_desc[gpio].chip) continue; chip = gpio_desc[gpio].chip; diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c index bb60e8c1a1f..7f92fdd5f0e 100644 --- a/drivers/gpio/mcp23s08.c +++ b/drivers/gpio/mcp23s08.c @@ -168,7 +168,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) { struct mcp23s08 *mcp; char bank; - unsigned t; + int t; unsigned mask; mcp = container_of(chip, struct mcp23s08, chip); @@ -239,6 +239,7 @@ static int mcp23s08_probe(struct spi_device *spi) mcp->chip.base = pdata->base; mcp->chip.ngpio = 8; mcp->chip.can_sleep = 1; + mcp->chip.owner = THIS_MODULE; spi_set_drvdata(spi, mcp); diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 6e72fd31184..7e40e8a55ed 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -23,21 +23,20 @@ #define PCA953X_INVERT 2 #define PCA953X_DIRECTION 3 -/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */ -struct pca953x_desc { - char name[I2C_NAME_SIZE]; - unsigned long driver_data; -}; - -static const struct pca953x_desc pca953x_descs[] = { +static const struct i2c_device_id pca953x_id[] = { { "pca9534", 8, }, { "pca9535", 16, }, { "pca9536", 4, }, { "pca9537", 4, }, { "pca9538", 8, }, { "pca9539", 16, }, + { "pca9554", 8, }, + { "pca9555", 16, }, + { "pca9557", 8, }, /* REVISIT several pca955x parts should work here too */ + { } }; +MODULE_DEVICE_TABLE(i2c, pca953x_id); struct pca953x_chip { unsigned gpio_start; @@ -189,28 +188,20 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->base = chip->gpio_start; gc->ngpio = gpios; gc->label = chip->client->name; + gc->owner = THIS_MODULE; } -static int __devinit pca953x_probe(struct i2c_client *client) +static int __devinit pca953x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pca953x_platform_data *pdata; struct pca953x_chip *chip; - int ret, i; - const struct pca953x_desc *id = NULL; + int ret; pdata = client->dev.platform_data; if (pdata == NULL) return -ENODEV; - /* this loop vanishes when we get i2c_device_id */ - for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++) - if (!strcmp(pca953x_descs[i].name, client->name)) { - id = pca953x_descs + i; - break; - } - if (!id) - return -ENODEV; - chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -290,6 +281,7 @@ static struct i2c_driver pca953x_driver = { }, .probe = pca953x_probe, .remove = pca953x_remove, + .id_table = pca953x_id, }; static int __init pca953x_init(void) diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c index c6b3b537838..aa6cc8b2a2b 100644 --- a/drivers/gpio/pcf857x.c +++ b/drivers/gpio/pcf857x.c @@ -26,6 +26,21 @@ #include <asm/gpio.h> +static const struct i2c_device_id pcf857x_id[] = { + { "pcf8574", 8 }, + { "pca8574", 8 }, + { "pca9670", 8 }, + { "pca9672", 8 }, + { "pca9674", 8 }, + { "pcf8575", 16 }, + { "pca8575", 16 }, + { "pca9671", 16 }, + { "pca9673", 16 }, + { "pca9675", 16 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf857x_id); + /* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets @@ -142,7 +157,8 @@ static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value) /*-------------------------------------------------------------------------*/ -static int pcf857x_probe(struct i2c_client *client) +static int pcf857x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pcf857x_platform_data *pdata; struct pcf857x *gpio; @@ -159,6 +175,7 @@ static int pcf857x_probe(struct i2c_client *client) gpio->chip.base = pdata->gpio_base; gpio->chip.can_sleep = 1; + gpio->chip.owner = THIS_MODULE; /* NOTE: the OnSemi jlc1562b is also largely compatible with * these parts, notably for output. It has a low-resolution @@ -171,13 +188,8 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between *4 and *4a parts. */ - if (strcmp(client->name, "pcf8574") == 0 - || strcmp(client->name, "pca8574") == 0 - || strcmp(client->name, "pca9670") == 0 - || strcmp(client->name, "pca9672") == 0 - || strcmp(client->name, "pca9674") == 0 - ) { - gpio->chip.ngpio = 8; + gpio->chip.ngpio = id->driver_data; + if (gpio->chip.ngpio == 8) { gpio->chip.direction_input = pcf857x_input8; gpio->chip.get = pcf857x_get8; gpio->chip.direction_output = pcf857x_output8; @@ -197,13 +209,7 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between '75 and '75c parts. */ - } else if (strcmp(client->name, "pcf8575") == 0 - || strcmp(client->name, "pca8575") == 0 - || strcmp(client->name, "pca9671") == 0 - || strcmp(client->name, "pca9673") == 0 - || strcmp(client->name, "pca9675") == 0 - ) { - gpio->chip.ngpio = 16; + } else if (gpio->chip.ngpio == 16) { gpio->chip.direction_input = pcf857x_input16; gpio->chip.get = pcf857x_get16; gpio->chip.direction_output = pcf857x_output16; @@ -312,6 +318,7 @@ static struct i2c_driver pcf857x_driver = { }, .probe = pcf857x_probe, .remove = pcf857x_remove, + .id_table = pcf857x_id, }; static int __init pcf857x_init(void) |