diff options
author | Stephen Warren <swarren@nvidia.com> | 2012-03-02 15:05:46 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-03-05 05:21:46 -0500 |
commit | 0e3db173e2b9fd3b82246516e72c17763eb5f98d (patch) | |
tree | ce00c29c56332c925766f7f793d388b9670d802f | |
parent | 7ecdb16fe63e5b356335ebdc236adfb48cef31e1 (diff) |
pinctrl: add usecount to pins for muxing
Multiple mapping table entries could reference the same pin, and hence
"own" it. This would be unusual now that pinctrl_get() represents a single
state for a client device, but in the future when it represents all known
states for a device, this is quite likely. Implement reference counting
for pin ownership to handle this.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/pinctrl/core.h | 10 | ||||
-rw-r--r-- | drivers/pinctrl/pinmux.c | 23 |
2 files changed, 28 insertions, 5 deletions
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 5f258b793400..0bc52ecaf710 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h | |||
@@ -82,7 +82,14 @@ struct pinctrl_setting { | |||
82 | * @name: a name for the pin, e.g. the name of the pin/pad/finger on a | 82 | * @name: a name for the pin, e.g. the name of the pin/pad/finger on a |
83 | * datasheet or such | 83 | * datasheet or such |
84 | * @dynamic_name: if the name of this pin was dynamically allocated | 84 | * @dynamic_name: if the name of this pin was dynamically allocated |
85 | * @owner: the device holding this pin or NULL of no device has claimed it | 85 | * @usecount: If zero, the pin is not claimed, and @owner should be NULL. |
86 | * If non-zero, this pin is claimed by @owner. This field is an integer | ||
87 | * rather than a boolean, since pinctrl_get() might process multiple | ||
88 | * mapping table entries that refer to, and hence claim, the same group | ||
89 | * or pin, and each of these will increment the @usecount. | ||
90 | * @owner: The name of the entity owning the pin. Typically, this is the name | ||
91 | * of the device that called pinctrl_get(). Alternatively, it may be the | ||
92 | * name of the GPIO passed to pinctrl_request_gpio(). | ||
86 | */ | 93 | */ |
87 | struct pin_desc { | 94 | struct pin_desc { |
88 | struct pinctrl_dev *pctldev; | 95 | struct pinctrl_dev *pctldev; |
@@ -90,6 +97,7 @@ struct pin_desc { | |||
90 | bool dynamic_name; | 97 | bool dynamic_name; |
91 | /* These fields only added when supporting pinmux drivers */ | 98 | /* These fields only added when supporting pinmux drivers */ |
92 | #ifdef CONFIG_PINMUX | 99 | #ifdef CONFIG_PINMUX |
100 | unsigned usecount; | ||
93 | const char *owner; | 101 | const char *owner; |
94 | #endif | 102 | #endif |
95 | }; | 103 | }; |
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index f0fb98d252e8..56ca42e6a6ec 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c | |||
@@ -83,11 +83,16 @@ static int pin_request(struct pinctrl_dev *pctldev, | |||
83 | goto out; | 83 | goto out; |
84 | } | 84 | } |
85 | 85 | ||
86 | if (desc->owner && strcmp(desc->owner, owner)) { | 86 | if (desc->usecount && strcmp(desc->owner, owner)) { |
87 | dev_err(pctldev->dev, | 87 | dev_err(pctldev->dev, |
88 | "pin already requested\n"); | 88 | "pin already requested\n"); |
89 | goto out; | 89 | goto out; |
90 | } | 90 | } |
91 | |||
92 | desc->usecount++; | ||
93 | if (desc->usecount > 1) | ||
94 | return 0; | ||
95 | |||
91 | desc->owner = owner; | 96 | desc->owner = owner; |
92 | 97 | ||
93 | /* Let each pin increase references to this module */ | 98 | /* Let each pin increase references to this module */ |
@@ -111,12 +116,18 @@ static int pin_request(struct pinctrl_dev *pctldev, | |||
111 | else | 116 | else |
112 | status = 0; | 117 | status = 0; |
113 | 118 | ||
114 | if (status) | 119 | if (status) { |
115 | dev_err(pctldev->dev, "->request on device %s failed for pin %d\n", | 120 | dev_err(pctldev->dev, "->request on device %s failed for pin %d\n", |
116 | pctldev->desc->name, pin); | 121 | pctldev->desc->name, pin); |
122 | module_put(pctldev->owner); | ||
123 | } | ||
124 | |||
117 | out_free_pin: | 125 | out_free_pin: |
118 | if (status) | 126 | if (status) { |
119 | desc->owner = NULL; | 127 | desc->usecount--; |
128 | if (!desc->usecount) | ||
129 | desc->owner = NULL; | ||
130 | } | ||
120 | out: | 131 | out: |
121 | if (status) | 132 | if (status) |
122 | dev_err(pctldev->dev, "pin-%d (%s) status %d\n", | 133 | dev_err(pctldev->dev, "pin-%d (%s) status %d\n", |
@@ -150,6 +161,10 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin, | |||
150 | return NULL; | 161 | return NULL; |
151 | } | 162 | } |
152 | 163 | ||
164 | desc->usecount--; | ||
165 | if (desc->usecount) | ||
166 | return NULL; | ||
167 | |||
153 | /* | 168 | /* |
154 | * If there is no kind of request function for the pin we just assume | 169 | * If there is no kind of request function for the pin we just assume |
155 | * we got it by default and proceed. | 170 | * we got it by default and proceed. |