Skip to content

Commit

Permalink
ARM: SAMSUNG: Add spinlock locking to GPIO banks
Browse files Browse the repository at this point in the history
Add locking to each GPIO bank to allow for SMP capable code
to use the gpiolib functions. See the gpio-core.h header file
for more information.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
  • Loading branch information
Ben Dooks committed May 11, 2010
1 parent 1d3ef01 commit fcef85c
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 12 deletions.
12 changes: 6 additions & 6 deletions arch/arm/plat-samsung/gpio-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)

offset = pin - chip->chip.base;

local_irq_save(flags);
s3c_gpio_lock(chip, flags);
ret = s3c_gpio_do_setcfg(chip, offset, config);
local_irq_restore(flags);
s3c_gpio_unlock(chip, flags);

return ret;
}
Expand All @@ -51,9 +51,9 @@ unsigned s3c_gpio_getcfg(unsigned int pin)
if (chip) {
offset = pin - chip->chip.base;

local_irq_save(flags);
s3c_gpio_lock(chip, flags);
ret = s3c_gpio_do_getcfg(chip, offset);
local_irq_restore(flags);
s3c_gpio_unlock(chip, flags);
}

return ret;
Expand All @@ -72,9 +72,9 @@ int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull)

offset = pin - chip->chip.base;

local_irq_save(flags);
s3c_gpio_lock(chip, flags);
ret = s3c_gpio_do_setpull(chip, offset, pull);
local_irq_restore(flags);
s3c_gpio_unlock(chip, flags);

return ret;
}
Expand Down
15 changes: 9 additions & 6 deletions arch/arm/plat-samsung/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/spinlock.h>

#include <plat/gpio-core.h>

Expand Down Expand Up @@ -52,14 +53,14 @@ static int s3c_gpiolib_input(struct gpio_chip *chip, unsigned offset)
unsigned long flags;
unsigned long con;

local_irq_save(flags);
s3c_gpio_lock(ourchip, flags);

con = __raw_readl(base + 0x00);
con &= ~(3 << (offset * 2));

__raw_writel(con, base + 0x00);

local_irq_restore(flags);
s3c_gpio_unlock(ourchip, flags);
return 0;
}

Expand All @@ -72,7 +73,7 @@ static int s3c_gpiolib_output(struct gpio_chip *chip,
unsigned long dat;
unsigned long con;

local_irq_save(flags);
s3c_gpio_lock(ourchip, flags);

dat = __raw_readl(base + 0x04);
dat &= ~(1 << offset);
Expand All @@ -87,7 +88,7 @@ static int s3c_gpiolib_output(struct gpio_chip *chip,
__raw_writel(con, base + 0x00);
__raw_writel(dat, base + 0x04);

local_irq_restore(flags);
s3c_gpio_unlock(ourchip, flags);
return 0;
}

Expand All @@ -99,15 +100,15 @@ static void s3c_gpiolib_set(struct gpio_chip *chip,
unsigned long flags;
unsigned long dat;

local_irq_save(flags);
s3c_gpio_lock(ourchip, flags);

dat = __raw_readl(base + 0x04);
dat &= ~(1 << offset);
if (value)
dat |= 1 << offset;
__raw_writel(dat, base + 0x04);

local_irq_restore(flags);
s3c_gpio_unlock(ourchip, flags);
}

static int s3c_gpiolib_get(struct gpio_chip *chip, unsigned offset)
Expand All @@ -131,6 +132,8 @@ __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
BUG_ON(!gc->label);
BUG_ON(!gc->ngpio);

spin_lock_init(&chip->lock);

if (!gc->direction_input)
gc->direction_input = s3c_gpiolib_input;
if (!gc->direction_output)
Expand Down
14 changes: 14 additions & 0 deletions arch/arm/plat-samsung/include/plat/gpio-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,26 @@ struct s3c_gpio_cfg;
* @chip: The chip structure to be exported via gpiolib.
* @base: The base pointer to the gpio configuration registers.
* @config: special function and pull-resistor control information.
* @lock: Lock for exclusive access to this gpio bank.
* @pm_save: Save information for suspend/resume support.
*
* This wrapper provides the necessary information for the Samsung
* specific gpios being registered with gpiolib.
*
* The lock protects each gpio bank from multiple access of the shared
* configuration registers, or from reading of data whilst another thread
* is writing to the register set.
*
* Each chip has its own lock to avoid any contention between different
* CPU cores trying to get one lock for different GPIO banks, where each
* bank of GPIO has its own register space and configuration registers.
*/
struct s3c_gpio_chip {
struct gpio_chip chip;
struct s3c_gpio_cfg *config;
struct s3c_gpio_pm *pm;
void __iomem *base;
spinlock_t lock;
#ifdef CONFIG_PM
u32 pm_save[4];
#endif
Expand Down Expand Up @@ -138,3 +148,7 @@ extern struct s3c_gpio_pm s3c_gpio_pm_4bit;
#define __gpio_pm(x) NULL

#endif /* CONFIG_PM */

/* locking wrappers to deal with multiple access to the same gpio bank */
#define s3c_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl)
#define s3c_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl)

0 comments on commit fcef85c

Please sign in to comment.