aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2015-03-22 18:52:48 -0400
committerFelipe Balbi <balbi@ti.com>2015-05-26 11:42:28 -0400
commite842b84c8e7221c45c8dbd7de09185c6149e1cf9 (patch)
tree62fc475e5eccfdcdb3210da3b8d48c0cac68cbc5
parent11bece5e063ca567e631c6ea3b1611c10dbc3282 (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.c97
-rw-r--r--include/linux/usb/phy.h2
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);
22static LIST_HEAD(phy_bind_list); 22static LIST_HEAD(phy_bind_list);
23static DEFINE_SPINLOCK(phy_lock); 23static DEFINE_SPINLOCK(phy_lock);
24 24
25struct phy_devm {
26 struct usb_phy *phy;
27 struct notifier_block *nb;
28};
29
25static struct usb_phy *__usb_find_phy(struct list_head *list, 30static 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
87static 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
82static int devm_usb_phy_match(struct device *dev, void *res, void *match_data) 96static 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:
153EXPORT_SYMBOL_GPL(usb_get_phy); 167EXPORT_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 */
170struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, 185struct 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
217err0: 223err0:
218 of_node_put(node);
219 224
220 return phy; 225 return phy;
221} 226}
227EXPORT_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 */
244struct 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}
222EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); 265EXPORT_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);
205extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); 205extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index);
206extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, 206extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
207 const char *phandle, u8 index); 207 const char *phandle, u8 index);
208extern struct usb_phy *devm_usb_get_phy_by_node(struct device *dev,
209 struct device_node *node, struct notifier_block *nb);
208extern void usb_put_phy(struct usb_phy *); 210extern void usb_put_phy(struct usb_phy *);
209extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); 211extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);
210extern int usb_bind_phy(const char *dev_name, u8 index, 212extern int usb_bind_phy(const char *dev_name, u8 index,