Re: [PATCH v2 2/3] gpio: twl4030: Cache the direction and output states in private data
From: Michael Trimarchi <michael@amarulasolutions.com>
Date: 2012-12-19 20:59:18
Also in:
lkml
Hi Grant Likely [off-list ref] wrote:
On Thu, 6 Dec 2012 11:52:06 +0100, Peter Ujfalusi [off-list ref] wrote:quoted
Use more coherent locking in the driver. Use bitfield to store theGPIOquoted
direction and if the pin is configured as output store the statusalso in aquoted
bitfiled. In this way we can just look at these bitfields when we needinformationquoted
about the pin status and only reach out to the chip when it isneeded.quoted
Signed-off-by: Peter Ujfalusi <redacted>Applied, thanks g.quoted
--- drivers/gpio/gpio-twl4030.c | 99++++++++++++++++++++++++++++++---------------quoted
1 file changed, 66 insertions(+), 33 deletions(-)diff --git a/drivers/gpio/gpio-twl4030.cb/drivers/gpio/gpio-twl4030.cquoted
index c092739..a38e6e9c 100644--- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c@@ -64,14 +64,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; };/*----------------------------------------------------------------------*/quoted
@@ -130,7 +131,7 @@ static inline int gpio_twl4030_read(u8 address)/*----------------------------------------------------------------------*/quoted
-static u8 cached_leden; /* protected by gpio_lock */ +static u8 cached_leden; /* The LED lines are open drain outputs ... a FET pulls to GND, soanquoted
* external pullup is needed. We could also expose the integratedPWMquoted
@@ -144,14 +145,12 @@ static void twl4030_led_set_value(int led, intvalue)quoted
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)@@ -162,7 +161,6 @@ static int twl4030_set_gpio_direction(int gpio,int is_input)quoted
u8 base = REG_GPIODATADIR1 + d_bnk; int ret = 0; - mutex_lock(&gpio_lock); ret = gpio_twl4030_read(base); if (ret >= 0) { if (is_input)@@ -172,7 +170,6 @@ static int twl4030_set_gpio_direction(int gpio,int is_input)quoted
ret = gpio_twl4030_write(base, reg); } - mutex_unlock(&gpio_lock); return ret; }@@ -212,7 +209,7 @@ static int twl_request(struct gpio_chip *chip,unsigned offset)quoted
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) {@@ -271,7 +268,7 @@ done: if (!status) priv->usage_count |= BIT(offset); - mutex_unlock(&gpio_lock); + mutex_unlock(&priv->mutex); return status; }@@ -279,64 +276,98 @@ static void twl_free(struct gpio_chip *chip,unsigned offset)quoted
{ 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);
I have the mobile but where is the unlock here?
quoted
return; } - 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); + 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); + dev_err(chip->dev, "%s: offset %d value %d\n", __func__, offset,ret);quoted
+ return ret; } -static int twl_direction_out(struct gpio_chip *chip, unsignedoffset, int value)quoted
+static void twl_set(struct gpio_chip *chip, unsigned offset, intvalue)quoted
{ - if (offset < TWL4030_GPIO_MAX) { + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + dev_err(chip->dev, "%s: offset %d value %d\n", __func__, offset,value);quoted
+ 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, intvalue)quoted
+static int twl_direction_out(struct gpio_chip *chip, unsignedoffset, int value)quoted
{ + struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); + + dev_err(chip->dev, "%s: offset %d value %d\n", __func__, offset,value);quoted
+ 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)@@ -469,6 +500,8 @@ no_irqs: 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);-- 1.8.0
-- Sent from my Android phone with K-9 Mail. Please excuse my brevity.