diff options
author | NeilBrown <neilb@suse.de> | 2015-03-22 18:52:48 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2015-05-26 11:42:28 -0400 |
commit | e842b84c8e7221c45c8dbd7de09185c6149e1cf9 (patch) | |
tree | 62fc475e5eccfdcdb3210da3b8d48c0cac68cbc5 | |
parent | 11bece5e063ca567e631c6ea3b1611c10dbc3282 (diff) |
usb: phy: Add interface to get phy give of device_node.
Split the "get phy from device_node" functionality out of
"get phy by phandle" so it can be used directly.
This is useful when a battery-charger is intimately associated with a
particular phy but handled by a separate driver. The charger
can find the device_node based on sibling relationships
without the need for a redundant declaration in the devicetree
description.
As a peripheral that gets a phy will often want to register a
notifier block, and de-register it later, that functionality
is included so the de-registration is automatic.
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/phy/phy.c | 97 | ||||
-rw-r--r-- | include/linux/usb/phy.h | 2 |
2 files changed, 72 insertions, 27 deletions
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index d1cd6b50f520..98f75d2842b7 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c | |||
@@ -22,6 +22,11 @@ static LIST_HEAD(phy_list); | |||
22 | static LIST_HEAD(phy_bind_list); | 22 | static LIST_HEAD(phy_bind_list); |
23 | static DEFINE_SPINLOCK(phy_lock); | 23 | static DEFINE_SPINLOCK(phy_lock); |
24 | 24 | ||
25 | struct phy_devm { | ||
26 | struct usb_phy *phy; | ||
27 | struct notifier_block *nb; | ||
28 | }; | ||
29 | |||
25 | static struct usb_phy *__usb_find_phy(struct list_head *list, | 30 | static struct usb_phy *__usb_find_phy(struct list_head *list, |
26 | enum usb_phy_type type) | 31 | enum usb_phy_type type) |
27 | { | 32 | { |
@@ -79,6 +84,15 @@ static void devm_usb_phy_release(struct device *dev, void *res) | |||
79 | usb_put_phy(phy); | 84 | usb_put_phy(phy); |
80 | } | 85 | } |
81 | 86 | ||
87 | static void devm_usb_phy_release2(struct device *dev, void *_res) | ||
88 | { | ||
89 | struct phy_devm *res = _res; | ||
90 | |||
91 | if (res->nb) | ||
92 | usb_unregister_notifier(res->phy, res->nb); | ||
93 | usb_put_phy(res->phy); | ||
94 | } | ||
95 | |||
82 | static int devm_usb_phy_match(struct device *dev, void *res, void *match_data) | 96 | static int devm_usb_phy_match(struct device *dev, void *res, void *match_data) |
83 | { | 97 | { |
84 | struct usb_phy **phy = res; | 98 | struct usb_phy **phy = res; |
@@ -153,40 +167,30 @@ err0: | |||
153 | EXPORT_SYMBOL_GPL(usb_get_phy); | 167 | EXPORT_SYMBOL_GPL(usb_get_phy); |
154 | 168 | ||
155 | /** | 169 | /** |
156 | * devm_usb_get_phy_by_phandle - find the USB PHY by phandle | 170 | * devm_usb_get_phy_by_node - find the USB PHY by device_node |
157 | * @dev - device that requests this phy | 171 | * @dev - device that requests this phy |
158 | * @phandle - name of the property holding the phy phandle value | 172 | * @node - the device_node for the phy device. |
159 | * @index - the index of the phy | 173 | * @nb - a notifier_block to register with the phy. |
160 | * | 174 | * |
161 | * Returns the phy driver associated with the given phandle value, | 175 | * Returns the phy driver associated with the given device_node, |
162 | * after getting a refcount to it, -ENODEV if there is no such phy or | 176 | * after getting a refcount to it, -ENODEV if there is no such phy or |
163 | * -EPROBE_DEFER if there is a phandle to the phy, but the device is | 177 | * -EPROBE_DEFER if the device is not yet loaded. While at that, it |
164 | * not yet loaded. While at that, it also associates the device with | 178 | * also associates the device with |
165 | * the phy using devres. On driver detach, release function is invoked | 179 | * the phy using devres. On driver detach, release function is invoked |
166 | * on the devres data, then, devres data is freed. | 180 | * on the devres data, then, devres data is freed. |
167 | * | 181 | * |
168 | * For use by USB host and peripheral drivers. | 182 | * For use by peripheral drivers for devices related to a phy, |
183 | * such as a charger. | ||
169 | */ | 184 | */ |
170 | struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | 185 | struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, |
171 | const char *phandle, u8 index) | 186 | struct device_node *node, |
187 | struct notifier_block *nb) | ||
172 | { | 188 | { |
173 | struct usb_phy *phy = ERR_PTR(-ENOMEM), **ptr; | 189 | struct usb_phy *phy = ERR_PTR(-ENOMEM); |
190 | struct phy_devm *ptr; | ||
174 | unsigned long flags; | 191 | unsigned long flags; |
175 | struct device_node *node; | ||
176 | 192 | ||
177 | if (!dev->of_node) { | 193 | ptr = devres_alloc(devm_usb_phy_release2, sizeof(*ptr), GFP_KERNEL); |
178 | dev_dbg(dev, "device does not have a device node entry\n"); | ||
179 | return ERR_PTR(-EINVAL); | ||
180 | } | ||
181 | |||
182 | node = of_parse_phandle(dev->of_node, phandle, index); | ||
183 | if (!node) { | ||
184 | dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, | ||
185 | dev->of_node->full_name); | ||
186 | return ERR_PTR(-ENODEV); | ||
187 | } | ||
188 | |||
189 | ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); | ||
190 | if (!ptr) { | 194 | if (!ptr) { |
191 | dev_dbg(dev, "failed to allocate memory for devres\n"); | 195 | dev_dbg(dev, "failed to allocate memory for devres\n"); |
192 | goto err0; | 196 | goto err0; |
@@ -205,8 +209,10 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | |||
205 | devres_free(ptr); | 209 | devres_free(ptr); |
206 | goto err1; | 210 | goto err1; |
207 | } | 211 | } |
208 | 212 | if (nb) | |
209 | *ptr = phy; | 213 | usb_register_notifier(phy, nb); |
214 | ptr->phy = phy; | ||
215 | ptr->nb = nb; | ||
210 | devres_add(dev, ptr); | 216 | devres_add(dev, ptr); |
211 | 217 | ||
212 | get_device(phy->dev); | 218 | get_device(phy->dev); |
@@ -215,10 +221,47 @@ err1: | |||
215 | spin_unlock_irqrestore(&phy_lock, flags); | 221 | spin_unlock_irqrestore(&phy_lock, flags); |
216 | 222 | ||
217 | err0: | 223 | err0: |
218 | of_node_put(node); | ||
219 | 224 | ||
220 | return phy; | 225 | return phy; |
221 | } | 226 | } |
227 | EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_node); | ||
228 | |||
229 | /** | ||
230 | * devm_usb_get_phy_by_phandle - find the USB PHY by phandle | ||
231 | * @dev - device that requests this phy | ||
232 | * @phandle - name of the property holding the phy phandle value | ||
233 | * @index - the index of the phy | ||
234 | * | ||
235 | * Returns the phy driver associated with the given phandle value, | ||
236 | * after getting a refcount to it, -ENODEV if there is no such phy or | ||
237 | * -EPROBE_DEFER if there is a phandle to the phy, but the device is | ||
238 | * not yet loaded. While at that, it also associates the device with | ||
239 | * the phy using devres. On driver detach, release function is invoked | ||
240 | * on the devres data, then, devres data is freed. | ||
241 | * | ||
242 | * For use by USB host and peripheral drivers. | ||
243 | */ | ||
244 | struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | ||
245 | const char *phandle, u8 index) | ||
246 | { | ||
247 | struct device_node *node; | ||
248 | struct usb_phy *phy; | ||
249 | |||
250 | if (!dev->of_node) { | ||
251 | dev_dbg(dev, "device does not have a device node entry\n"); | ||
252 | return ERR_PTR(-EINVAL); | ||
253 | } | ||
254 | |||
255 | node = of_parse_phandle(dev->of_node, phandle, index); | ||
256 | if (!node) { | ||
257 | dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, | ||
258 | dev->of_node->full_name); | ||
259 | return ERR_PTR(-ENODEV); | ||
260 | } | ||
261 | phy = devm_usb_get_phy_by_node(dev, node, NULL); | ||
262 | of_node_put(node); | ||
263 | return phy; | ||
264 | } | ||
222 | EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); | 265 | EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); |
223 | 266 | ||
224 | /** | 267 | /** |
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index bc91b5d380fd..8ed1e29ef329 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h | |||
@@ -205,6 +205,8 @@ extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); | |||
205 | extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); | 205 | extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); |
206 | extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | 206 | extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, |
207 | const char *phandle, u8 index); | 207 | const char *phandle, u8 index); |
208 | extern struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, | ||
209 | struct device_node *node, struct notifier_block *nb); | ||
208 | extern void usb_put_phy(struct usb_phy *); | 210 | extern void usb_put_phy(struct usb_phy *); |
209 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); | 211 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); |
210 | extern int usb_bind_phy(const char *dev_name, u8 index, | 212 | extern int usb_bind_phy(const char *dev_name, u8 index, |