plat-nomadik: GPIO updates
Subsystems (3)
This patch set consolidates a number of updates to the plat-nomadik GPIO code that we have stabilized inside ST-Ericsson for the past few months. It's time to get in sync.
Yours,
Linus Walleij
PATCH 1/9 plat-nomadik: support varying number of GPIOs per block
From: Rabin Vincent <[email protected]>
--- arch/arm/mach-ux500/devices-common.c | 1 + arch/arm/plat-nomadik/gpio.c | 5 ++--- arch/arm/plat-nomadik/include/plat/gpio.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-)
arch/arm/mach-ux500/devices-common.c +1 -0
@@ -139,6 +139,7 @@ void dbx500_add_gpios(resource_size_t *base, int num, int irq,for (i =0 ; i < num; i++, first +=32 , irq++) { pdata->first_gpio = first; pdata->first_irq =NOMADIK_GPIO_TO_IRQ (first); + pdata->num_gpio =32 ;dbx500_add_gpio (i, base[i], irq, pdata); }
arch/arm/plat-nomadik/gpio.c +2 -3
@@ -35,7 +35,6 @@* Symbols in this file are called "nmk_gpio" for "nomadik gpio" */ -#define NMK_GPIO_PER_CHIP 32struct nmk_gpio_chip {struct gpio_chip chip;void __iomem *addr;
@@ -546,7 +545,7 @@ static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)int i; first_irq =NOMADIK_GPIO_TO_IRQ (nmk_chip->chip.base); -for (i = first_irq; i < first_irq +NMK_GPIO_PER_CHIP ; i++) { +for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {set_irq_chip (i, &nmk_gpio_irq_chip);set_irq_handler (i, handle_edge_irq);set_irq_flags (i,IRQF_VALID );
@@ -612,7 +611,6 @@ static struct gpio_chip nmk_gpio_template = { .direction_output = nmk_gpio_make_output, .set = nmk_gpio_set_output, .to_irq = nmk_gpio_to_irq, - .ngpio = NMK_GPIO_PER_CHIP, .can_sleep = 0, };
@@ -672,6 +670,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) chip = &nmk_chip->chip; chip->base = pdata->first_gpio; + chip->ngpio = pdata->num_gpio; chip->label = pdata->name ?:dev_name (&dev->dev); chip->dev = &dev->dev; chip->owner =THIS_MODULE ;
arch/arm/plat-nomadik/include/plat/gpio.h +1 -0
@@ -82,6 +82,7 @@ struct nmk_gpio_platform_data {char *name;int first_gpio;int first_irq; + int num_gpio; };#endif /* __ASM_PLAT_GPIO_H */
Signature · 1 line
1.7.3.2
PATCH 2/9 plat-nomadik: add custom dbg_show for GPIO
In reply to Linus WalleijFrom: Rabin Vincent <[email protected]>
--- arch/arm/plat-nomadik/gpio.c | 92 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 92 insertions(+), 0 deletions(-)
arch/arm/plat-nomadik/gpio.c +92 -0
@@ -604,6 +604,97 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)return NOMADIK_GPIO_TO_IRQ (nmk_chip->chip.base) + offset; } +#ifdef CONFIG_DEBUG_FS + +#include <linux/seq_file.h> + +static void nmk_gpio_dbg_show (struct seq_file *s,struct gpio_chip *chip) +{ +int mode; +unsigned i; +unsigned gpio = chip->base; +int is_out; +struct nmk_gpio_chip *nmk_chip = + container_of(chip, struct nmk_gpio_chip, chip); +const char *modes[] = { + [NMK_GPIO_ALT_GPIO ] ="gpio" , + [NMK_GPIO_ALT_A ] ="altA" , + [NMK_GPIO_ALT_B ] ="altB" , + [NMK_GPIO_ALT_C ] ="altC" , + }; + +for (i =0 ; i < chip->ngpio; i++, gpio++) { +const char *label =gpiochip_is_requested (chip, i); +bool pull; +u32 bit =1 << i; + +if (!label) +continue ; + + is_out =readl (nmk_chip->addr +NMK_GPIO_DIR ) & bit; + pull = !(readl (nmk_chip->addr +NMK_GPIO_PDIS ) & bit); + mode =nmk_gpio_get_mode (gpio); +seq_printf (s," gpio-%-3d (%-20.20s) %s %s %s %s" , + gpio, label, + is_out ?"out" :"in " , + chip->get + ? (chip->get (chip, i) ?"hi" :"lo" ) + :"? " , + (mode <0 ) ?"unknown" : modes[mode], + pull ?"pull" :"none" ); + +if (!is_out) { +int irq =gpio_to_irq (gpio); +struct irq_desc *desc =irq_to_desc (irq); + +/* This races with request_irq(), set_irq_type(), +* and set_irq_wake() ... but those are "rare". +* +* More significantly, trigger type flags aren't +* currently maintained by genirq. +*/ +if (irq >=0 && desc->action) { +char *trigger; + +switch (desc->status &IRQ_TYPE_SENSE_MASK ) { +case IRQ_TYPE_NONE : + trigger ="(default)" ; +break ; +case IRQ_TYPE_EDGE_FALLING : + trigger ="edge-falling" ; +break ; +case IRQ_TYPE_EDGE_RISING : + trigger ="edge-rising" ; +break ; +case IRQ_TYPE_EDGE_BOTH : + trigger ="edge-both" ; +break ; +case IRQ_TYPE_LEVEL_HIGH : + trigger ="level-high" ; +break ; +case IRQ_TYPE_LEVEL_LOW : + trigger ="level-low" ; +break ; +default : + trigger ="?trigger?" ; +break ; + } + +seq_printf (s," irq-%d %s%s" , + irq, trigger, + (desc->status &IRQ_WAKEUP ) + ?" wakeup" :"" ); + } + } + +seq_printf (s,"\n" ); + } +} + +#else +#define nmk_gpio_dbg_show NULL +#endif +/* This structure is replicated for each GPIO block allocated at probe time */ static struct gpio_chip nmk_gpio_template = { .direction_input = nmk_gpio_make_input,
@@ -611,6 +702,7 @@ static struct gpio_chip nmk_gpio_template = { .direction_output = nmk_gpio_make_output, .set = nmk_gpio_set_output, .to_irq = nmk_gpio_to_irq, + .dbg_show = nmk_gpio_dbg_show, .can_sleep = 0, };
Signature · 1 line
1.7.3.2
PATCH 3/9 plat-nomadik: implement suspend/resume for GPIO
In reply to Linus WalleijFrom: Rabin Vincent <[email protected]>
--- arch/arm/plat-nomadik/gpio.c | 51 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 49 insertions(+), 2 deletions(-)
arch/arm/plat-nomadik/gpio.c +49 -2
@@ -44,6 +44,7 @@ struct nmk_gpio_chip {/* Keep track of configured edges */ u32 edge_rising;u32 edge_falling; +u32 backup[10 ]; }; static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
@@ -792,14 +793,60 @@ out:return ret; } +#ifdef CONFIG_PM +static int nmk_gpio_pm (struct platform_device *dev,bool suspend) +{ +struct nmk_gpio_chip *nmk_chip =platform_get_drvdata (dev); +int i; +static const unsigned int regs[] = { +NMK_GPIO_DAT , +NMK_GPIO_PDIS , +NMK_GPIO_DIR , +NMK_GPIO_AFSLA , +NMK_GPIO_AFSLB , +NMK_GPIO_SLPC , +NMK_GPIO_RIMSC , +NMK_GPIO_FIMSC , +NMK_GPIO_RWIMSC , +NMK_GPIO_FWIMSC , + }; + +BUILD_BUG_ON (ARRAY_SIZE (nmk_chip->backup) !=ARRAY_SIZE (regs)); + +/* XXX: is this sufficient? what about pull-up/down configuration? */ + +for (i =0 ; i <ARRAY_SIZE (regs); i++) { +if (suspend) + nmk_chip->backup[i] =readl (nmk_chip->addr + regs[i]); +else +writel (nmk_chip->backup[i], nmk_chip->addr + regs[i]); + } + +return 0 ; +} + +static int nmk_gpio_suspend (struct platform_device *dev,pm_message_t state) +{ +return nmk_gpio_pm (dev, true); +} + +static int nmk_gpio_resume (struct platform_device *dev) +{ +return nmk_gpio_pm (dev, false); +} +#else +#define nmk_gpio_suspend NULL +#define nmk_gpio_resume NULL +#endif +static struct platform_driver nmk_gpio_driver = { .driver = { .owner =THIS_MODULE , .name ="gpio" , }, .probe = nmk_gpio_probe, - .suspend =NULL ,/* to be done */ - .resume =NULL , + .suspend = nmk_gpio_suspend, + .resume = nmk_gpio_resume, };static int __init nmk_gpio_init (void )
Signature · 1 line
1.7.3.2
PATCH 4/9 plat-nomadik: support secondary GPIO interrupts
In reply to Linus WalleijFrom: Rabin Vincent <[email protected]>
When GPIOs wake up the system from sleep mode, the normal GPIO interrupt handler does not hit and the normal interrupt status register does not contain the status. Instead the secondary GPIO handler does, and the interrupt status needs to be retrieved from the wakeup status saved by the suspend/resume code.
--- arch/arm/plat-nomadik/gpio.c | 51 +++++++++++++++++++++++++--- arch/arm/plat-nomadik/include/plat/gpio.h | 1 + 2 files changed, 46 insertions(+), 6 deletions(-)
arch/arm/plat-nomadik/gpio.c +45 -6
@@ -39,7 +39,10 @@ struct nmk_gpio_chip {struct gpio_chip chip;void __iomem *addr;struct clk *clk; +unsigned int bank;unsigned int parent_irq; +unsigned int secondary_parent_irq; +u32 (*get_secondary_status)(unsigned int bank);spinlock_t lock;/* Keep track of configured edges */ u32 edge_rising;
@@ -514,12 +517,11 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_set_wake = nmk_gpio_irq_set_wake, }; -static void nmk_gpio_irq_handler (unsigned int irq,struct irq_desc *desc) +static void __nmk_gpio_irq_handler (unsigned int irq,struct irq_desc *desc, +u32 status) {struct nmk_gpio_chip *nmk_chip;struct irq_chip *host_chip =get_irq_chip (irq); -unsigned int gpio_irq; -u32 pending;unsigned int first_irq;if (host_chip->irq_mask_ack)
@@ -532,14 +534,33 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) nmk_chip =get_irq_data (irq); first_irq =NOMADIK_GPIO_TO_IRQ (nmk_chip->chip.base); -while ( (pending =readl (nmk_chip->addr +NMK_GPIO_IS )) ) { - gpio_irq = first_irq +__ffs (pending); -generic_handle_irq (gpio_irq); +while (status) { +int bit =__ffs (status); + +generic_handle_irq (first_irq + bit); + status &= ~BIT (bit); } host_chip->irq_unmask (&desc->irq_data); } +static void nmk_gpio_irq_handler (unsigned int irq,struct irq_desc *desc) +{ +struct nmk_gpio_chip *nmk_chip =get_irq_data (irq); +u32 status =readl (nmk_chip->addr +NMK_GPIO_IS ); + +__nmk_gpio_irq_handler (irq, desc, status); +} + +static void nmk_gpio_secondary_irq_handler (unsigned int irq, +struct irq_desc *desc) +{ +struct nmk_gpio_chip *nmk_chip =get_irq_data (irq); +u32 status = nmk_chip->get_secondary_status (nmk_chip->bank); + +__nmk_gpio_irq_handler (irq, desc, status); +} +static int nmk_gpio_init_irq (struct nmk_gpio_chip *nmk_chip) {unsigned int first_irq;
@@ -553,8 +574,16 @@ static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)set_irq_chip_data (i, nmk_chip);set_irq_type (i,IRQ_TYPE_EDGE_FALLING ); } +set_irq_chained_handler (nmk_chip->parent_irq, nmk_gpio_irq_handler);set_irq_data (nmk_chip->parent_irq, nmk_chip); + +if (nmk_chip->secondary_parent_irq >=0 ) { +set_irq_chained_handler (nmk_chip->secondary_parent_irq, + nmk_gpio_secondary_irq_handler); +set_irq_data (nmk_chip->secondary_parent_irq, nmk_chip); + } +return 0 ; }
@@ -714,6 +743,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)struct gpio_chip *chip;struct resource *res;struct clk *clk; +int secondary_irq;int irq;int ret;
@@ -732,6 +762,12 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) goto out; } + secondary_irq =platform_get_irq (dev,1 ); +if (secondary_irq >=0 && !pdata->get_secondary_status) { + ret = -EINVAL ; + goto out; + } +if (request_mem_region (res->start,resource_size (res),dev_name (&dev->dev)) ==NULL ) { ret = -EBUSY ;
@@ -755,10 +791,13 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)* The virt address in nmk_chip->addr is in the nomadik register space, * so we can simply convert the resource address, without remapping */ + nmk_chip->bank = dev->id; nmk_chip->clk = clk; nmk_chip->addr =io_p2v (res->start); nmk_chip->chip = nmk_gpio_template; nmk_chip->parent_irq = irq; + nmk_chip->secondary_parent_irq = secondary_irq; + nmk_chip->get_secondary_status = pdata->get_secondary_status;spin_lock_init (&nmk_chip->lock); chip = &nmk_chip->chip;
arch/arm/plat-nomadik/include/plat/gpio.h +1 -0
@@ -83,6 +83,7 @@ struct nmk_gpio_platform_data {int first_gpio;int first_irq;int num_gpio; + u32 (*get_secondary_status)(unsigned int bank); };#endif /* __ASM_PLAT_GPIO_H */
Signature · 1 line
1.7.3.2
PATCH 5/9 plat-nomadik: pull-up/down settings for GPIO resume
In reply to Linus WalleijFrom: Jonas Aaberg <[email protected]>
Suspend/resume didn't take care of pull-up and pull-down settings and writing back the DAT register at resume can change pull up/down settings, depending on pin input value. Output values are now also restored.
--- arch/arm/plat-nomadik/Kconfig | 6 +++ arch/arm/plat-nomadik/gpio.c | 78 ++++++++++++++++++++++++++++------------ 2 files changed, 60 insertions(+), 24 deletions(-)
arch/arm/plat-nomadik/Kconfig +6 -0
@@ -25,4 +25,10 @@ config NOMADIK_GPIO help Support for the Nomadik GPIO controller. +config NOMADIK_GPIO_PM + bool + depends on NOMADIK_GPIO && PM + help + Support PM for the Nomadik GPIO controller. + endif
arch/arm/plat-nomadik/gpio.c +54 -24
123 lines not on this page · raw message
Signature · 1 line
1.7.3.2
PATCH 6/9 plat-nomadik: type secondary IRQ correctly
In reply to Linus WalleijFrom: Virupax Sadashivpetimath <[email protected]>
Coverity found that we were checking an unsigned variable for greater than zero. Type it correctly.
--- arch/arm/plat-nomadik/gpio.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/plat-nomadik/gpio.c +1 -1
@@ -53,7 +53,7 @@ struct nmk_gpio_chip {struct clk *clk;unsigned int bank;unsigned int parent_irq; -unsigned int secondary_parent_irq; +int secondary_parent_irq;u32 (*get_secondary_status)(unsigned int bank);spinlock_t lock;/* Keep track of configured edges */
Signature · 1 line
1.7.3.2
PATCH 6/9 plat-nomadik: type secondary IRQ correctly
Hello.
Quoted 4 lines · Linus Walleij
From: Virupax Sadashivpetimath <[email protected]>
Coverity found that we were checking an unsigned variable for greater than zero. Type it correctly.
There's nothing criminal in checking unsigned for > 0. Perhaps you meant >= 0?
Quoted 3 lines
Signed-off-by Virupax Sadashivpetimath <[email protected]>Signed-off-by Linus Walleij <[email protected]>Signed-off-by Linus Walleij <[email protected]>
Twice?
WBR, Sergei
PATCH 6/9 plat-nomadik: type secondary IRQ correctly
2011/2/8 Sergei Shtylyov <[email protected]>:
Quoted 11 lines
Hello.
Quoted 4 lines · Linus Walleij
From: Virupax Sadashivpetimath <[email protected]>
Coverity found that we were checking an unsigned variable for greater than zero. Type it correctly.
? There's nothing criminal in checking unsigned for > 0. Perhaps you meant
Quoted 1 line
= 0?
Yeah the if()-clause Coverity reacted to was this:
if (nmk_chip->secondary_parent_irq >= 0) {
I'll update the patch description.
Quoted 6 lines
Quoted 4 lines
Signed-off-by: Virupax Sadashivpetimath
<[email protected]>Signed-off-by Linus Walleij <[email protected]>Signed-off-by Linus Walleij <[email protected]>? Twice?
Yes, for two different organizations. One pays my wages and the other one control my work.
Let's say that I think if Greg and the Linux Foundation wasn't doing these statistics over the organizations contributing to Linux every kernel release, it wouldn't be such a big deal. Now everybody wants to be in those stats. Lee from Linaro may want to expand on this...
Yours,
Linus Walleij
PATCH 7/9 plat-nomadik: set altfunc to GPIO when enabling the sleep config
In reply to Linus WalleijFrom: Rabin Vincent <[email protected]>
--- arch/arm/plat-nomadik/gpio.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
arch/arm/plat-nomadik/gpio.c +2 -0
@@ -175,6 +175,8 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,int slpm_output =PIN_SLPM_DIR (cfg);int slpm_val =PIN_SLPM_VAL (cfg); + af =NMK_GPIO_ALT_GPIO ; +/* * The SLPM_* values are normal values + 1 to allow zero to * mean "same as normal".
Signature · 1 line
1.7.3.2
PATCH 8/9 plat-nomadik: implement safe switch sequence for Alt-C
In reply to Linus WalleijFrom: Rabin Vincent <[email protected]>
Setting pinmux alternative C for a GPIO pin is actually not so easy since it ivolves setting value "1" in two registers, and since the combined result will take effect for intermediate values (01 or 10) this will cause glitches while you wrote one register but have not yet written the other.
This patch implements a series of kludges including an optional machine-specific callback to avoid glitches when changing pin mux mode to alternative C.
--- arch/arm/plat-nomadik/gpio.c | 211 +++++++++++++++++++++++------ arch/arm/plat-nomadik/include/plat/gpio.h | 1 + 2 files changed, 172 insertions(+), 40 deletions(-)
arch/arm/plat-nomadik/gpio.c +171 -40
@@ -47,6 +47,8 @@ static const u32 backup_regs[] = { NMK_GPIO_FWIMSC, }; +#define NMK_GPIO_PER_CHIP 32 +struct nmk_gpio_chip {struct gpio_chip chip;void __iomem *addr;
@@ -55,6 +57,7 @@ struct nmk_gpio_chip {unsigned int parent_irq;int secondary_parent_irq;u32 (*get_secondary_status)(unsigned int bank); +void (*set_ioforce)(bool enable);spinlock_t lock;/* Keep track of configured edges */ u32 edge_rising;
@@ -64,6 +67,13 @@ struct nmk_gpio_chip {u32 pull; }; +static struct nmk_gpio_chip * +nmk_gpio_chips[DIV_ROUND_UP (ARCH_NR_GPIOS ,NMK_GPIO_PER_CHIP )]; + +static DEFINE_SPINLOCK (nmk_gpio_slpm_lock); + +#define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips) +static void __nmk_gpio_set_mode (struct nmk_gpio_chip *nmk_chip,unsigned offset,int gpio_mode) {
@@ -138,8 +148,38 @@ static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,__nmk_gpio_set_output (nmk_chip, offset, val); } +static void __nmk_gpio_set_mode_safe (struct nmk_gpio_chip *nmk_chip, +unsigned offset,int gpio_mode, +bool glitch) +{ +u32 rwimsc; +u32 fwimsc; + +if (glitch && nmk_chip->set_ioforce) { +u32 bit =BIT (offset); + + rwimsc =readl (nmk_chip->addr +NMK_GPIO_RWIMSC ); + fwimsc =readl (nmk_chip->addr +NMK_GPIO_FWIMSC ); + +/* Prevent spurious wakeups */ +writel (rwimsc & ~bit, nmk_chip->addr +NMK_GPIO_RWIMSC ); +writel (fwimsc & ~bit, nmk_chip->addr +NMK_GPIO_FWIMSC ); + + nmk_chip->set_ioforce (true); + } + +__nmk_gpio_set_mode (nmk_chip, offset, gpio_mode); + +if (glitch && nmk_chip->set_ioforce) { + nmk_chip->set_ioforce (false); + +writel (rwimsc, nmk_chip->addr +NMK_GPIO_RWIMSC ); +writel (fwimsc, nmk_chip->addr +NMK_GPIO_FWIMSC ); + } +} +static void __nmk_config_pin (struct nmk_gpio_chip *nmk_chip,unsigned offset, -pin_cfg_t cfg,bool sleep) +pin_cfg_t cfg,bool sleep,unsigned int *slpmregs) {static const char *afnames[] = { [NMK_GPIO_ALT_GPIO ] ="GPIO" ,
@@ -164,6 +204,7 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,int slpm =PIN_SLPM (cfg);int output =PIN_DIR (cfg);int val =PIN_VAL (cfg); +bool glitch = af ==NMK_GPIO_ALT_C ; dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n", pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
@@ -202,8 +243,116 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,__nmk_gpio_set_pull (nmk_chip, offset, pull); } -__nmk_gpio_set_slpm (nmk_chip, offset, slpm); -__nmk_gpio_set_mode (nmk_chip, offset, af); +/* +* If we've backed up the SLPM registers (glitch workaround), modify +* the backups since they will be restored. +*/ +if (slpmregs) { +if (slpm ==NMK_GPIO_SLPM_NOCHANGE ) + slpmregs[nmk_chip->bank] |=BIT (offset); +else + slpmregs[nmk_chip->bank] &= ~BIT (offset); + }else +__nmk_gpio_set_slpm (nmk_chip, offset, slpm); + +__nmk_gpio_set_mode_safe (nmk_chip, offset, af, glitch); +} + +/* +* Safe sequence used to switch IOs between GPIO and Alternate-C mode: +* - Save SLPM registers +* - Set SLPM=0 for the IOs you want to switch and others to 1 +* - Configure the GPIO registers for the IOs that are being switched +* - Set IOFORCE=1 +* - Modify the AFLSA/B registers for the IOs that are being switched +* - Set IOFORCE=0 +* - Restore SLPM registers +* - Any spurious wake up event during switch sequence to be ignored and +* cleared +*/ +static void nmk_gpio_glitch_slpm_init (unsigned int *slpm) +{ +int i; + +for (i =0 ; i <NUM_BANKS ; i++) { +struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; +unsigned int temp = slpm[i]; + +if (!chip) +break ; + + slpm[i] =readl (chip->addr +NMK_GPIO_SLPC ); +writel (temp, chip->addr +NMK_GPIO_SLPC ); + } +} + +static void nmk_gpio_glitch_slpm_restore (unsigned int *slpm) +{ +int i; + +for (i =0 ; i <NUM_BANKS ; i++) { +struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + +if (!chip) +break ; + +writel (slpm[i], chip->addr +NMK_GPIO_SLPC ); + } +} + +static int __nmk_config_pins (pin_cfg_t *cfgs,int num,bool sleep) +{ +static unsigned int slpm[NUM_BANKS ]; +unsigned long flags; +bool glitch = false; +int ret =0 ; +int i; + +for (i =0 ; i < num; i++) { +if (PIN_ALT (cfgs[i]) ==NMK_GPIO_ALT_C ) { + glitch = true; +break ; + } + } + +spin_lock_irqsave (&nmk_gpio_slpm_lock, flags); + +if (glitch) { +memset (slpm,0xff ,sizeof (slpm)); + +for (i =0 ; i < num; i++) { +int pin =PIN_NUM (cfgs[i]); +int offset = pin %NMK_GPIO_PER_CHIP ; + +if (PIN_ALT (cfgs[i]) ==NMK_GPIO_ALT_C ) + slpm[pin /NMK_GPIO_PER_CHIP ] &= ~BIT (offset); + } + +nmk_gpio_glitch_slpm_init (slpm); + } + +for (i =0 ; i < num; i++) { +struct nmk_gpio_chip *nmk_chip; +int pin =PIN_NUM (cfgs[i]); + + nmk_chip =get_irq_chip_data (NOMADIK_GPIO_TO_IRQ (pin)); +if (!nmk_chip) { + ret = -EINVAL ; +break ; + } + +spin_lock (&nmk_chip->lock); +__nmk_config_pin (nmk_chip, pin - nmk_chip->chip.base, + cfgs[i], sleep, glitch ? slpm :NULL ); +spin_unlock (&nmk_chip->lock); + } + +if (glitch) +nmk_gpio_glitch_slpm_restore (slpm); + +spin_unlock_irqrestore (&nmk_gpio_slpm_lock, flags); + +return ret; }/**
@@ -222,19 +371,7 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,*/ int nmk_config_pin (pin_cfg_t cfg,bool sleep) { -struct nmk_gpio_chip *nmk_chip; -int gpio =PIN_NUM (cfg); -unsigned long flags; - - nmk_chip =get_irq_chip_data (NOMADIK_GPIO_TO_IRQ (gpio)); -if (!nmk_chip) -return -EINVAL ; - -spin_lock_irqsave (&nmk_chip->lock, flags); -__nmk_config_pin (nmk_chip, gpio - nmk_chip->chip.base, cfg, sleep); -spin_unlock_irqrestore (&nmk_chip->lock, flags); - -return 0 ; +return __nmk_config_pins (&cfg,1 , sleep); }EXPORT_SYMBOL (nmk_config_pin);
@@ -248,31 +385,13 @@ EXPORT_SYMBOL(nmk_config_pin);*/ int nmk_config_pins (pin_cfg_t *cfgs,int num) { -int ret =0 ; -int i; - -for (i =0 ; i < num; i++) { - ret =nmk_config_pin (cfgs[i], false); -if (ret) -break ; - } - -return ret; +return __nmk_config_pins (cfgs, num, false); }EXPORT_SYMBOL (nmk_config_pins);int nmk_config_pins_sleep (pin_cfg_t *cfgs,int num) { -int ret =0 ; -int i; - -for (i =0 ; i < num; i++) { - ret =nmk_config_pin (cfgs[i], true); -if (ret) -break ; - } - -return ret; +return __nmk_config_pins (cfgs, num, true); }EXPORT_SYMBOL (nmk_config_pins_sleep);
@@ -299,9 +418,13 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)if (!nmk_chip)return -EINVAL ; -spin_lock_irqsave (&nmk_chip->lock, flags); +spin_lock_irqsave (&nmk_gpio_slpm_lock, flags); +spin_lock (&nmk_chip->lock); +__nmk_gpio_set_slpm (nmk_chip, gpio - nmk_chip->chip.base, mode); -spin_unlock_irqrestore (&nmk_chip->lock, flags); + +spin_unlock (&nmk_chip->lock); +spin_unlock_irqrestore (&nmk_gpio_slpm_lock, flags);return 0 ; }
@@ -474,7 +597,9 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)if (!nmk_chip)return -EINVAL ; -spin_lock_irqsave (&nmk_chip->lock, flags); +spin_lock_irqsave (&nmk_gpio_slpm_lock, flags); +spin_lock (&nmk_chip->lock); +#ifdef CONFIG_ARCH_U8500 if (cpu_is_u8500v2 ()) { __nmk_gpio_set_slpm(nmk_chip, gpio,
@@ -483,7 +608,9 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) }#endif __nmk_gpio_irq_modify (nmk_chip, gpio,WAKE , on); -spin_unlock_irqrestore (&nmk_chip->lock, flags); + +spin_unlock (&nmk_chip->lock); +spin_unlock_irqrestore (&nmk_gpio_slpm_lock, flags);return 0 ; }
@@ -826,6 +953,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) nmk_chip->parent_irq = irq; nmk_chip->secondary_parent_irq = secondary_irq; nmk_chip->get_secondary_status = pdata->get_secondary_status; + nmk_chip->set_ioforce = pdata->set_ioforce;spin_lock_init (&nmk_chip->lock); chip = &nmk_chip->chip;
@@ -839,6 +967,9 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)if (ret) goto out_free; +BUG_ON (nmk_chip->bank >=ARRAY_SIZE (nmk_gpio_chips)); + + nmk_gpio_chips[nmk_chip->bank] = nmk_chip;platform_set_drvdata (dev, nmk_chip);nmk_gpio_init_irq (nmk_chip);
arch/arm/plat-nomadik/include/plat/gpio.h +1 -0
@@ -84,6 +84,7 @@ struct nmk_gpio_platform_data {int first_irq;int num_gpio;u32 (*get_secondary_status)(unsigned int bank); + void (*set_ioforce)(bool enable); };#endif /* __ASM_PLAT_GPIO_H */
Signature · 1 line
1.7.3.2
PATCH 9/9 plat-nomadik: change sleep/wakeup setting in GPIO SLPM register
In reply to Linus WalleijFrom: Rikard Olsson <[email protected]>
This patch fixes a bug when setting SLPM register for DB8500. When calling__nmk_gpio_set_slpm(...) offset to GPIO is now used instead of the GPIO number itself.
--- arch/arm/plat-nomadik/gpio.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/plat-nomadik/gpio.c +1 -1
@@ -602,7 +602,7 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)#ifdef CONFIG_ARCH_U8500 if (cpu_is_u8500v2 ()) { -__nmk_gpio_set_slpm (nmk_chip, gpio, +__nmk_gpio_set_slpm (nmk_chip, gpio - nmk_chip->chip.base, on ?NMK_GPIO_SLPM_WAKEUP_ENABLE :NMK_GPIO_SLPM_WAKEUP_DISABLE ); }
Signature · 1 line
1.7.3.2