aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpio/gpio-twl4030.c100
1 files changed, 65 insertions, 35 deletions
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index 4643f9cd0cae..4d330e36da1d 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -37,7 +37,6 @@
37 37
38#include <linux/i2c/twl.h> 38#include <linux/i2c/twl.h>
39 39
40
41/* 40/*
42 * The GPIO "subchip" supports 18 GPIOs which can be configured as 41 * The GPIO "subchip" supports 18 GPIOs which can be configured as
43 * inputs or outputs, with pullups or pulldowns on each pin. Each 42 * inputs or outputs, with pullups or pulldowns on each pin. Each
@@ -64,14 +63,15 @@
64/* Mask for GPIO registers when aggregated into a 32-bit integer */ 63/* Mask for GPIO registers when aggregated into a 32-bit integer */
65#define GPIO_32_MASK 0x0003ffff 64#define GPIO_32_MASK 0x0003ffff
66 65
67/* Data structures */
68static DEFINE_MUTEX(gpio_lock);
69
70struct gpio_twl4030_priv { 66struct gpio_twl4030_priv {
71 struct gpio_chip gpio_chip; 67 struct gpio_chip gpio_chip;
68 struct mutex mutex;
72 int irq_base; 69 int irq_base;
73 70
71 /* Bitfields for state caching */
74 unsigned int usage_count; 72 unsigned int usage_count;
73 unsigned int direction;
74 unsigned int out_state;
75}; 75};
76 76
77/*----------------------------------------------------------------------*/ 77/*----------------------------------------------------------------------*/
@@ -130,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address)
130 130
131/*----------------------------------------------------------------------*/ 131/*----------------------------------------------------------------------*/
132 132
133static u8 cached_leden; /* protected by gpio_lock */ 133static u8 cached_leden;
134 134
135/* The LED lines are open drain outputs ... a FET pulls to GND, so an 135/* The LED lines are open drain outputs ... a FET pulls to GND, so an
136 * external pullup is needed. We could also expose the integrated PWM 136 * external pullup is needed. We could also expose the integrated PWM
@@ -144,14 +144,12 @@ static void twl4030_led_set_value(int led, int value)
144 if (led) 144 if (led)
145 mask <<= 1; 145 mask <<= 1;
146 146
147 mutex_lock(&gpio_lock);
148 if (value) 147 if (value)
149 cached_leden &= ~mask; 148 cached_leden &= ~mask;
150 else 149 else
151 cached_leden |= mask; 150 cached_leden |= mask;
152 status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, 151 status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
153 TWL4030_LED_LEDEN_REG); 152 TWL4030_LED_LEDEN_REG);
154 mutex_unlock(&gpio_lock);
155} 153}
156 154
157static int twl4030_set_gpio_direction(int gpio, int is_input) 155static int twl4030_set_gpio_direction(int gpio, int is_input)
@@ -162,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
162 u8 base = REG_GPIODATADIR1 + d_bnk; 160 u8 base = REG_GPIODATADIR1 + d_bnk;
163 int ret = 0; 161 int ret = 0;
164 162
165 mutex_lock(&gpio_lock);
166 ret = gpio_twl4030_read(base); 163 ret = gpio_twl4030_read(base);
167 if (ret >= 0) { 164 if (ret >= 0) {
168 if (is_input) 165 if (is_input)
@@ -172,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
172 169
173 ret = gpio_twl4030_write(base, reg); 170 ret = gpio_twl4030_write(base, reg);
174 } 171 }
175 mutex_unlock(&gpio_lock);
176 return ret; 172 return ret;
177} 173}
178 174
@@ -212,7 +208,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
212 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); 208 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
213 int status = 0; 209 int status = 0;
214 210
215 mutex_lock(&gpio_lock); 211 mutex_lock(&priv->mutex);
216 212
217 /* Support the two LED outputs as output-only GPIOs. */ 213 /* Support the two LED outputs as output-only GPIOs. */
218 if (offset >= TWL4030_GPIO_MAX) { 214 if (offset >= TWL4030_GPIO_MAX) {
@@ -271,7 +267,7 @@ done:
271 if (!status) 267 if (!status)
272 priv->usage_count |= BIT(offset); 268 priv->usage_count |= BIT(offset);
273 269
274 mutex_unlock(&gpio_lock); 270 mutex_unlock(&priv->mutex);
275 return status; 271 return status;
276} 272}
277 273
@@ -279,64 +275,96 @@ static void twl_free(struct gpio_chip *chip, unsigned offset)
279{ 275{
280 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); 276 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
281 277
278 mutex_lock(&priv->mutex);
282 if (offset >= TWL4030_GPIO_MAX) { 279 if (offset >= TWL4030_GPIO_MAX) {
283 twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); 280 twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
284 return; 281 goto out;
285 } 282 }
286 283
287 mutex_lock(&gpio_lock);
288
289 priv->usage_count &= ~BIT(offset); 284 priv->usage_count &= ~BIT(offset);
290 285
291 /* on last use, switch off GPIO module */ 286 /* on last use, switch off GPIO module */
292 if (!priv->usage_count) 287 if (!priv->usage_count)
293 gpio_twl4030_write(REG_GPIO_CTRL, 0x0); 288 gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
294 289
295 mutex_unlock(&gpio_lock); 290out:
291 mutex_unlock(&priv->mutex);
296} 292}
297 293
298static int twl_direction_in(struct gpio_chip *chip, unsigned offset) 294static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
299{ 295{
300 return (offset < TWL4030_GPIO_MAX) 296 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
301 ? twl4030_set_gpio_direction(offset, 1) 297 int ret;
302 : -EINVAL; 298
299 mutex_lock(&priv->mutex);
300 if (offset < TWL4030_GPIO_MAX)
301 ret = twl4030_set_gpio_direction(offset, 1);
302 else
303 ret = -EINVAL;
304
305 if (!ret)
306 priv->direction &= ~BIT(offset);
307
308 mutex_unlock(&priv->mutex);
309
310 return ret;
303} 311}
304 312
305static int twl_get(struct gpio_chip *chip, unsigned offset) 313static int twl_get(struct gpio_chip *chip, unsigned offset)
306{ 314{
307 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); 315 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
316 int ret;
308 int status = 0; 317 int status = 0;
309 318
310 if (!(priv->usage_count & BIT(offset))) 319 mutex_lock(&priv->mutex);
311 return -EPERM; 320 if (!(priv->usage_count & BIT(offset))) {
321 ret = -EPERM;
322 goto out;
323 }
312 324
313 if (offset < TWL4030_GPIO_MAX) 325 if (priv->direction & BIT(offset))
314 status = twl4030_get_gpio_datain(offset); 326 status = priv->out_state & BIT(offset);
315 else if (offset == TWL4030_GPIO_MAX)
316 status = cached_leden & LEDEN_LEDAON;
317 else 327 else
318 status = cached_leden & LEDEN_LEDBON; 328 status = twl4030_get_gpio_datain(offset);
319 329
320 return (status < 0) ? 0 : status; 330 ret = (status <= 0) ? 0 : 1;
331out:
332 mutex_unlock(&priv->mutex);
333 return ret;
321} 334}
322 335
323static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) 336static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
324{ 337{
325 if (offset < TWL4030_GPIO_MAX) { 338 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
339
340 mutex_lock(&priv->mutex);
341 if (offset < TWL4030_GPIO_MAX)
326 twl4030_set_gpio_dataout(offset, value); 342 twl4030_set_gpio_dataout(offset, value);
327 return twl4030_set_gpio_direction(offset, 0); 343 else
328 } else {
329 twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); 344 twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
330 return 0; 345
331 } 346 if (value)
347 priv->out_state |= BIT(offset);
348 else
349 priv->out_state &= ~BIT(offset);
350
351 mutex_unlock(&priv->mutex);
332} 352}
333 353
334static void twl_set(struct gpio_chip *chip, unsigned offset, int value) 354static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
335{ 355{
356 struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
357
358 mutex_lock(&priv->mutex);
336 if (offset < TWL4030_GPIO_MAX) 359 if (offset < TWL4030_GPIO_MAX)
337 twl4030_set_gpio_dataout(offset, value); 360 twl4030_set_gpio_dataout(offset, value);
338 else 361
339 twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); 362 priv->direction |= BIT(offset);
363 mutex_unlock(&priv->mutex);
364
365 twl_set(chip, offset, value);
366
367 return 0;
340} 368}
341 369
342static int twl_to_irq(struct gpio_chip *chip, unsigned offset) 370static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -469,6 +497,8 @@ no_irqs:
469 priv->gpio_chip.ngpio = TWL4030_GPIO_MAX; 497 priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
470 priv->gpio_chip.dev = &pdev->dev; 498 priv->gpio_chip.dev = &pdev->dev;
471 499
500 mutex_init(&priv->mutex);
501
472 if (node) 502 if (node)
473 pdata = of_gpio_twl4030(&pdev->dev); 503 pdata = of_gpio_twl4030(&pdev->dev);
474 504