Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 358745
b: refs/heads/master
c: c111fea
h: refs/heads/master
i:
  358743: cf1fd1b
v: v3
  • Loading branch information
Peter Ujfalusi authored and Linus Walleij committed Jan 17, 2013
1 parent b36b065 commit e782bca
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 72c7901ef00925c6d0cc7ab69183a684908303bc
refs/heads/master: c111feabe2e200b15300d97107ffc1280bf8de2a
100 changes: 65 additions & 35 deletions trunk/drivers/gpio/gpio-twl4030.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@

#include <linux/i2c/twl.h>


/*
* The GPIO "subchip" supports 18 GPIOs which can be configured as
* inputs or outputs, with pullups or pulldowns on each pin. Each
Expand All @@ -64,14 +63,15 @@
/* Mask for GPIO registers when aggregated into a 32-bit integer */
#define GPIO_32_MASK 0x0003ffff

/* Data structures */
static DEFINE_MUTEX(gpio_lock);

struct gpio_twl4030_priv {
struct gpio_chip gpio_chip;
struct mutex mutex;
int irq_base;

/* Bitfields for state caching */
unsigned int usage_count;
unsigned int direction;
unsigned int out_state;
};

/*----------------------------------------------------------------------*/
Expand Down Expand Up @@ -130,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address)

/*----------------------------------------------------------------------*/

static u8 cached_leden; /* protected by gpio_lock */
static u8 cached_leden;

/* The LED lines are open drain outputs ... a FET pulls to GND, so an
* external pullup is needed. We could also expose the integrated PWM
Expand All @@ -144,14 +144,12 @@ static void twl4030_led_set_value(int led, int value)
if (led)
mask <<= 1;

mutex_lock(&gpio_lock);
if (value)
cached_leden &= ~mask;
else
cached_leden |= mask;
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
TWL4030_LED_LEDEN_REG);
mutex_unlock(&gpio_lock);
}

static int twl4030_set_gpio_direction(int gpio, int is_input)
Expand All @@ -162,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
u8 base = REG_GPIODATADIR1 + d_bnk;
int ret = 0;

mutex_lock(&gpio_lock);
ret = gpio_twl4030_read(base);
if (ret >= 0) {
if (is_input)
Expand All @@ -172,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)

ret = gpio_twl4030_write(base, reg);
}
mutex_unlock(&gpio_lock);
return ret;
}

Expand Down Expand Up @@ -212,7 +208,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int status = 0;

mutex_lock(&gpio_lock);
mutex_lock(&priv->mutex);

/* Support the two LED outputs as output-only GPIOs. */
if (offset >= TWL4030_GPIO_MAX) {
Expand Down Expand Up @@ -271,72 +267,104 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
if (!status)
priv->usage_count |= BIT(offset);

mutex_unlock(&gpio_lock);
mutex_unlock(&priv->mutex);
return status;
}

static void twl_free(struct gpio_chip *chip, unsigned offset)
{
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);

mutex_lock(&priv->mutex);
if (offset >= TWL4030_GPIO_MAX) {
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
return;
goto out;
}

mutex_lock(&gpio_lock);

priv->usage_count &= ~BIT(offset);

/* on last use, switch off GPIO module */
if (!priv->usage_count)
gpio_twl4030_write(REG_GPIO_CTRL, 0x0);

mutex_unlock(&gpio_lock);
out:
mutex_unlock(&priv->mutex);
}

static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
{
return (offset < TWL4030_GPIO_MAX)
? twl4030_set_gpio_direction(offset, 1)
: -EINVAL;
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int ret;

mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX)
ret = twl4030_set_gpio_direction(offset, 1);
else
ret = -EINVAL;

if (!ret)
priv->direction &= ~BIT(offset);

mutex_unlock(&priv->mutex);

return ret;
}

static int twl_get(struct gpio_chip *chip, unsigned offset)
{
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int ret;
int status = 0;

if (!(priv->usage_count & BIT(offset)))
return -EPERM;
mutex_lock(&priv->mutex);
if (!(priv->usage_count & BIT(offset))) {
ret = -EPERM;
goto out;
}

if (offset < TWL4030_GPIO_MAX)
status = twl4030_get_gpio_datain(offset);
else if (offset == TWL4030_GPIO_MAX)
status = cached_leden & LEDEN_LEDAON;
if (priv->direction & BIT(offset))
status = priv->out_state & BIT(offset);
else
status = cached_leden & LEDEN_LEDBON;
status = twl4030_get_gpio_datain(offset);

return (status < 0) ? 0 : status;
ret = (status <= 0) ? 0 : 1;
out:
mutex_unlock(&priv->mutex);
return ret;
}

static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
{
if (offset < TWL4030_GPIO_MAX) {
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);

mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX)
twl4030_set_gpio_dataout(offset, value);
return twl4030_set_gpio_direction(offset, 0);
} else {
else
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
return 0;
}

if (value)
priv->out_state |= BIT(offset);
else
priv->out_state &= ~BIT(offset);

mutex_unlock(&priv->mutex);
}

static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
{
struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);

mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX)
twl4030_set_gpio_dataout(offset, value);
else
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);

priv->direction |= BIT(offset);
mutex_unlock(&priv->mutex);

twl_set(chip, offset, value);

return 0;
}

static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
Expand Down Expand Up @@ -469,6 +497,8 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
priv->gpio_chip.dev = &pdev->dev;

mutex_init(&priv->mutex);

if (node)
pdata = of_gpio_twl4030(&pdev->dev);

Expand Down

0 comments on commit e782bca

Please sign in to comment.