From 1631081993b1e6a6d668b3eb089904b88f0efc2b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 31 Oct 2012 17:03:33 +0800 Subject: [PATCH 01/12] gpio: em: Fix build errors Fix below build errors: CC [M] drivers/gpio/gpio-em.o drivers/gpio/gpio-em.c: In function 'em_gio_probe': drivers/gpio/gpio-em.c:306: error: 'err' undeclared (first use in this function) drivers/gpio/gpio-em.c:306: error: (Each undeclared identifier is reported only once drivers/gpio/gpio-em.c:306: error: for each function it appears in.) drivers/gpio/gpio-em.c:308: error: label 'err3' used but not defined drivers/gpio/gpio-em.c:279: error: label 'err2' used but not defined drivers/gpio/gpio-em.c:265: error: label 'err1' used but not defined drivers/gpio/gpio-em.c:250: error: label 'err0' used but not defined drivers/gpio/gpio-em.c:309: warning: no return statement in function returning non-void drivers/gpio/gpio-em.c: At top level: drivers/gpio/gpio-em.c:311: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:317: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:323: warning: data definition has no type or storage class drivers/gpio/gpio-em.c:323: warning: type defaults to 'int' in declaration of 'ret' drivers/gpio/gpio-em.c:323: error: 'gpio_chip' undeclared here (not in a function) drivers/gpio/gpio-em.c:323: error: initializer element is not constant drivers/gpio/gpio-em.c:324: error: expected identifier or '(' before 'if' drivers/gpio/gpio-em.c:328: error: expected identifier or '(' before 'return' drivers/gpio/gpio-em.c:330: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:332: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:334: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:336: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:338: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:340: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:342: error: expected '=', ',', ';', 'asm' or '__attribute__' before ':' token drivers/gpio/gpio-em.c:344: error: expected identifier or '(' before '}' token drivers/gpio/gpio-em.c: In function 'em_gio_remove': drivers/gpio/gpio-em.c:361: error: implicit declaration of function 'em_gio_irq_domain_cleanup' make[2]: *** [drivers/gpio/gpio-em.o] Error 1 make[1]: *** [drivers/gpio] Error 2 make: *** [drivers] Error 2 Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 88bdfe37816f..b00706329d26 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -302,8 +302,8 @@ static int __devinit em_gio_probe(struct platform_device *pdev) p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, pdata->number_of_pins, &em_gio_irq_domain_ops, p); - if (!p->irq_domain) - err = -ENXIO; + if (!p->irq_domain) { + ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); goto err3; } @@ -358,7 +358,7 @@ static int __devexit em_gio_remove(struct platform_device *pdev) free_irq(irq[1]->start, pdev); free_irq(irq[0]->start, pdev); - em_gio_irq_domain_cleanup(p); + irq_domain_remove(p->irq_domain); iounmap(p->base1); iounmap(p->base0); kfree(p); From 5c868fc629b0e645a68aec3a6834d965e71531f4 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 2 Nov 2012 16:02:25 +0100 Subject: [PATCH 02/12] gpio-pch: Set parent dev for gpio chip This will show the gpio chip as a child node under /sys/bus/pci/devices/xxxx:xx:xx.x/ Signed-off-by: Alexander Stein Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 4ad0c4f9171c..e3a14fef79e1 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -215,6 +215,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) struct gpio_chip *gpio = &chip->gpio; gpio->label = dev_name(chip->dev); + gpio->dev = chip->dev; gpio->owner = THIS_MODULE; gpio->direction_input = pch_gpio_direction_input; gpio->get = pch_gpio_get; From 8939ddc76a2f3399be98a60246ae0b365442f008 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 7 Nov 2012 20:31:32 +0530 Subject: [PATCH 03/12] gpio: tegra: fix suspend/resume apis Following are changes done to fix the suspend/resume functionality of tegra gpio driver: - Protect suspend/resume callbacks with CONFIG_PM_SLEEP because CONFIG_PM doesn't actually enable any of the PM callbacks, it only allows to enable CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. This means if CONFIG_PM is used to protect system sleep callbacks then it may end up unreferenced if only runtime PM is enabled. - Fix the suspend/resume APIs declaration as per callback prototype. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index c7c175a4aff1..da32754fb25b 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -64,7 +65,7 @@ struct tegra_gpio_bank { int bank; int irq; spinlock_t lvl_lock[4]; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP u32 cnf[4]; u32 out[4]; u32 oe[4]; @@ -285,8 +286,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } -#ifdef CONFIG_PM -void tegra_gpio_resume(void) +#ifdef CONFIG_PM_SLEEP +static int tegra_gpio_resume(struct device *dev) { unsigned long flags; int b; @@ -308,9 +309,10 @@ void tegra_gpio_resume(void) } local_irq_restore(flags); + return 0; } -void tegra_gpio_suspend(void) +static int tegra_gpio_suspend(struct device *dev) { unsigned long flags; int b; @@ -330,6 +332,7 @@ void tegra_gpio_suspend(void) } } local_irq_restore(flags); + return 0; } static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) @@ -345,11 +348,15 @@ static struct irq_chip tegra_gpio_irq_chip = { .irq_mask = tegra_gpio_irq_mask, .irq_unmask = tegra_gpio_irq_unmask, .irq_set_type = tegra_gpio_irq_set_type, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .irq_set_wake = tegra_gpio_wake_enable, #endif }; +static const struct dev_pm_ops tegra_gpio_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) +}; + struct tegra_gpio_soc_config { u32 bank_stride; u32 upper_offset; @@ -489,6 +496,7 @@ static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", .owner = THIS_MODULE, + .pm = &tegra_gpio_pm_ops, .of_match_table = tegra_gpio_of_match, }, .probe = tegra_gpio_probe, From 924a09873c658a23e416258c6f81348cba2cfe87 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:45:24 +0800 Subject: [PATCH 04/12] gpio: tegra: Staticize non-exported symbols Both tegra_gpio_request() and tegra_gpio_free() are not referenced outside of this file, make them static. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index da32754fb25b..5ad4ceb14daa 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -118,12 +118,12 @@ static void tegra_gpio_disable(int gpio) } EXPORT_SYMBOL_GPL(tegra_gpio_disable); -int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); } -void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) +static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) { pinctrl_free_gpio(offset); tegra_gpio_disable(offset); From 65b6ca466748a8e0a906e40a470e1582bc565d79 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:47:02 +0800 Subject: [PATCH 05/12] gpio: tegra: Drop exporting static functions Both tegra_gpio_enable() and tegra_gpio_disable() are static functions, it does not make sense to export them. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 5ad4ceb14daa..cfd9b723002b 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -110,13 +110,11 @@ static void tegra_gpio_enable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); } -EXPORT_SYMBOL_GPL(tegra_gpio_enable); static void tegra_gpio_disable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); } -EXPORT_SYMBOL_GPL(tegra_gpio_disable); static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { From 3764bdde1dc2fe53a87db1777440c2532cfccd58 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Nov 2012 10:27:29 +0800 Subject: [PATCH 06/12] gpio: mvebu: Set free callback for gpio_chip We call pinctrl_request_gpio() in request callback, thus we need to call pinctrl_free_gpio() in free callback. Both mvebu_gpio_request() and mvebu_gpio_free() are not referenced outside of this file, make them static. Signed-off-by: Axel Lin Acked-by: Thomas Petazzoni Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index e0bde063221f..8b3065703566 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -163,12 +163,12 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) * Functions implementing the gpio_chip methods */ -int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) +static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) { return pinctrl_request_gpio(chip->base + pin); } -void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) +static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) { pinctrl_free_gpio(chip->base + pin); } @@ -518,6 +518,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.label = dev_name(&pdev->dev); mvchip->chip.dev = &pdev->dev; mvchip->chip.request = mvebu_gpio_request; + mvchip->chip.free = mvebu_gpio_free; mvchip->chip.direction_input = mvebu_gpio_direction_input; mvchip->chip.get = mvebu_gpio_get; mvchip->chip.direction_output = mvebu_gpio_direction_output; From 55ecd26373bc995c279a5d988ee36c2767e4f3ca Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Nov 2012 18:01:51 +0100 Subject: [PATCH 07/12] gpio: pca953x: Register an IRQ domain The PCA953x used to register no IRQ domain, which made it impossible to use it as an interrupt-parent from the device tree. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 9c693ae17956..5ba7e60de942 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ struct pca953x_chip { u32 irq_trig_raise; u32 irq_trig_fall; int irq_base; + struct irq_domain *domain; #endif struct i2c_client *client; @@ -333,14 +335,14 @@ static void pca953x_irq_mask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask &= ~(1 << d->hwirq); } static void pca953x_irq_unmask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << (d->irq - chip->irq_base); + chip->irq_mask |= 1 << d->hwirq; } static void pca953x_irq_bus_lock(struct irq_data *d) @@ -372,8 +374,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - u32 level = d->irq - chip->irq_base; - u32 mask = 1 << level; + u32 mask = 1 << d->hwirq; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -454,7 +455,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->domain, level)); pending &= ~(1 << level); } while (pending); @@ -499,6 +500,17 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (chip->irq_base < 0) goto out_failed; + chip->domain = irq_domain_add_legacy(client->dev.of_node, + chip->gpio_chip.ngpio, + chip->irq_base, + 0, + &irq_domain_simple_ops, + NULL); + if (!chip->domain) { + ret = -ENODEV; + goto out_irqdesc_free; + } + for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { int irq = lvl + chip->irq_base; @@ -521,7 +533,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - goto out_failed; + goto out_irqdesc_free; } chip->gpio_chip.to_irq = pca953x_gpio_to_irq; @@ -529,6 +541,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return 0; +out_irqdesc_free: + irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); out_failed: chip->irq_base = -1; return ret; From ed32620ea72889c8a9dda278a960bce01136d9a4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Nov 2012 18:01:52 +0100 Subject: [PATCH 08/12] gpio: pca953x: Add compatible strings to gpio-pca953x driver Even though the device tree binding code was already written, the compatible strings were not yet in the driver. Signed-off-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5ba7e60de942..0c5eaf5f4c90 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -765,9 +765,38 @@ static int pca953x_remove(struct i2c_client *client) return 0; } +static const struct of_device_id pca953x_dt_ids[] = { + { .compatible = "nxp,pca9534", }, + { .compatible = "nxp,pca9535", }, + { .compatible = "nxp,pca9536", }, + { .compatible = "nxp,pca9537", }, + { .compatible = "nxp,pca9538", }, + { .compatible = "nxp,pca9539", }, + { .compatible = "nxp,pca9554", }, + { .compatible = "nxp,pca9555", }, + { .compatible = "nxp,pca9556", }, + { .compatible = "nxp,pca9557", }, + { .compatible = "nxp,pca9574", }, + { .compatible = "nxp,pca9575", }, + + { .compatible = "maxim,max7310", }, + { .compatible = "maxim,max7312", }, + { .compatible = "maxim,max7313", }, + { .compatible = "maxim,max7315", }, + + { .compatible = "ti,pca6107", }, + { .compatible = "ti,tca6408", }, + { .compatible = "ti,tca6416", }, + { .compatible = "ti,tca6424", }, + { } +}; + +MODULE_DEVICE_TABLE(of, pca953x_dt_ids); + static struct i2c_driver pca953x_driver = { .driver = { .name = "pca953x", + .of_match_table = pca953x_dt_ids, }, .probe = pca953x_probe, .remove = pca953x_remove, From 195812e4b6a631e8eaad4046bf6890db4328ea1f Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 9 Nov 2012 11:34:20 +0530 Subject: [PATCH 09/12] gpio: tegra: read output value when gpio is set in direction_out Read the output value when gpio is set for the output mode for gpio_get_value(). Reading input value in direction out does not give correct value. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index cfd9b723002b..5389be8c2b51 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -134,6 +134,11 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { + /* If gpio is in output mode then read from the out value */ + if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1) + return (tegra_gpio_readl(GPIO_OUT(offset)) >> + GPIO_BIT(offset)) & 0x1; + return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; } From 9859eb99e9212339e2009b98c396b08260276edf Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 13 Nov 2012 10:35:13 +0100 Subject: [PATCH 10/12] gpio: twl4030: Use only TWL4030_MODULE_LED for LED configuration Avoid using the TWL4030_MODULE_PWMA/B as module ID. The LEDEN, PWMA ON/OFF and PWMB ON/OFF registers are in a continuous range starting from LED base. This is going to be helpful for further cleanup in the twl stack. No functional changes. Signed-off-by: Peter Ujfalusi Signed-off-by: Linus Walleij --- drivers/gpio/gpio-twl4030.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index c5f8ca233e1f..d2138b0fd4ca 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -88,11 +88,15 @@ static inline int gpio_twl4030_write(u8 address, u8 data) /*----------------------------------------------------------------------*/ /* - * LED register offsets (use TWL4030_MODULE_{LED,PWMA,PWMB})) + * LED register offsets from TWL_MODULE_LED base * PWMs A and B are dedicated to LEDs A and B, respectively. */ -#define TWL4030_LED_LEDEN 0x0 +#define TWL4030_LED_LEDEN_REG 0x00 +#define TWL4030_PWMAON_REG 0x01 +#define TWL4030_PWMAOFF_REG 0x02 +#define TWL4030_PWMBON_REG 0x03 +#define TWL4030_PWMBOFF_REG 0x04 /* LEDEN bits */ #define LEDEN_LEDAON BIT(0) @@ -104,9 +108,6 @@ static inline int gpio_twl4030_write(u8 address, u8 data) #define LEDEN_PWM_LENGTHA BIT(6) #define LEDEN_PWM_LENGTHB BIT(7) -#define TWL4030_PWMx_PWMxON 0x0 -#define TWL4030_PWMx_PWMxOFF 0x1 - #define PWMxON_LENGTH BIT(7) /*----------------------------------------------------------------------*/ @@ -145,7 +146,7 @@ static void twl4030_led_set_value(int led, int value) else cached_leden |= mask; status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, - TWL4030_LED_LEDEN); + TWL4030_LED_LEDEN_REG); mutex_unlock(&gpio_lock); } @@ -216,33 +217,33 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) if (offset >= TWL4030_GPIO_MAX) { u8 ledclr_mask = LEDEN_LEDAON | LEDEN_LEDAEXT | LEDEN_LEDAPWM | LEDEN_PWM_LENGTHA; - u8 module = TWL4030_MODULE_PWMA; + u8 reg = TWL4030_PWMAON_REG; offset -= TWL4030_GPIO_MAX; if (offset) { ledclr_mask <<= 1; - module = TWL4030_MODULE_PWMB; + reg = TWL4030_PWMBON_REG; } /* initialize PWM to always-drive */ - status = twl_i2c_write_u8(module, 0x7f, - TWL4030_PWMx_PWMxOFF); + /* Configure PWM OFF register first */ + status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg + 1); if (status < 0) goto done; - status = twl_i2c_write_u8(module, 0x7f, - TWL4030_PWMx_PWMxON); + + /* Followed by PWM ON register */ + status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg); if (status < 0) goto done; /* init LED to not-driven (high) */ - module = TWL4030_MODULE_LED; - status = twl_i2c_read_u8(module, &cached_leden, - TWL4030_LED_LEDEN); + status = twl_i2c_read_u8(TWL4030_MODULE_LED, &cached_leden, + TWL4030_LED_LEDEN_REG); if (status < 0) goto done; cached_leden &= ~ledclr_mask; - status = twl_i2c_write_u8(module, cached_leden, - TWL4030_LED_LEDEN); + status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, + TWL4030_LED_LEDEN_REG); if (status < 0) goto done; From 8754fccbae661a0020923cffd63e21de36d51e2e Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Thu, 15 Nov 2012 14:59:40 +0100 Subject: [PATCH 11/12] gpio: gpio-max710x: Support device tree probing For probing via device tree, we need to support the case without platform_data. In this case, chip.base is set to -1 for automatic numbering. Signed-off-by: Roland Stigge Acked-by: Wolfram Sang Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max730x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 05e2dac60b3b..c4bf86abd4d8 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -167,10 +167,6 @@ int __devinit __max730x_probe(struct max7301 *ts) int i, ret; pdata = dev->platform_data; - if (!pdata || !pdata->base) { - dev_err(dev, "incorrect or missing platform data\n"); - return -EINVAL; - } mutex_init(&ts->lock); dev_set_drvdata(dev, ts); @@ -178,7 +174,12 @@ int __devinit __max730x_probe(struct max7301 *ts) /* Power up the chip and disable IRQ output */ ts->write(dev, 0x04, 0x01); - ts->input_pullup_active = pdata->input_pullup_active; + if (pdata) { + ts->input_pullup_active = pdata->input_pullup_active; + ts->chip.base = pdata->base; + } else { + ts->chip.base = -1; + } ts->chip.label = dev->driver->name; ts->chip.direction_input = max7301_direction_input; @@ -186,7 +187,6 @@ int __devinit __max730x_probe(struct max7301 *ts) ts->chip.direction_output = max7301_direction_output; ts->chip.set = max7301_set; - ts->chip.base = pdata->base; ts->chip.ngpio = PIN_NUMBER; ts->chip.can_sleep = 1; ts->chip.dev = dev; From b53bc2819a71099ecfc3d61ba0796b3dcc6be321 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Fri, 16 Nov 2012 10:45:25 +0530 Subject: [PATCH 12/12] gpio: SPEAr: add spi chipselect control driver SPEAr platform provides a provision to control chipselects of ARM PL022 Prime Cell spi controller through its system registers, which otherwise remains under PL022 control which some protocols do not want. This commit intends to provide the spi chipselect control in software over gpiolib interface. spi chip drivers can use the exported gpiolib interface to define their chipselect through DT or platform data. Cc: Grant Likely Signed-off-by: Shiraz Hashim Reviewed-by: Vipin Kumar Acked-by: Arnd Bergmann Signed-off-by: Viresh Kumar Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/spear_spics.txt | 50 ++++ arch/arm/plat-spear/Kconfig | 1 + drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-spear-spics.c | 217 ++++++++++++++++++ 5 files changed, 276 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/spear_spics.txt create mode 100644 drivers/gpio/gpio-spear-spics.c diff --git a/Documentation/devicetree/bindings/gpio/spear_spics.txt b/Documentation/devicetree/bindings/gpio/spear_spics.txt new file mode 100644 index 000000000000..96c37eb15075 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/spear_spics.txt @@ -0,0 +1,50 @@ +=== ST Microelectronics SPEAr SPI CS Driver === + +SPEAr platform provides a provision to control chipselects of ARM PL022 Prime +Cell spi controller through its system registers, which otherwise remains under +PL022 control. If chipselect remain under PL022 control then they would be +released as soon as transfer is over and TxFIFO becomes empty. This is not +desired by some of the device protocols above spi which expect (multiple) +transfers without releasing their chipselects. + +Chipselects can be controlled by software by turning them as GPIOs. SPEAr +provides another interface through system registers through which software can +directly control each PL022 chipselect. Hence, it is natural for SPEAr to export +the control of this interface as gpio. + +Required properties: + + * compatible: should be defined as "st,spear-spics-gpio" + * reg: mentioning address range of spics controller + * st-spics,peripcfg-reg: peripheral configuration register offset + * st-spics,sw-enable-bit: bit offset to enable sw control + * st-spics,cs-value-bit: bit offset to drive chipselect low or high + * st-spics,cs-enable-mask: chip select number bit mask + * st-spics,cs-enable-shift: chip select number program offset + * gpio-controller: Marks the device node as gpio controller + * #gpio-cells: should be 1 and will mention chip select number + +All the above bit offsets are within peripcfg register. + +Example: +------- +spics: spics@e0700000{ + compatible = "st,spear-spics-gpio"; + reg = <0xe0700000 0x1000>; + st-spics,peripcfg-reg = <0x3b0>; + st-spics,sw-enable-bit = <12>; + st-spics,cs-value-bit = <11>; + st-spics,cs-enable-mask = <3>; + st-spics,cs-enable-shift = <8>; + gpio-controller; + #gpio-cells = <2>; +}; + + +spi0: spi@e0100000 { + status = "okay"; + num-cs = <3>; + cs-gpios = <&gpio1 7 0>, <&spics 0>, + <&spics 1>; + ... +} diff --git a/arch/arm/plat-spear/Kconfig b/arch/arm/plat-spear/Kconfig index f8db7b2deb36..87dbd81bdf51 100644 --- a/arch/arm/plat-spear/Kconfig +++ b/arch/arm/plat-spear/Kconfig @@ -12,6 +12,7 @@ config ARCH_SPEAR13XX bool "ST SPEAr13xx with Device Tree" select ARM_GIC select CPU_V7 + select GPIO_SPEAR_SPICS select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 select PINCTRL diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9e3fb3438718..4f592c615990 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -196,6 +196,13 @@ config GPIO_PXA help Say yes here to support the PXA GPIO device +config GPIO_SPEAR_SPICS + bool "ST SPEAr13xx SPI Chip Select as GPIO support" + depends on PLAT_SPEAR + select GENERIC_IRQ_CHIP + help + Say yes here to support ST SPEAr SPI Chip Select as GPIO device + config GPIO_STA2X11 bool "STA2x11/ConneXt GPIO support" depends on MFD_STA2X11 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 1c1b63fcaeb3..a268d99f4e43 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o +obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c new file mode 100644 index 000000000000..5f45fc4ed5d1 --- /dev/null +++ b/drivers/gpio/gpio-spear-spics.c @@ -0,0 +1,217 @@ +/* + * SPEAr platform SPI chipselect abstraction over gpiolib + * + * Copyright (C) 2012 ST Microelectronics + * Shiraz Hashim + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* maximum chipselects */ +#define NUM_OF_GPIO 4 + +/* + * Provision is available on some SPEAr SoCs to control ARM PL022 spi cs + * through system registers. This register lies outside spi (pl022) + * address space into system registers. + * + * It provides control for spi chip select lines so that any chipselect + * (out of 4 possible chipselects in pl022) can be made low to select + * the particular slave. + */ + +/** + * struct spear_spics - represents spi chip select control + * @base: base address + * @perip_cfg: configuration register + * @sw_enable_bit: bit to enable s/w control over chipselects + * @cs_value_bit: bit to program high or low chipselect + * @cs_enable_mask: mask to select bits required to select chipselect + * @cs_enable_shift: bit pos of cs_enable_mask + * @use_count: use count of a spi controller cs lines + * @last_off: stores last offset caller of set_value() + * @chip: gpio_chip abstraction + */ +struct spear_spics { + void __iomem *base; + u32 perip_cfg; + u32 sw_enable_bit; + u32 cs_value_bit; + u32 cs_enable_mask; + u32 cs_enable_shift; + unsigned long use_count; + int last_off; + struct gpio_chip chip; +}; + +/* gpio framework specific routines */ +static int spics_get_value(struct gpio_chip *chip, unsigned offset) +{ + return -ENXIO; +} + +static void spics_set_value(struct gpio_chip *chip, unsigned offset, int value) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + /* select chip select from register */ + tmp = readl_relaxed(spics->base + spics->perip_cfg); + if (spics->last_off != offset) { + spics->last_off = offset; + tmp &= ~(spics->cs_enable_mask << spics->cs_enable_shift); + tmp |= offset << spics->cs_enable_shift; + } + + /* toggle chip select line */ + tmp &= ~(0x1 << spics->cs_value_bit); + tmp |= value << spics->cs_value_bit; + writel_relaxed(tmp, spics->base + spics->perip_cfg); +} + +static int spics_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return -ENXIO; +} + +static int spics_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + spics_set_value(chip, offset, value); + return 0; +} + +static int spics_request(struct gpio_chip *chip, unsigned offset) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + if (!spics->use_count++) { + tmp = readl_relaxed(spics->base + spics->perip_cfg); + tmp |= 0x1 << spics->sw_enable_bit; + tmp |= 0x1 << spics->cs_value_bit; + writel_relaxed(tmp, spics->base + spics->perip_cfg); + } + + return 0; +} + +static void spics_free(struct gpio_chip *chip, unsigned offset) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + if (!--spics->use_count) { + tmp = readl_relaxed(spics->base + spics->perip_cfg); + tmp &= ~(0x1 << spics->sw_enable_bit); + writel_relaxed(tmp, spics->base + spics->perip_cfg); + } +} + +static int spics_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spear_spics *spics; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); + return -EBUSY; + } + + spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); + if (!spics) { + dev_err(&pdev->dev, "memory allocation fail\n"); + return -ENOMEM; + } + + spics->base = devm_request_and_ioremap(&pdev->dev, res); + if (!spics->base) { + dev_err(&pdev->dev, "request and ioremap fail\n"); + return -ENOMEM; + } + + if (of_property_read_u32(np, "st-spics,peripcfg-reg", + &spics->perip_cfg)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,sw-enable-bit", + &spics->sw_enable_bit)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-value-bit", + &spics->cs_value_bit)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-enable-mask", + &spics->cs_enable_mask)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-enable-shift", + &spics->cs_enable_shift)) + goto err_dt_data; + + platform_set_drvdata(pdev, spics); + + spics->chip.ngpio = NUM_OF_GPIO; + spics->chip.base = -1; + spics->chip.request = spics_request; + spics->chip.free = spics_free; + spics->chip.direction_input = spics_direction_input; + spics->chip.direction_output = spics_direction_output; + spics->chip.get = spics_get_value; + spics->chip.set = spics_set_value; + spics->chip.label = dev_name(&pdev->dev); + spics->chip.dev = &pdev->dev; + spics->chip.owner = THIS_MODULE; + spics->last_off = -1; + + ret = gpiochip_add(&spics->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpio chip\n"); + return ret; + } + + dev_info(&pdev->dev, "spear spics registered\n"); + return 0; + +err_dt_data: + dev_err(&pdev->dev, "DT probe failed\n"); + return -EINVAL; +} + +static const struct of_device_id spics_gpio_of_match[] = { + { .compatible = "st,spear-spics-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, spics_gpio_of_match); + +static struct platform_driver spics_gpio_driver = { + .probe = spics_gpio_probe, + .driver = { + .owner = THIS_MODULE, + .name = "spear-spics-gpio", + .of_match_table = spics_gpio_of_match, + }, +}; + +static int __init spics_gpio_init(void) +{ + return platform_driver_register(&spics_gpio_driver); +} +subsys_initcall(spics_gpio_init); + +MODULE_AUTHOR("Shiraz Hashim "); +MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction"); +MODULE_LICENSE("GPL");