diff options
author | Magnus Damm <damm@igel.co.jp> | 2008-12-25 04:17:18 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-01-27 00:49:09 -0500 |
commit | 0fc64cc0a27288e77ee8e12648d59632649371fc (patch) | |
tree | 1104b4892473a1df3162941904b0a16bb2786adf /arch/sh/kernel/gpio.c | |
parent | 18801be7f805b891876a6676ec7fac2e1acdec13 (diff) |
sh: lockless gpio_get_value()
This patch separates the register read and write functions to
allow lockless gpio_get_value().
Signed-off-by: Magnus Damm <damm@igel.co.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/gpio.c')
-rw-r--r-- | arch/sh/kernel/gpio.c | 126 |
1 files changed, 63 insertions, 63 deletions
diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c index fe92ba151b89..f8397a09491c 100644 --- a/arch/sh/kernel/gpio.c +++ b/arch/sh/kernel/gpio.c | |||
@@ -46,9 +46,8 @@ static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r) | |||
46 | return 1; | 46 | return 1; |
47 | } | 47 | } |
48 | 48 | ||
49 | static int read_write_reg(unsigned long reg, unsigned long reg_width, | 49 | static int gpio_read_reg(unsigned long reg, unsigned long reg_width, |
50 | unsigned long field_width, unsigned long in_pos, | 50 | unsigned long field_width, unsigned long in_pos) |
51 | unsigned long value, int do_write) | ||
52 | { | 51 | { |
53 | unsigned long data, mask, pos; | 52 | unsigned long data, mask, pos; |
54 | 53 | ||
@@ -57,10 +56,9 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width, | |||
57 | pos = reg_width - ((in_pos + 1) * field_width); | 56 | pos = reg_width - ((in_pos + 1) * field_width); |
58 | 57 | ||
59 | #ifdef DEBUG | 58 | #ifdef DEBUG |
60 | pr_info("%s, addr = %lx, value = %ld, pos = %ld, " | 59 | pr_info("read_reg: addr = %lx, pos = %ld, " |
61 | "r_width = %ld, f_width = %ld\n", | 60 | "r_width = %ld, f_width = %ld\n", |
62 | do_write ? "write" : "read", reg, value, pos, | 61 | reg, pos, reg_width, field_width); |
63 | reg_width, field_width); | ||
64 | #endif | 62 | #endif |
65 | 63 | ||
66 | switch (reg_width) { | 64 | switch (reg_width) { |
@@ -75,24 +73,38 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width, | |||
75 | break; | 73 | break; |
76 | } | 74 | } |
77 | 75 | ||
78 | if (!do_write) | 76 | return (data >> pos) & mask; |
79 | return (data >> pos) & mask; | 77 | } |
78 | |||
79 | static void gpio_write_reg(unsigned long reg, unsigned long reg_width, | ||
80 | unsigned long field_width, unsigned long in_pos, | ||
81 | unsigned long value) | ||
82 | { | ||
83 | unsigned long mask, pos; | ||
84 | |||
85 | mask = (1 << field_width) - 1; | ||
86 | pos = reg_width - ((in_pos + 1) * field_width); | ||
80 | 87 | ||
81 | data &= ~(mask << pos); | 88 | #ifdef DEBUG |
82 | data |= value << pos; | 89 | pr_info("write_reg addr = %lx, value = %ld, pos = %ld, " |
90 | "r_width = %ld, f_width = %ld\n", | ||
91 | reg, value, pos, reg_width, field_width); | ||
92 | #endif | ||
93 | |||
94 | mask = ~(mask << pos); | ||
95 | value = value << pos; | ||
83 | 96 | ||
84 | switch (reg_width) { | 97 | switch (reg_width) { |
85 | case 8: | 98 | case 8: |
86 | ctrl_outb(data, reg); | 99 | ctrl_outb((ctrl_inb(reg) & mask) | value, reg); |
87 | break; | 100 | break; |
88 | case 16: | 101 | case 16: |
89 | ctrl_outw(data, reg); | 102 | ctrl_outw((ctrl_inw(reg) & mask) | value, reg); |
90 | break; | 103 | break; |
91 | case 32: | 104 | case 32: |
92 | ctrl_outl(data, reg); | 105 | ctrl_outl((ctrl_inl(reg) & mask) | value, reg); |
93 | break; | 106 | break; |
94 | } | 107 | } |
95 | return 0; | ||
96 | } | 108 | } |
97 | 109 | ||
98 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) | 110 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) |
@@ -205,9 +217,9 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, | |||
205 | return -1; | 217 | return -1; |
206 | } | 218 | } |
207 | 219 | ||
208 | static int write_config_reg(struct pinmux_info *gpioc, | 220 | static void write_config_reg(struct pinmux_info *gpioc, |
209 | struct pinmux_cfg_reg *crp, | 221 | struct pinmux_cfg_reg *crp, |
210 | int index) | 222 | int index) |
211 | { | 223 | { |
212 | unsigned long ncomb, pos, value; | 224 | unsigned long ncomb, pos, value; |
213 | 225 | ||
@@ -215,8 +227,7 @@ static int write_config_reg(struct pinmux_info *gpioc, | |||
215 | pos = index / ncomb; | 227 | pos = index / ncomb; |
216 | value = index % ncomb; | 228 | value = index % ncomb; |
217 | 229 | ||
218 | return read_write_reg(crp->reg, crp->reg_width, | 230 | gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value); |
219 | crp->field_width, pos, value, 1); | ||
220 | } | 231 | } |
221 | 232 | ||
222 | static int check_config_reg(struct pinmux_info *gpioc, | 233 | static int check_config_reg(struct pinmux_info *gpioc, |
@@ -229,8 +240,8 @@ static int check_config_reg(struct pinmux_info *gpioc, | |||
229 | pos = index / ncomb; | 240 | pos = index / ncomb; |
230 | value = index % ncomb; | 241 | value = index % ncomb; |
231 | 242 | ||
232 | if (read_write_reg(crp->reg, crp->reg_width, | 243 | if (gpio_read_reg(crp->reg, crp->reg_width, |
233 | crp->field_width, pos, 0, 0) == value) | 244 | crp->field_width, pos) == value) |
234 | return 0; | 245 | return 0; |
235 | 246 | ||
236 | return -1; | 247 | return -1; |
@@ -238,8 +249,8 @@ static int check_config_reg(struct pinmux_info *gpioc, | |||
238 | 249 | ||
239 | enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; | 250 | enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; |
240 | 251 | ||
241 | int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | 252 | static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, |
242 | int pinmux_type, int cfg_mode) | 253 | int pinmux_type, int cfg_mode) |
243 | { | 254 | { |
244 | struct pinmux_cfg_reg *cr = NULL; | 255 | struct pinmux_cfg_reg *cr = NULL; |
245 | pinmux_enum_t enum_id; | 256 | pinmux_enum_t enum_id; |
@@ -305,8 +316,7 @@ int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | |||
305 | break; | 316 | break; |
306 | 317 | ||
307 | case GPIO_CFG_REQ: | 318 | case GPIO_CFG_REQ: |
308 | if (write_config_reg(gpioc, cr, index) != 0) | 319 | write_config_reg(gpioc, cr, index); |
309 | goto out_err; | ||
310 | *cntp = *cntp + 1; | 320 | *cntp = *cntp + 1; |
311 | break; | 321 | break; |
312 | 322 | ||
@@ -393,9 +403,12 @@ EXPORT_SYMBOL(gpio_free); | |||
393 | static int pinmux_direction(struct pinmux_info *gpioc, | 403 | static int pinmux_direction(struct pinmux_info *gpioc, |
394 | unsigned gpio, int new_pinmux_type) | 404 | unsigned gpio, int new_pinmux_type) |
395 | { | 405 | { |
396 | int ret, pinmux_type; | 406 | int pinmux_type; |
407 | int ret = -EINVAL; | ||
408 | |||
409 | if (!gpioc) | ||
410 | goto err_out; | ||
397 | 411 | ||
398 | ret = -EINVAL; | ||
399 | pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; | 412 | pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; |
400 | 413 | ||
401 | switch (pinmux_type) { | 414 | switch (pinmux_type) { |
@@ -433,68 +446,59 @@ int gpio_direction_input(unsigned gpio) | |||
433 | { | 446 | { |
434 | struct pinmux_info *gpioc = gpio_controller(gpio); | 447 | struct pinmux_info *gpioc = gpio_controller(gpio); |
435 | unsigned long flags; | 448 | unsigned long flags; |
436 | int ret = -EINVAL; | 449 | int ret; |
437 | |||
438 | if (!gpioc) | ||
439 | goto err_out; | ||
440 | 450 | ||
441 | spin_lock_irqsave(&gpio_lock, flags); | 451 | spin_lock_irqsave(&gpio_lock, flags); |
442 | ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_INPUT); | 452 | ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_INPUT); |
443 | spin_unlock_irqrestore(&gpio_lock, flags); | 453 | spin_unlock_irqrestore(&gpio_lock, flags); |
444 | err_out: | 454 | |
445 | return ret; | 455 | return ret; |
446 | } | 456 | } |
447 | EXPORT_SYMBOL(gpio_direction_input); | 457 | EXPORT_SYMBOL(gpio_direction_input); |
448 | 458 | ||
449 | static int __gpio_get_set_value(struct pinmux_info *gpioc, | 459 | static void __gpio_set_value(struct pinmux_info *gpioc, |
450 | unsigned gpio, int value, | 460 | unsigned gpio, int value) |
451 | int do_write) | ||
452 | { | 461 | { |
453 | struct pinmux_data_reg *dr = NULL; | 462 | struct pinmux_data_reg *dr = NULL; |
454 | int bit = 0; | 463 | int bit = 0; |
455 | 464 | ||
456 | if (get_data_reg(gpioc, gpio, &dr, &bit) != 0) | 465 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) |
457 | BUG(); | 466 | BUG(); |
458 | else | 467 | else |
459 | value = read_write_reg(dr->reg, dr->reg_width, | 468 | gpio_write_reg(dr->reg, dr->reg_width, 1, bit, !!value); |
460 | 1, bit, !!value, do_write); | ||
461 | |||
462 | return value; | ||
463 | } | 469 | } |
464 | 470 | ||
465 | int gpio_direction_output(unsigned gpio, int value) | 471 | int gpio_direction_output(unsigned gpio, int value) |
466 | { | 472 | { |
467 | struct pinmux_info *gpioc = gpio_controller(gpio); | 473 | struct pinmux_info *gpioc = gpio_controller(gpio); |
468 | unsigned long flags; | 474 | unsigned long flags; |
469 | int ret = -EINVAL; | 475 | int ret; |
470 | |||
471 | if (!gpioc) | ||
472 | goto err_out; | ||
473 | 476 | ||
474 | spin_lock_irqsave(&gpio_lock, flags); | 477 | spin_lock_irqsave(&gpio_lock, flags); |
475 | __gpio_get_set_value(gpioc, gpio, value, 1); | 478 | __gpio_set_value(gpioc, gpio, value); |
476 | ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT); | 479 | ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT); |
477 | spin_unlock_irqrestore(&gpio_lock, flags); | 480 | spin_unlock_irqrestore(&gpio_lock, flags); |
478 | err_out: | 481 | |
479 | return ret; | 482 | return ret; |
480 | } | 483 | } |
481 | EXPORT_SYMBOL(gpio_direction_output); | 484 | EXPORT_SYMBOL(gpio_direction_output); |
482 | 485 | ||
483 | int gpio_get_value(unsigned gpio) | 486 | static int __gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) |
484 | { | 487 | { |
485 | struct pinmux_info *gpioc = gpio_controller(gpio); | 488 | struct pinmux_data_reg *dr = NULL; |
486 | unsigned long flags; | 489 | int bit = 0; |
487 | int value = 0; | ||
488 | 490 | ||
489 | if (!gpioc) | 491 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) { |
490 | BUG(); | 492 | BUG(); |
491 | else { | 493 | return 0; |
492 | spin_lock_irqsave(&gpio_lock, flags); | ||
493 | value = __gpio_get_set_value(gpioc, gpio, 0, 0); | ||
494 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
495 | } | 494 | } |
496 | 495 | ||
497 | return value; | 496 | return gpio_read_reg(dr->reg, dr->reg_width, 1, bit); |
497 | } | ||
498 | |||
499 | int gpio_get_value(unsigned gpio) | ||
500 | { | ||
501 | return __gpio_get_value(gpio_controller(gpio), gpio); | ||
498 | } | 502 | } |
499 | EXPORT_SYMBOL(gpio_get_value); | 503 | EXPORT_SYMBOL(gpio_get_value); |
500 | 504 | ||
@@ -503,13 +507,9 @@ void gpio_set_value(unsigned gpio, int value) | |||
503 | struct pinmux_info *gpioc = gpio_controller(gpio); | 507 | struct pinmux_info *gpioc = gpio_controller(gpio); |
504 | unsigned long flags; | 508 | unsigned long flags; |
505 | 509 | ||
506 | if (!gpioc) | 510 | spin_lock_irqsave(&gpio_lock, flags); |
507 | BUG(); | 511 | __gpio_set_value(gpioc, gpio, value); |
508 | else { | 512 | spin_unlock_irqrestore(&gpio_lock, flags); |
509 | spin_lock_irqsave(&gpio_lock, flags); | ||
510 | __gpio_get_set_value(gpioc, gpio, value, 1); | ||
511 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
512 | } | ||
513 | } | 513 | } |
514 | EXPORT_SYMBOL(gpio_set_value); | 514 | EXPORT_SYMBOL(gpio_set_value); |
515 | 515 | ||