diff options
author | Mathias Nyman <mathias.nyman@linux.intel.com> | 2012-10-24 10:25:27 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-10-26 03:18:55 -0400 |
commit | 80b0a6029272247f19146bf8f88e5d4bba94cba5 (patch) | |
tree | 40cb6244bd1efb5e8e351952cf15e36d06801491 | |
parent | d6a2fa0424aefe97289aa561444ec3ae09bdbba0 (diff) |
gpiolib: add gpio get direction callback support
Add .get_direction callback to gpio_chip. This allows gpiolib
to check the current direction of a gpio.
Used to show the correct gpio direction in sysfs and debug entries.
If callback is not set then gpiolib will work as previously;
e.g. guessing everything is input until a direction is set.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/gpio/gpiolib.c | 38 | ||||
-rw-r--r-- | include/asm-generic/gpio.h | 5 |
2 files changed, 41 insertions, 2 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d5f9742d9ac1..e468eed261c5 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -191,6 +191,32 @@ err: | |||
191 | return ret; | 191 | return ret; |
192 | } | 192 | } |
193 | 193 | ||
194 | /* caller ensures gpio is valid and requested, chip->get_direction may sleep */ | ||
195 | static int gpio_get_direction(unsigned gpio) | ||
196 | { | ||
197 | struct gpio_chip *chip; | ||
198 | struct gpio_desc *desc = &gpio_desc[gpio]; | ||
199 | int status = -EINVAL; | ||
200 | |||
201 | chip = gpio_to_chip(gpio); | ||
202 | gpio -= chip->base; | ||
203 | |||
204 | if (!chip->get_direction) | ||
205 | return status; | ||
206 | |||
207 | status = chip->get_direction(chip, gpio); | ||
208 | if (status > 0) { | ||
209 | /* GPIOF_DIR_IN, or other positive */ | ||
210 | status = 1; | ||
211 | clear_bit(FLAG_IS_OUT, &desc->flags); | ||
212 | } | ||
213 | if (status == 0) { | ||
214 | /* GPIOF_DIR_OUT */ | ||
215 | set_bit(FLAG_IS_OUT, &desc->flags); | ||
216 | } | ||
217 | return status; | ||
218 | } | ||
219 | |||
194 | #ifdef CONFIG_GPIO_SYSFS | 220 | #ifdef CONFIG_GPIO_SYSFS |
195 | 221 | ||
196 | /* lock protects against unexport_gpio() being called while | 222 | /* lock protects against unexport_gpio() being called while |
@@ -223,6 +249,7 @@ static ssize_t gpio_direction_show(struct device *dev, | |||
223 | struct device_attribute *attr, char *buf) | 249 | struct device_attribute *attr, char *buf) |
224 | { | 250 | { |
225 | const struct gpio_desc *desc = dev_get_drvdata(dev); | 251 | const struct gpio_desc *desc = dev_get_drvdata(dev); |
252 | unsigned gpio = desc - gpio_desc; | ||
226 | ssize_t status; | 253 | ssize_t status; |
227 | 254 | ||
228 | mutex_lock(&sysfs_lock); | 255 | mutex_lock(&sysfs_lock); |
@@ -230,6 +257,7 @@ static ssize_t gpio_direction_show(struct device *dev, | |||
230 | if (!test_bit(FLAG_EXPORT, &desc->flags)) | 257 | if (!test_bit(FLAG_EXPORT, &desc->flags)) |
231 | status = -EIO; | 258 | status = -EIO; |
232 | else | 259 | else |
260 | gpio_get_direction(gpio); | ||
233 | status = sprintf(buf, "%s\n", | 261 | status = sprintf(buf, "%s\n", |
234 | test_bit(FLAG_IS_OUT, &desc->flags) | 262 | test_bit(FLAG_IS_OUT, &desc->flags) |
235 | ? "out" : "in"); | 263 | ? "out" : "in"); |
@@ -1080,6 +1108,7 @@ int gpiochip_add(struct gpio_chip *chip) | |||
1080 | * inputs (often with pullups enabled) so power | 1108 | * inputs (often with pullups enabled) so power |
1081 | * usage is minimized. Linux code should set the | 1109 | * usage is minimized. Linux code should set the |
1082 | * gpio direction first thing; but until it does, | 1110 | * gpio direction first thing; but until it does, |
1111 | * and in case chip->get_direction is not set, | ||
1083 | * we may expose the wrong direction in sysfs. | 1112 | * we may expose the wrong direction in sysfs. |
1084 | */ | 1113 | */ |
1085 | gpio_desc[id].flags = !chip->direction_input | 1114 | gpio_desc[id].flags = !chip->direction_input |
@@ -1231,9 +1260,15 @@ int gpio_request(unsigned gpio, const char *label) | |||
1231 | desc_set_label(desc, NULL); | 1260 | desc_set_label(desc, NULL); |
1232 | module_put(chip->owner); | 1261 | module_put(chip->owner); |
1233 | clear_bit(FLAG_REQUESTED, &desc->flags); | 1262 | clear_bit(FLAG_REQUESTED, &desc->flags); |
1263 | goto done; | ||
1234 | } | 1264 | } |
1235 | } | 1265 | } |
1236 | 1266 | if (chip->get_direction) { | |
1267 | /* chip->get_direction may sleep */ | ||
1268 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
1269 | gpio_get_direction(gpio); | ||
1270 | spin_lock_irqsave(&gpio_lock, flags); | ||
1271 | } | ||
1237 | done: | 1272 | done: |
1238 | if (status) | 1273 | if (status) |
1239 | pr_debug("gpio_request: gpio-%d (%s) status %d\n", | 1274 | pr_debug("gpio_request: gpio-%d (%s) status %d\n", |
@@ -1769,6 +1804,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |||
1769 | if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) | 1804 | if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) |
1770 | continue; | 1805 | continue; |
1771 | 1806 | ||
1807 | gpio_get_direction(gpio); | ||
1772 | is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); | 1808 | is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); |
1773 | seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", | 1809 | seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", |
1774 | gpio, gdesc->label, | 1810 | gpio, gdesc->label, |
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a9432fc6b8ba..eb70ca295971 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h | |||
@@ -56,6 +56,8 @@ struct device_node; | |||
56 | * enabling module power and clock; may sleep | 56 | * enabling module power and clock; may sleep |
57 | * @free: optional hook for chip-specific deactivation, such as | 57 | * @free: optional hook for chip-specific deactivation, such as |
58 | * disabling module power and clock; may sleep | 58 | * disabling module power and clock; may sleep |
59 | * @get_direction: returns direction for signal "offset", 0=out, 1=in, | ||
60 | * (same as GPIOF_DIR_XXX), or negative error | ||
59 | * @direction_input: configures signal "offset" as input, or returns error | 61 | * @direction_input: configures signal "offset" as input, or returns error |
60 | * @get: returns value for signal "offset"; for output signals this | 62 | * @get: returns value for signal "offset"; for output signals this |
61 | * returns either the value actually sensed, or zero | 63 | * returns either the value actually sensed, or zero |
@@ -100,7 +102,8 @@ struct gpio_chip { | |||
100 | unsigned offset); | 102 | unsigned offset); |
101 | void (*free)(struct gpio_chip *chip, | 103 | void (*free)(struct gpio_chip *chip, |
102 | unsigned offset); | 104 | unsigned offset); |
103 | 105 | int (*get_direction)(struct gpio_chip *chip, | |
106 | unsigned offset); | ||
104 | int (*direction_input)(struct gpio_chip *chip, | 107 | int (*direction_input)(struct gpio_chip *chip, |
105 | unsigned offset); | 108 | unsigned offset); |
106 | int (*get)(struct gpio_chip *chip, | 109 | int (*get)(struct gpio_chip *chip, |