aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/gpio.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2008-12-25 04:17:18 -0500
committerPaul Mundt <lethal@linux-sh.org>2009-01-27 00:49:09 -0500
commit0fc64cc0a27288e77ee8e12648d59632649371fc (patch)
tree1104b4892473a1df3162941904b0a16bb2786adf /arch/sh/kernel/gpio.c
parent18801be7f805b891876a6676ec7fac2e1acdec13 (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.c126
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
49static int read_write_reg(unsigned long reg, unsigned long reg_width, 49static 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
79static 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
98static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) 110static 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
208static int write_config_reg(struct pinmux_info *gpioc, 220static 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
222static int check_config_reg(struct pinmux_info *gpioc, 233static 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
239enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; 250enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
240 251
241int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, 252static 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);
393static int pinmux_direction(struct pinmux_info *gpioc, 403static 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}
447EXPORT_SYMBOL(gpio_direction_input); 457EXPORT_SYMBOL(gpio_direction_input);
448 458
449static int __gpio_get_set_value(struct pinmux_info *gpioc, 459static 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
465int gpio_direction_output(unsigned gpio, int value) 471int 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}
481EXPORT_SYMBOL(gpio_direction_output); 484EXPORT_SYMBOL(gpio_direction_output);
482 485
483int gpio_get_value(unsigned gpio) 486static 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
499int gpio_get_value(unsigned gpio)
500{
501 return __gpio_get_value(gpio_controller(gpio), gpio);
498} 502}
499EXPORT_SYMBOL(gpio_get_value); 503EXPORT_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}
514EXPORT_SYMBOL(gpio_set_value); 514EXPORT_SYMBOL(gpio_set_value);
515 515