aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/gpio.c
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2008-12-25 04:17:26 -0500
committerPaul Mundt <lethal@linux-sh.org>2009-01-27 00:49:10 -0500
commit3292094e88ce6b76714dad8ec4b43d7c5c12ada2 (patch)
tree0469a3523b1794a9ecb9f5df99ce3d726d442b2a /arch/sh/kernel/gpio.c
parent0fc64cc0a27288e77ee8e12648d59632649371fc (diff)
sh: lockless gpio_set_value()
This patch optimizes the gpio data register handling for gpio_set_value(). Instead of using the good old spinlock-plus-read-modify-write strategy we now use a shadow register and atomic operations. This improves the bitbanging mmc performance on Migo-R from 26 Kbytes/s to 40 Kbytes/s. 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.c106
1 files changed, 81 insertions, 25 deletions
diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c
index f8397a09491c..280135673726 100644
--- a/arch/sh/kernel/gpio.c
+++ b/arch/sh/kernel/gpio.c
@@ -46,6 +46,62 @@ 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 unsigned long gpio_read_raw_reg(unsigned long reg,
50 unsigned long reg_width)
51{
52 switch (reg_width) {
53 case 8:
54 return ctrl_inb(reg);
55 case 16:
56 return ctrl_inw(reg);
57 case 32:
58 return ctrl_inl(reg);
59 }
60
61 BUG();
62 return 0;
63}
64
65static void gpio_write_raw_reg(unsigned long reg,
66 unsigned long reg_width,
67 unsigned long data)
68{
69 switch (reg_width) {
70 case 8:
71 ctrl_outb(data, reg);
72 return;
73 case 16:
74 ctrl_outw(data, reg);
75 return;
76 case 32:
77 ctrl_outl(data, reg);
78 return;
79 }
80
81 BUG();
82}
83
84static void gpio_write_bit(struct pinmux_data_reg *dr,
85 unsigned long in_pos, unsigned long value)
86{
87 unsigned long pos;
88
89 pos = dr->reg_width - (in_pos + 1);
90
91#ifdef DEBUG
92 pr_info("write_bit addr = %lx, value = %ld, pos = %ld, "
93 "r_width = %ld\n",
94 dr->reg, !!value, pos, dr->reg_width);
95#endif
96
97 if (value)
98 set_bit(pos, &dr->reg_shadow);
99 else
100 clear_bit(pos, &dr->reg_shadow);
101
102 gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow);
103}
104
49static int gpio_read_reg(unsigned long reg, unsigned long reg_width, 105static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
50 unsigned long field_width, unsigned long in_pos) 106 unsigned long field_width, unsigned long in_pos)
51{ 107{
@@ -61,18 +117,7 @@ static int gpio_read_reg(unsigned long reg, unsigned long reg_width,
61 reg, pos, reg_width, field_width); 117 reg, pos, reg_width, field_width);
62#endif 118#endif
63 119
64 switch (reg_width) { 120 data = gpio_read_raw_reg(reg, reg_width);
65 case 8:
66 data = ctrl_inb(reg);
67 break;
68 case 16:
69 data = ctrl_inw(reg);
70 break;
71 case 32:
72 data = ctrl_inl(reg);
73 break;
74 }
75
76 return (data >> pos) & mask; 121 return (data >> pos) & mask;
77} 122}
78 123
@@ -140,6 +185,26 @@ static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio)
140 return -1; 185 return -1;
141} 186}
142 187
188static void setup_data_regs(struct pinmux_info *gpioc)
189{
190 struct pinmux_data_reg *drp;
191 int k;
192
193 for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++)
194 setup_data_reg(gpioc, k);
195
196 k = 0;
197 while (1) {
198 drp = gpioc->data_regs + k;
199
200 if (!drp->reg_width)
201 break;
202
203 drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width);
204 k++;
205 }
206}
207
143static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, 208static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio,
144 struct pinmux_data_reg **drp, int *bitp) 209 struct pinmux_data_reg **drp, int *bitp)
145{ 210{
@@ -465,7 +530,7 @@ static void __gpio_set_value(struct pinmux_info *gpioc,
465 if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) 530 if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0)
466 BUG(); 531 BUG();
467 else 532 else
468 gpio_write_reg(dr->reg, dr->reg_width, 1, bit, !!value); 533 gpio_write_bit(dr, bit, value);
469} 534}
470 535
471int gpio_direction_output(unsigned gpio, int value) 536int gpio_direction_output(unsigned gpio, int value)
@@ -474,8 +539,8 @@ int gpio_direction_output(unsigned gpio, int value)
474 unsigned long flags; 539 unsigned long flags;
475 int ret; 540 int ret;
476 541
477 spin_lock_irqsave(&gpio_lock, flags);
478 __gpio_set_value(gpioc, gpio, value); 542 __gpio_set_value(gpioc, gpio, value);
543 spin_lock_irqsave(&gpio_lock, flags);
479 ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT); 544 ret = pinmux_direction(gpioc, gpio, PINMUX_TYPE_OUTPUT);
480 spin_unlock_irqrestore(&gpio_lock, flags); 545 spin_unlock_irqrestore(&gpio_lock, flags);
481 546
@@ -504,25 +569,16 @@ EXPORT_SYMBOL(gpio_get_value);
504 569
505void gpio_set_value(unsigned gpio, int value) 570void gpio_set_value(unsigned gpio, int value)
506{ 571{
507 struct pinmux_info *gpioc = gpio_controller(gpio); 572 __gpio_set_value(gpio_controller(gpio), gpio, value);
508 unsigned long flags;
509
510 spin_lock_irqsave(&gpio_lock, flags);
511 __gpio_set_value(gpioc, gpio, value);
512 spin_unlock_irqrestore(&gpio_lock, flags);
513} 573}
514EXPORT_SYMBOL(gpio_set_value); 574EXPORT_SYMBOL(gpio_set_value);
515 575
516int register_pinmux(struct pinmux_info *pip) 576int register_pinmux(struct pinmux_info *pip)
517{ 577{
518 int k;
519
520 registered_gpio = pip; 578 registered_gpio = pip;
579 setup_data_regs(pip);
521 pr_info("pinmux: %s handling gpio %d -> %d\n", 580 pr_info("pinmux: %s handling gpio %d -> %d\n",
522 pip->name, pip->first_gpio, pip->last_gpio); 581 pip->name, pip->first_gpio, pip->last_gpio);
523 582
524 for (k = pip->first_gpio; k <= pip->last_gpio; k++)
525 setup_data_reg(pip, k);
526
527 return 0; 583 return 0;
528} 584}