diff options
Diffstat (limited to 'drivers/gpio/gpio-generic.c')
| -rw-r--r-- | drivers/gpio/gpio-generic.c | 103 |
1 files changed, 78 insertions, 25 deletions
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index e38dd0c3197..fea8c82bb8f 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -104,6 +104,26 @@ static unsigned long bgpio_read64(void __iomem *reg) } #endif /* BITS_PER_LONG >= 64 */ +static void bgpio_write16be(void __iomem *reg, unsigned long data) +{ + iowrite16be(data, reg); +} + +static unsigned long bgpio_read16be(void __iomem *reg) +{ + return ioread16be(reg); +} + +static void bgpio_write32be(void __iomem *reg, unsigned long data) +{ + iowrite32be(data, reg); +} + +static unsigned long bgpio_read32be(void __iomem *reg) +{ + return ioread32be(reg); +} + static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin) { return 1 << pin; @@ -119,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct bgpio_chip *bgc = to_bgpio_chip(gc); - return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio); + return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) @@ -249,7 +269,8 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) static int bgpio_setup_accessors(struct device *dev, struct bgpio_chip *bgc, - bool be) + bool bit_be, + bool byte_be) { switch (bgc->bits) { @@ -258,17 +279,33 @@ static int bgpio_setup_accessors(struct device *dev, bgc->write_reg = bgpio_write8; break; case 16: - bgc->read_reg = bgpio_read16; - bgc->write_reg = bgpio_write16; + if (byte_be) { + bgc->read_reg = bgpio_read16be; + bgc->write_reg = bgpio_write16be; + } else { + bgc->read_reg = bgpio_read16; + bgc->write_reg = bgpio_write16; + } break; case 32: - bgc->read_reg = bgpio_read32; - bgc->write_reg = bgpio_write32; + if (byte_be) { + bgc->read_reg = bgpio_read32be; + bgc->write_reg = bgpio_write32be; + } else { + bgc->read_reg = bgpio_read32; + bgc->write_reg = bgpio_write32; + } break; #if BITS_PER_LONG >= 64 case 64: - bgc->read_reg = bgpio_read64; - bgc->write_reg = bgpio_write64; + if (byte_be) { + dev_err(dev, + "64 bit big endian byte order unsupported\n"); + return -EINVAL; + } else { + bgc->read_reg = bgpio_read64; + bgc->write_reg = bgpio_write64; + } break; #endif /* BITS_PER_LONG >= 64 */ default: @@ -276,7 +313,7 @@ static int bgpio_setup_accessors(struct device *dev, return -EINVAL; } - bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask; + bgc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask; return 0; } @@ -351,20 +388,24 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, return 0; } -int bgpio_remove(struct bgpio_chip *bgc) +static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) { - int err = gpiochip_remove(&bgc->gc); + if (gpio_pin < chip->ngpio) + return 0; - kfree(bgc); + return -EINVAL; +} - return err; +int bgpio_remove(struct bgpio_chip *bgc) +{ + return gpiochip_remove(&bgc->gc); } EXPORT_SYMBOL_GPL(bgpio_remove); int bgpio_init(struct bgpio_chip *bgc, struct device *dev, unsigned long sz, void __iomem *dat, void __iomem *set, void __iomem *clr, void __iomem *dirout, void __iomem *dirin, - bool big_endian) + unsigned long flags) { int ret; @@ -380,12 +421,14 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, bgc->gc.label = dev_name(dev); bgc->gc.base = -1; bgc->gc.ngpio = bgc->bits; + bgc->gc.request = bgpio_request; ret = bgpio_setup_io(bgc, dat, set, clr); if (ret) return ret; - ret = bgpio_setup_accessors(dev, bgc, big_endian); + ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN, + flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER); if (ret) return ret; @@ -394,6 +437,11 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, return ret; bgc->data = bgc->read_reg(bgc->reg_dat); + if (bgc->gc.set == bgpio_set_set && + !(flags & BGPIOF_UNREADABLE_REG_SET)) + bgc->data = bgc->read_reg(bgc->reg_set); + if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR)) + bgc->dir = bgc->read_reg(bgc->reg_dir); return ret; } @@ -439,7 +487,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev, return ret; } -static int __devinit bgpio_pdev_probe(struct platform_device *pdev) +static int bgpio_pdev_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *r; @@ -449,7 +497,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) void __iomem *dirout; void __iomem *dirin; unsigned long sz; - bool be; + unsigned long flags = pdev->id_entry->driver_data; int err; struct bgpio_chip *bgc; struct bgpio_pdata *pdata = dev_get_platdata(dev); @@ -480,17 +528,17 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) if (err) return err; - be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"); - bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); if (!bgc) return -ENOMEM; - err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be); + err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, flags); if (err) return err; if (pdata) { + if (pdata->label) + bgc->gc.label = pdata->label; bgc->gc.base = pdata->base; if (pdata->ngpio > 0) bgc->gc.ngpio = pdata->ngpio; @@ -501,7 +549,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) return gpiochip_add(&bgc->gc); } -static int __devexit bgpio_pdev_remove(struct platform_device *pdev) +static int bgpio_pdev_remove(struct platform_device *pdev) { struct bgpio_chip *bgc = platform_get_drvdata(pdev); @@ -509,9 +557,14 @@ static int __devexit bgpio_pdev_remove(struct platform_device *pdev) } static const struct platform_device_id bgpio_id_table[] = { - { "basic-mmio-gpio", }, - { "basic-mmio-gpio-be", }, - {}, + { + .name = "basic-mmio-gpio", + .driver_data = 0, + }, { + .name = "basic-mmio-gpio-be", + .driver_data = BGPIOF_BIG_ENDIAN, + }, + { } }; MODULE_DEVICE_TABLE(platform, bgpio_id_table); @@ -521,7 +574,7 @@ static struct platform_driver bgpio_driver = { }, .id_table = bgpio_id_table, .probe = bgpio_pdev_probe, - .remove = __devexit_p(bgpio_pdev_remove), + .remove = bgpio_pdev_remove, }; module_platform_driver(bgpio_driver); |
