diff options
author | Magnus Damm <damm@igel.co.jp> | 2008-12-25 04:17:09 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-01-27 00:49:09 -0500 |
commit | 18801be7f805b891876a6676ec7fac2e1acdec13 (patch) | |
tree | 71b4366a89ac25980dc16bc1b33fbc6943f1155c /arch/sh | |
parent | 5376071069ec8a7e6a8112beab16fc24f5139475 (diff) |
sh: make gpio_get/set_value() O(1)
This patch modifies the table based SuperH gpio implementation to
make use of direct table lookups. With this change the functions
gpio_get_value() and gpio_set_value() are O(1).
Tested on Migo-R using bitbanging mmc. Performance is improved from
11 KBytes/s to 26 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')
-rw-r--r-- | arch/sh/include/asm/gpio.h | 7 | ||||
-rw-r--r-- | arch/sh/kernel/gpio.c | 48 |
2 files changed, 43 insertions, 12 deletions
diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h index 90673658eb14..942fefa61c7e 100644 --- a/arch/sh/include/asm/gpio.h +++ b/arch/sh/include/asm/gpio.h | |||
@@ -20,7 +20,7 @@ | |||
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | typedef unsigned short pinmux_enum_t; | 22 | typedef unsigned short pinmux_enum_t; |
23 | typedef unsigned char pinmux_flag_t; | 23 | typedef unsigned short pinmux_flag_t; |
24 | 24 | ||
25 | #define PINMUX_TYPE_NONE 0 | 25 | #define PINMUX_TYPE_NONE 0 |
26 | #define PINMUX_TYPE_FUNCTION 1 | 26 | #define PINMUX_TYPE_FUNCTION 1 |
@@ -34,6 +34,11 @@ typedef unsigned char pinmux_flag_t; | |||
34 | #define PINMUX_FLAG_WANT_PULLUP (1 << 3) | 34 | #define PINMUX_FLAG_WANT_PULLUP (1 << 3) |
35 | #define PINMUX_FLAG_WANT_PULLDOWN (1 << 4) | 35 | #define PINMUX_FLAG_WANT_PULLDOWN (1 << 4) |
36 | 36 | ||
37 | #define PINMUX_FLAG_DBIT_SHIFT 5 | ||
38 | #define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT) | ||
39 | #define PINMUX_FLAG_DREG_SHIFT 10 | ||
40 | #define PINMUX_FLAG_DREG (0x3f << PINMUX_FLAG_DREG_SHIFT) | ||
41 | |||
37 | struct pinmux_gpio { | 42 | struct pinmux_gpio { |
38 | pinmux_enum_t enum_id; | 43 | pinmux_enum_t enum_id; |
39 | pinmux_flag_t flags; | 44 | pinmux_flag_t flags; |
diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c index d37165361034..fe92ba151b89 100644 --- a/arch/sh/kernel/gpio.c +++ b/arch/sh/kernel/gpio.c | |||
@@ -95,14 +95,13 @@ static int read_write_reg(unsigned long reg, unsigned long reg_width, | |||
95 | return 0; | 95 | return 0; |
96 | } | 96 | } |
97 | 97 | ||
98 | static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | 98 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) |
99 | struct pinmux_data_reg **drp, int *bitp) | ||
100 | { | 99 | { |
101 | pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; | 100 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; |
102 | struct pinmux_data_reg *data_reg; | 101 | struct pinmux_data_reg *data_reg; |
103 | int k, n; | 102 | int k, n; |
104 | 103 | ||
105 | if (!enum_in_range(enum_id, &gpioc->data)) | 104 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) |
106 | return -1; | 105 | return -1; |
107 | 106 | ||
108 | k = 0; | 107 | k = 0; |
@@ -113,19 +112,38 @@ static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | |||
113 | break; | 112 | break; |
114 | 113 | ||
115 | for (n = 0; n < data_reg->reg_width; n++) { | 114 | for (n = 0; n < data_reg->reg_width; n++) { |
116 | if (data_reg->enum_ids[n] == enum_id) { | 115 | if (data_reg->enum_ids[n] == gpiop->enum_id) { |
117 | *drp = data_reg; | 116 | gpiop->flags &= ~PINMUX_FLAG_DREG; |
118 | *bitp = n; | 117 | gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT); |
118 | gpiop->flags &= ~PINMUX_FLAG_DBIT; | ||
119 | gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT); | ||
119 | return 0; | 120 | return 0; |
120 | |||
121 | } | 121 | } |
122 | } | 122 | } |
123 | k++; | 123 | k++; |
124 | } | 124 | } |
125 | 125 | ||
126 | BUG(); | ||
127 | |||
126 | return -1; | 128 | return -1; |
127 | } | 129 | } |
128 | 130 | ||
131 | static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | ||
132 | struct pinmux_data_reg **drp, int *bitp) | ||
133 | { | ||
134 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | ||
135 | int k, n; | ||
136 | |||
137 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | ||
138 | return -1; | ||
139 | |||
140 | k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT; | ||
141 | n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT; | ||
142 | *drp = gpioc->data_regs + k; | ||
143 | *bitp = n; | ||
144 | return 0; | ||
145 | } | ||
146 | |||
129 | static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | 147 | static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, |
130 | struct pinmux_cfg_reg **crp, int *indexp, | 148 | struct pinmux_cfg_reg **crp, int *indexp, |
131 | unsigned long **cntp) | 149 | unsigned long **cntp) |
@@ -341,7 +359,8 @@ int __gpio_request(unsigned gpio) | |||
341 | BUG(); | 359 | BUG(); |
342 | } | 360 | } |
343 | 361 | ||
344 | gpioc->gpios[gpio].flags = pinmux_type; | 362 | gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; |
363 | gpioc->gpios[gpio].flags |= pinmux_type; | ||
345 | 364 | ||
346 | ret = 0; | 365 | ret = 0; |
347 | err_unlock: | 366 | err_unlock: |
@@ -364,7 +383,8 @@ void gpio_free(unsigned gpio) | |||
364 | 383 | ||
365 | pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; | 384 | pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; |
366 | pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE); | 385 | pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE); |
367 | gpioc->gpios[gpio].flags = PINMUX_TYPE_NONE; | 386 | gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; |
387 | gpioc->gpios[gpio].flags |= PINMUX_TYPE_NONE; | ||
368 | 388 | ||
369 | spin_unlock_irqrestore(&gpio_lock, flags); | 389 | spin_unlock_irqrestore(&gpio_lock, flags); |
370 | } | 390 | } |
@@ -401,7 +421,8 @@ static int pinmux_direction(struct pinmux_info *gpioc, | |||
401 | GPIO_CFG_REQ) != 0) | 421 | GPIO_CFG_REQ) != 0) |
402 | BUG(); | 422 | BUG(); |
403 | 423 | ||
404 | gpioc->gpios[gpio].flags = new_pinmux_type; | 424 | gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; |
425 | gpioc->gpios[gpio].flags |= new_pinmux_type; | ||
405 | 426 | ||
406 | ret = 0; | 427 | ret = 0; |
407 | err_out: | 428 | err_out: |
@@ -494,9 +515,14 @@ EXPORT_SYMBOL(gpio_set_value); | |||
494 | 515 | ||
495 | int register_pinmux(struct pinmux_info *pip) | 516 | int register_pinmux(struct pinmux_info *pip) |
496 | { | 517 | { |
518 | int k; | ||
519 | |||
497 | registered_gpio = pip; | 520 | registered_gpio = pip; |
498 | pr_info("pinmux: %s handling gpio %d -> %d\n", | 521 | pr_info("pinmux: %s handling gpio %d -> %d\n", |
499 | pip->name, pip->first_gpio, pip->last_gpio); | 522 | pip->name, pip->first_gpio, pip->last_gpio); |
500 | 523 | ||
524 | for (k = pip->first_gpio; k <= pip->last_gpio; k++) | ||
525 | setup_data_reg(pip, k); | ||
526 | |||
501 | return 0; | 527 | return 0; |
502 | } | 528 | } |