1cedf8602SSascha Hauer /* 2cedf8602SSascha Hauer * phy.c -- USB phy handling 3cedf8602SSascha Hauer * 4cedf8602SSascha Hauer * Copyright (C) 2004-2013 Texas Instruments 5cedf8602SSascha Hauer * 6cedf8602SSascha Hauer * This program is free software; you can redistribute it and/or modify 7cedf8602SSascha Hauer * it under the terms of the GNU General Public License as published by 8cedf8602SSascha Hauer * the Free Software Foundation; either version 2 of the License, or 9cedf8602SSascha Hauer * (at your option) any later version. 10cedf8602SSascha Hauer */ 11cedf8602SSascha Hauer #include <linux/kernel.h> 12cedf8602SSascha Hauer #include <linux/export.h> 13cedf8602SSascha Hauer #include <linux/err.h> 14cedf8602SSascha Hauer #include <linux/device.h> 15cedf8602SSascha Hauer #include <linux/module.h> 16cedf8602SSascha Hauer #include <linux/slab.h> 17cedf8602SSascha Hauer #include <linux/of.h> 18cedf8602SSascha Hauer 19cedf8602SSascha Hauer #include <linux/usb/phy.h> 20cedf8602SSascha Hauer 21cedf8602SSascha Hauer static LIST_HEAD(phy_list); 22cedf8602SSascha Hauer static LIST_HEAD(phy_bind_list); 23cedf8602SSascha Hauer static DEFINE_SPINLOCK(phy_lock); 24cedf8602SSascha Hauer 25e842b84cSNeilBrown struct phy_devm { 26e842b84cSNeilBrown struct usb_phy *phy; 27e842b84cSNeilBrown struct notifier_block *nb; 28e842b84cSNeilBrown }; 29e842b84cSNeilBrown 30cedf8602SSascha Hauer static struct usb_phy *__usb_find_phy(struct list_head *list, 31cedf8602SSascha Hauer enum usb_phy_type type) 32cedf8602SSascha Hauer { 33cedf8602SSascha Hauer struct usb_phy *phy = NULL; 34cedf8602SSascha Hauer 35cedf8602SSascha Hauer list_for_each_entry(phy, list, head) { 36cedf8602SSascha Hauer if (phy->type != type) 37cedf8602SSascha Hauer continue; 38cedf8602SSascha Hauer 39cedf8602SSascha Hauer return phy; 40cedf8602SSascha Hauer } 41cedf8602SSascha Hauer 420df8fc37SHeikki Krogerus return ERR_PTR(-ENODEV); 43cedf8602SSascha Hauer } 44cedf8602SSascha Hauer 45cedf8602SSascha Hauer static struct usb_phy *__usb_find_phy_dev(struct device *dev, 46cedf8602SSascha Hauer struct list_head *list, u8 index) 47cedf8602SSascha Hauer { 48cedf8602SSascha Hauer struct usb_phy_bind *phy_bind = NULL; 49cedf8602SSascha Hauer 50cedf8602SSascha Hauer list_for_each_entry(phy_bind, list, list) { 51cedf8602SSascha Hauer if (!(strcmp(phy_bind->dev_name, dev_name(dev))) && 52cedf8602SSascha Hauer phy_bind->index == index) { 53cedf8602SSascha Hauer if (phy_bind->phy) 54cedf8602SSascha Hauer return phy_bind->phy; 55cedf8602SSascha Hauer else 56cedf8602SSascha Hauer return ERR_PTR(-EPROBE_DEFER); 57cedf8602SSascha Hauer } 58cedf8602SSascha Hauer } 59cedf8602SSascha Hauer 60cedf8602SSascha Hauer return ERR_PTR(-ENODEV); 61cedf8602SSascha Hauer } 62cedf8602SSascha Hauer 63cedf8602SSascha Hauer static struct usb_phy *__of_usb_find_phy(struct device_node *node) 64cedf8602SSascha Hauer { 65cedf8602SSascha Hauer struct usb_phy *phy; 66cedf8602SSascha Hauer 67c818a94cSThierry Reding if (!of_device_is_available(node)) 68c818a94cSThierry Reding return ERR_PTR(-ENODEV); 69c818a94cSThierry Reding 70cedf8602SSascha Hauer list_for_each_entry(phy, &phy_list, head) { 71cedf8602SSascha Hauer if (node != phy->dev->of_node) 72cedf8602SSascha Hauer continue; 73cedf8602SSascha Hauer 74cedf8602SSascha Hauer return phy; 75cedf8602SSascha Hauer } 76cedf8602SSascha Hauer 779c9d8249SMaxime Ripard return ERR_PTR(-EPROBE_DEFER); 78cedf8602SSascha Hauer } 79cedf8602SSascha Hauer 80cedf8602SSascha Hauer static void devm_usb_phy_release(struct device *dev, void *res) 81cedf8602SSascha Hauer { 82cedf8602SSascha Hauer struct usb_phy *phy = *(struct usb_phy **)res; 83cedf8602SSascha Hauer 84cedf8602SSascha Hauer usb_put_phy(phy); 85cedf8602SSascha Hauer } 86cedf8602SSascha Hauer 87e842b84cSNeilBrown static void devm_usb_phy_release2(struct device *dev, void *_res) 88e842b84cSNeilBrown { 89e842b84cSNeilBrown struct phy_devm *res = _res; 90e842b84cSNeilBrown 91e842b84cSNeilBrown if (res->nb) 92e842b84cSNeilBrown usb_unregister_notifier(res->phy, res->nb); 93e842b84cSNeilBrown usb_put_phy(res->phy); 94e842b84cSNeilBrown } 95e842b84cSNeilBrown 96cedf8602SSascha Hauer static int devm_usb_phy_match(struct device *dev, void *res, void *match_data) 97cedf8602SSascha Hauer { 98869aee0fSAxel Lin struct usb_phy **phy = res; 99869aee0fSAxel Lin 100869aee0fSAxel Lin return *phy == match_data; 101cedf8602SSascha Hauer } 102cedf8602SSascha Hauer 1037d21114dSBaolin Wang static int usb_add_extcon(struct usb_phy *x) 1047d21114dSBaolin Wang { 1057d21114dSBaolin Wang int ret; 1067d21114dSBaolin Wang 1077d21114dSBaolin Wang if (of_property_read_bool(x->dev->of_node, "extcon")) { 1087d21114dSBaolin Wang x->edev = extcon_get_edev_by_phandle(x->dev, 0); 1097d21114dSBaolin Wang if (IS_ERR(x->edev)) 1107d21114dSBaolin Wang return PTR_ERR(x->edev); 1117d21114dSBaolin Wang 1127d21114dSBaolin Wang x->id_edev = extcon_get_edev_by_phandle(x->dev, 1); 1137d21114dSBaolin Wang if (IS_ERR(x->id_edev)) { 1147d21114dSBaolin Wang x->id_edev = NULL; 1157d21114dSBaolin Wang dev_info(x->dev, "No separate ID extcon device\n"); 1167d21114dSBaolin Wang } 1177d21114dSBaolin Wang 1187d21114dSBaolin Wang if (x->vbus_nb.notifier_call) { 1197d21114dSBaolin Wang ret = devm_extcon_register_notifier(x->dev, x->edev, 1207d21114dSBaolin Wang EXTCON_USB, 1217d21114dSBaolin Wang &x->vbus_nb); 1227d21114dSBaolin Wang if (ret < 0) { 1237d21114dSBaolin Wang dev_err(x->dev, 1247d21114dSBaolin Wang "register VBUS notifier failed\n"); 1257d21114dSBaolin Wang return ret; 1267d21114dSBaolin Wang } 1277d21114dSBaolin Wang } 1287d21114dSBaolin Wang 1297d21114dSBaolin Wang if (x->id_nb.notifier_call) { 1307d21114dSBaolin Wang struct extcon_dev *id_ext; 1317d21114dSBaolin Wang 1327d21114dSBaolin Wang if (x->id_edev) 1337d21114dSBaolin Wang id_ext = x->id_edev; 1347d21114dSBaolin Wang else 1357d21114dSBaolin Wang id_ext = x->edev; 1367d21114dSBaolin Wang 1377d21114dSBaolin Wang ret = devm_extcon_register_notifier(x->dev, id_ext, 1387d21114dSBaolin Wang EXTCON_USB_HOST, 1397d21114dSBaolin Wang &x->id_nb); 1407d21114dSBaolin Wang if (ret < 0) { 1417d21114dSBaolin Wang dev_err(x->dev, 1427d21114dSBaolin Wang "register ID notifier failed\n"); 1437d21114dSBaolin Wang return ret; 1447d21114dSBaolin Wang } 1457d21114dSBaolin Wang } 1467d21114dSBaolin Wang } 1477d21114dSBaolin Wang 1487d21114dSBaolin Wang return 0; 1497d21114dSBaolin Wang } 1507d21114dSBaolin Wang 151cedf8602SSascha Hauer /** 152cedf8602SSascha Hauer * devm_usb_get_phy - find the USB PHY 153cedf8602SSascha Hauer * @dev - device that requests this phy 154cedf8602SSascha Hauer * @type - the type of the phy the controller requires 155cedf8602SSascha Hauer * 156cedf8602SSascha Hauer * Gets the phy using usb_get_phy(), and associates a device with it using 157cedf8602SSascha Hauer * devres. On driver detach, release function is invoked on the devres data, 158cedf8602SSascha Hauer * then, devres data is freed. 159cedf8602SSascha Hauer * 160cedf8602SSascha Hauer * For use by USB host and peripheral drivers. 161cedf8602SSascha Hauer */ 162cedf8602SSascha Hauer struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type) 163cedf8602SSascha Hauer { 164cedf8602SSascha Hauer struct usb_phy **ptr, *phy; 165cedf8602SSascha Hauer 166cedf8602SSascha Hauer ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); 167cedf8602SSascha Hauer if (!ptr) 1687f4d1e7bSGabor Juhos return ERR_PTR(-ENOMEM); 169cedf8602SSascha Hauer 170cedf8602SSascha Hauer phy = usb_get_phy(type); 171cedf8602SSascha Hauer if (!IS_ERR(phy)) { 172cedf8602SSascha Hauer *ptr = phy; 173cedf8602SSascha Hauer devres_add(dev, ptr); 174cedf8602SSascha Hauer } else 175cedf8602SSascha Hauer devres_free(ptr); 176cedf8602SSascha Hauer 177cedf8602SSascha Hauer return phy; 178cedf8602SSascha Hauer } 179110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(devm_usb_get_phy); 180cedf8602SSascha Hauer 181cedf8602SSascha Hauer /** 182cedf8602SSascha Hauer * usb_get_phy - find the USB PHY 183cedf8602SSascha Hauer * @type - the type of the phy the controller requires 184cedf8602SSascha Hauer * 185cedf8602SSascha Hauer * Returns the phy driver, after getting a refcount to it; or 186cedf8602SSascha Hauer * -ENODEV if there is no such phy. The caller is responsible for 187cedf8602SSascha Hauer * calling usb_put_phy() to release that count. 188cedf8602SSascha Hauer * 189cedf8602SSascha Hauer * For use by USB host and peripheral drivers. 190cedf8602SSascha Hauer */ 191cedf8602SSascha Hauer struct usb_phy *usb_get_phy(enum usb_phy_type type) 192cedf8602SSascha Hauer { 193cedf8602SSascha Hauer struct usb_phy *phy = NULL; 194cedf8602SSascha Hauer unsigned long flags; 195cedf8602SSascha Hauer 196cedf8602SSascha Hauer spin_lock_irqsave(&phy_lock, flags); 197cedf8602SSascha Hauer 198cedf8602SSascha Hauer phy = __usb_find_phy(&phy_list, type); 199cedf8602SSascha Hauer if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { 200e9d123a5SJosh Boyer pr_debug("PHY: unable to find transceiver of type %s\n", 201cedf8602SSascha Hauer usb_phy_type_string(type)); 2029dc9cb0cSMathias Krause if (!IS_ERR(phy)) 2039dc9cb0cSMathias Krause phy = ERR_PTR(-ENODEV); 2049dc9cb0cSMathias Krause 205cedf8602SSascha Hauer goto err0; 206cedf8602SSascha Hauer } 207cedf8602SSascha Hauer 208cedf8602SSascha Hauer get_device(phy->dev); 209cedf8602SSascha Hauer 210cedf8602SSascha Hauer err0: 211cedf8602SSascha Hauer spin_unlock_irqrestore(&phy_lock, flags); 212cedf8602SSascha Hauer 213cedf8602SSascha Hauer return phy; 214cedf8602SSascha Hauer } 215110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(usb_get_phy); 216cedf8602SSascha Hauer 217cedf8602SSascha Hauer /** 218e842b84cSNeilBrown * devm_usb_get_phy_by_node - find the USB PHY by device_node 219cedf8602SSascha Hauer * @dev - device that requests this phy 220e842b84cSNeilBrown * @node - the device_node for the phy device. 221e842b84cSNeilBrown * @nb - a notifier_block to register with the phy. 222cedf8602SSascha Hauer * 223e842b84cSNeilBrown * Returns the phy driver associated with the given device_node, 224cedf8602SSascha Hauer * after getting a refcount to it, -ENODEV if there is no such phy or 225e842b84cSNeilBrown * -EPROBE_DEFER if the device is not yet loaded. While at that, it 226e842b84cSNeilBrown * also associates the device with 227cedf8602SSascha Hauer * the phy using devres. On driver detach, release function is invoked 228cedf8602SSascha Hauer * on the devres data, then, devres data is freed. 229cedf8602SSascha Hauer * 230e842b84cSNeilBrown * For use by peripheral drivers for devices related to a phy, 231e842b84cSNeilBrown * such as a charger. 232cedf8602SSascha Hauer */ 233e842b84cSNeilBrown struct usb_phy *devm_usb_get_phy_by_node(struct device *dev, 234e842b84cSNeilBrown struct device_node *node, 235e842b84cSNeilBrown struct notifier_block *nb) 236cedf8602SSascha Hauer { 237e842b84cSNeilBrown struct usb_phy *phy = ERR_PTR(-ENOMEM); 238e842b84cSNeilBrown struct phy_devm *ptr; 239cedf8602SSascha Hauer unsigned long flags; 240cedf8602SSascha Hauer 241e842b84cSNeilBrown ptr = devres_alloc(devm_usb_phy_release2, sizeof(*ptr), GFP_KERNEL); 242cedf8602SSascha Hauer if (!ptr) { 243cedf8602SSascha Hauer dev_dbg(dev, "failed to allocate memory for devres\n"); 244cedf8602SSascha Hauer goto err0; 245cedf8602SSascha Hauer } 246cedf8602SSascha Hauer 247cedf8602SSascha Hauer spin_lock_irqsave(&phy_lock, flags); 248cedf8602SSascha Hauer 249cedf8602SSascha Hauer phy = __of_usb_find_phy(node); 250c818a94cSThierry Reding if (IS_ERR(phy)) { 251c818a94cSThierry Reding devres_free(ptr); 252c818a94cSThierry Reding goto err1; 253c818a94cSThierry Reding } 2541290a958SArjun Sreedharan 255c818a94cSThierry Reding if (!try_module_get(phy->dev->driver->owner)) { 256c818a94cSThierry Reding phy = ERR_PTR(-ENODEV); 257cedf8602SSascha Hauer devres_free(ptr); 258cedf8602SSascha Hauer goto err1; 259cedf8602SSascha Hauer } 260e842b84cSNeilBrown if (nb) 261e842b84cSNeilBrown usb_register_notifier(phy, nb); 262e842b84cSNeilBrown ptr->phy = phy; 263e842b84cSNeilBrown ptr->nb = nb; 264cedf8602SSascha Hauer devres_add(dev, ptr); 265cedf8602SSascha Hauer 266cedf8602SSascha Hauer get_device(phy->dev); 267cedf8602SSascha Hauer 268cedf8602SSascha Hauer err1: 269cedf8602SSascha Hauer spin_unlock_irqrestore(&phy_lock, flags); 270cedf8602SSascha Hauer 271cedf8602SSascha Hauer err0: 272cedf8602SSascha Hauer 273cedf8602SSascha Hauer return phy; 274cedf8602SSascha Hauer } 275e842b84cSNeilBrown EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_node); 276e842b84cSNeilBrown 277e842b84cSNeilBrown /** 278e842b84cSNeilBrown * devm_usb_get_phy_by_phandle - find the USB PHY by phandle 279e842b84cSNeilBrown * @dev - device that requests this phy 280e842b84cSNeilBrown * @phandle - name of the property holding the phy phandle value 281e842b84cSNeilBrown * @index - the index of the phy 282e842b84cSNeilBrown * 283e842b84cSNeilBrown * Returns the phy driver associated with the given phandle value, 284e842b84cSNeilBrown * after getting a refcount to it, -ENODEV if there is no such phy or 285e842b84cSNeilBrown * -EPROBE_DEFER if there is a phandle to the phy, but the device is 286e842b84cSNeilBrown * not yet loaded. While at that, it also associates the device with 287e842b84cSNeilBrown * the phy using devres. On driver detach, release function is invoked 288e842b84cSNeilBrown * on the devres data, then, devres data is freed. 289e842b84cSNeilBrown * 290e842b84cSNeilBrown * For use by USB host and peripheral drivers. 291e842b84cSNeilBrown */ 292e842b84cSNeilBrown struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, 293e842b84cSNeilBrown const char *phandle, u8 index) 294e842b84cSNeilBrown { 295e842b84cSNeilBrown struct device_node *node; 296e842b84cSNeilBrown struct usb_phy *phy; 297e842b84cSNeilBrown 298e842b84cSNeilBrown if (!dev->of_node) { 299e842b84cSNeilBrown dev_dbg(dev, "device does not have a device node entry\n"); 300e842b84cSNeilBrown return ERR_PTR(-EINVAL); 301e842b84cSNeilBrown } 302e842b84cSNeilBrown 303e842b84cSNeilBrown node = of_parse_phandle(dev->of_node, phandle, index); 304e842b84cSNeilBrown if (!node) { 305e842b84cSNeilBrown dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, 306e842b84cSNeilBrown dev->of_node->full_name); 307e842b84cSNeilBrown return ERR_PTR(-ENODEV); 308e842b84cSNeilBrown } 309e842b84cSNeilBrown phy = devm_usb_get_phy_by_node(dev, node, NULL); 310e842b84cSNeilBrown of_node_put(node); 311e842b84cSNeilBrown return phy; 312e842b84cSNeilBrown } 313110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); 314cedf8602SSascha Hauer 315cedf8602SSascha Hauer /** 316cedf8602SSascha Hauer * usb_get_phy_dev - find the USB PHY 317cedf8602SSascha Hauer * @dev - device that requests this phy 318cedf8602SSascha Hauer * @index - the index of the phy 319cedf8602SSascha Hauer * 320cedf8602SSascha Hauer * Returns the phy driver, after getting a refcount to it; or 321cedf8602SSascha Hauer * -ENODEV if there is no such phy. The caller is responsible for 322cedf8602SSascha Hauer * calling usb_put_phy() to release that count. 323cedf8602SSascha Hauer * 324cedf8602SSascha Hauer * For use by USB host and peripheral drivers. 325cedf8602SSascha Hauer */ 326cedf8602SSascha Hauer struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index) 327cedf8602SSascha Hauer { 328cedf8602SSascha Hauer struct usb_phy *phy = NULL; 329cedf8602SSascha Hauer unsigned long flags; 330cedf8602SSascha Hauer 331cedf8602SSascha Hauer spin_lock_irqsave(&phy_lock, flags); 332cedf8602SSascha Hauer 333cedf8602SSascha Hauer phy = __usb_find_phy_dev(dev, &phy_bind_list, index); 334cedf8602SSascha Hauer if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { 335e9d123a5SJosh Boyer dev_dbg(dev, "unable to find transceiver\n"); 3362c4e3dbfSArjun Sreedharan if (!IS_ERR(phy)) 3372c4e3dbfSArjun Sreedharan phy = ERR_PTR(-ENODEV); 3382c4e3dbfSArjun Sreedharan 339cedf8602SSascha Hauer goto err0; 340cedf8602SSascha Hauer } 341cedf8602SSascha Hauer 342cedf8602SSascha Hauer get_device(phy->dev); 343cedf8602SSascha Hauer 344cedf8602SSascha Hauer err0: 345cedf8602SSascha Hauer spin_unlock_irqrestore(&phy_lock, flags); 346cedf8602SSascha Hauer 347cedf8602SSascha Hauer return phy; 348cedf8602SSascha Hauer } 349110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(usb_get_phy_dev); 350cedf8602SSascha Hauer 351cedf8602SSascha Hauer /** 352cedf8602SSascha Hauer * devm_usb_get_phy_dev - find the USB PHY using device ptr and index 353cedf8602SSascha Hauer * @dev - device that requests this phy 354cedf8602SSascha Hauer * @index - the index of the phy 355cedf8602SSascha Hauer * 356cedf8602SSascha Hauer * Gets the phy using usb_get_phy_dev(), and associates a device with it using 357cedf8602SSascha Hauer * devres. On driver detach, release function is invoked on the devres data, 358cedf8602SSascha Hauer * then, devres data is freed. 359cedf8602SSascha Hauer * 360cedf8602SSascha Hauer * For use by USB host and peripheral drivers. 361cedf8602SSascha Hauer */ 362cedf8602SSascha Hauer struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) 363cedf8602SSascha Hauer { 364cedf8602SSascha Hauer struct usb_phy **ptr, *phy; 365cedf8602SSascha Hauer 366cedf8602SSascha Hauer ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); 367cedf8602SSascha Hauer if (!ptr) 368cedf8602SSascha Hauer return NULL; 369cedf8602SSascha Hauer 370cedf8602SSascha Hauer phy = usb_get_phy_dev(dev, index); 371cedf8602SSascha Hauer if (!IS_ERR(phy)) { 372cedf8602SSascha Hauer *ptr = phy; 373cedf8602SSascha Hauer devres_add(dev, ptr); 374cedf8602SSascha Hauer } else 375cedf8602SSascha Hauer devres_free(ptr); 376cedf8602SSascha Hauer 377cedf8602SSascha Hauer return phy; 378cedf8602SSascha Hauer } 379110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(devm_usb_get_phy_dev); 380cedf8602SSascha Hauer 381cedf8602SSascha Hauer /** 382cedf8602SSascha Hauer * devm_usb_put_phy - release the USB PHY 383cedf8602SSascha Hauer * @dev - device that wants to release this phy 384cedf8602SSascha Hauer * @phy - the phy returned by devm_usb_get_phy() 385cedf8602SSascha Hauer * 386cedf8602SSascha Hauer * destroys the devres associated with this phy and invokes usb_put_phy 387cedf8602SSascha Hauer * to release the phy. 388cedf8602SSascha Hauer * 389cedf8602SSascha Hauer * For use by USB host and peripheral drivers. 390cedf8602SSascha Hauer */ 391cedf8602SSascha Hauer void devm_usb_put_phy(struct device *dev, struct usb_phy *phy) 392cedf8602SSascha Hauer { 393cedf8602SSascha Hauer int r; 394cedf8602SSascha Hauer 395cedf8602SSascha Hauer r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy); 396cedf8602SSascha Hauer dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); 397cedf8602SSascha Hauer } 398110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(devm_usb_put_phy); 399cedf8602SSascha Hauer 400cedf8602SSascha Hauer /** 401cedf8602SSascha Hauer * usb_put_phy - release the USB PHY 402cedf8602SSascha Hauer * @x: the phy returned by usb_get_phy() 403cedf8602SSascha Hauer * 404cedf8602SSascha Hauer * Releases a refcount the caller received from usb_get_phy(). 405cedf8602SSascha Hauer * 406cedf8602SSascha Hauer * For use by USB host and peripheral drivers. 407cedf8602SSascha Hauer */ 408cedf8602SSascha Hauer void usb_put_phy(struct usb_phy *x) 409cedf8602SSascha Hauer { 410cedf8602SSascha Hauer if (x) { 411cedf8602SSascha Hauer struct module *owner = x->dev->driver->owner; 412cedf8602SSascha Hauer 413cedf8602SSascha Hauer put_device(x->dev); 414cedf8602SSascha Hauer module_put(owner); 415cedf8602SSascha Hauer } 416cedf8602SSascha Hauer } 417110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(usb_put_phy); 418cedf8602SSascha Hauer 419cedf8602SSascha Hauer /** 420cedf8602SSascha Hauer * usb_add_phy - declare the USB PHY 421cedf8602SSascha Hauer * @x: the USB phy to be used; or NULL 422cedf8602SSascha Hauer * @type - the type of this PHY 423cedf8602SSascha Hauer * 424cedf8602SSascha Hauer * This call is exclusively for use by phy drivers, which 425cedf8602SSascha Hauer * coordinate the activities of drivers for host and peripheral 426cedf8602SSascha Hauer * controllers, and in some cases for VBUS current regulation. 427cedf8602SSascha Hauer */ 428cedf8602SSascha Hauer int usb_add_phy(struct usb_phy *x, enum usb_phy_type type) 429cedf8602SSascha Hauer { 430cedf8602SSascha Hauer int ret = 0; 431cedf8602SSascha Hauer unsigned long flags; 432cedf8602SSascha Hauer struct usb_phy *phy; 433cedf8602SSascha Hauer 434cedf8602SSascha Hauer if (x->type != USB_PHY_TYPE_UNDEFINED) { 435cedf8602SSascha Hauer dev_err(x->dev, "not accepting initialized PHY %s\n", x->label); 436cedf8602SSascha Hauer return -EINVAL; 437cedf8602SSascha Hauer } 438cedf8602SSascha Hauer 4397d21114dSBaolin Wang ret = usb_add_extcon(x); 4407d21114dSBaolin Wang if (ret) 4417d21114dSBaolin Wang return ret; 4427d21114dSBaolin Wang 44331e32227SNeil Zhang ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); 44431e32227SNeil Zhang 445cedf8602SSascha Hauer spin_lock_irqsave(&phy_lock, flags); 446cedf8602SSascha Hauer 447cedf8602SSascha Hauer list_for_each_entry(phy, &phy_list, head) { 448cedf8602SSascha Hauer if (phy->type == type) { 449cedf8602SSascha Hauer ret = -EBUSY; 450cedf8602SSascha Hauer dev_err(x->dev, "transceiver type %s already exists\n", 451cedf8602SSascha Hauer usb_phy_type_string(type)); 452cedf8602SSascha Hauer goto out; 453cedf8602SSascha Hauer } 454cedf8602SSascha Hauer } 455cedf8602SSascha Hauer 456cedf8602SSascha Hauer x->type = type; 457cedf8602SSascha Hauer list_add_tail(&x->head, &phy_list); 458cedf8602SSascha Hauer 459cedf8602SSascha Hauer out: 460cedf8602SSascha Hauer spin_unlock_irqrestore(&phy_lock, flags); 461cedf8602SSascha Hauer return ret; 462cedf8602SSascha Hauer } 463110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(usb_add_phy); 464cedf8602SSascha Hauer 465cedf8602SSascha Hauer /** 466cedf8602SSascha Hauer * usb_add_phy_dev - declare the USB PHY 467cedf8602SSascha Hauer * @x: the USB phy to be used; or NULL 468cedf8602SSascha Hauer * 469cedf8602SSascha Hauer * This call is exclusively for use by phy drivers, which 470cedf8602SSascha Hauer * coordinate the activities of drivers for host and peripheral 471cedf8602SSascha Hauer * controllers, and in some cases for VBUS current regulation. 472cedf8602SSascha Hauer */ 473cedf8602SSascha Hauer int usb_add_phy_dev(struct usb_phy *x) 474cedf8602SSascha Hauer { 475cedf8602SSascha Hauer struct usb_phy_bind *phy_bind; 476cedf8602SSascha Hauer unsigned long flags; 4777d21114dSBaolin Wang int ret; 478cedf8602SSascha Hauer 479cedf8602SSascha Hauer if (!x->dev) { 480cedf8602SSascha Hauer dev_err(x->dev, "no device provided for PHY\n"); 481cedf8602SSascha Hauer return -EINVAL; 482cedf8602SSascha Hauer } 483cedf8602SSascha Hauer 4847d21114dSBaolin Wang ret = usb_add_extcon(x); 4857d21114dSBaolin Wang if (ret) 4867d21114dSBaolin Wang return ret; 4877d21114dSBaolin Wang 48831e32227SNeil Zhang ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); 48931e32227SNeil Zhang 490cedf8602SSascha Hauer spin_lock_irqsave(&phy_lock, flags); 491cedf8602SSascha Hauer list_for_each_entry(phy_bind, &phy_bind_list, list) 492cedf8602SSascha Hauer if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev)))) 493cedf8602SSascha Hauer phy_bind->phy = x; 494cedf8602SSascha Hauer 495cedf8602SSascha Hauer list_add_tail(&x->head, &phy_list); 496cedf8602SSascha Hauer 497cedf8602SSascha Hauer spin_unlock_irqrestore(&phy_lock, flags); 498cedf8602SSascha Hauer return 0; 499cedf8602SSascha Hauer } 500110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(usb_add_phy_dev); 501cedf8602SSascha Hauer 502cedf8602SSascha Hauer /** 503cedf8602SSascha Hauer * usb_remove_phy - remove the OTG PHY 504cedf8602SSascha Hauer * @x: the USB OTG PHY to be removed; 505cedf8602SSascha Hauer * 506cedf8602SSascha Hauer * This reverts the effects of usb_add_phy 507cedf8602SSascha Hauer */ 508cedf8602SSascha Hauer void usb_remove_phy(struct usb_phy *x) 509cedf8602SSascha Hauer { 510cedf8602SSascha Hauer unsigned long flags; 511cedf8602SSascha Hauer struct usb_phy_bind *phy_bind; 512cedf8602SSascha Hauer 513cedf8602SSascha Hauer spin_lock_irqsave(&phy_lock, flags); 514cedf8602SSascha Hauer if (x) { 515cedf8602SSascha Hauer list_for_each_entry(phy_bind, &phy_bind_list, list) 516cedf8602SSascha Hauer if (phy_bind->phy == x) 517cedf8602SSascha Hauer phy_bind->phy = NULL; 518cedf8602SSascha Hauer list_del(&x->head); 519cedf8602SSascha Hauer } 520cedf8602SSascha Hauer spin_unlock_irqrestore(&phy_lock, flags); 521cedf8602SSascha Hauer } 522110ff6d0SFelipe Balbi EXPORT_SYMBOL_GPL(usb_remove_phy); 523cedf8602SSascha Hauer 524cedf8602SSascha Hauer /** 525cedf8602SSascha Hauer * usb_bind_phy - bind the phy and the controller that uses the phy 526cedf8602SSascha Hauer * @dev_name: the device name of the device that will bind to the phy 527cedf8602SSascha Hauer * @index: index to specify the port number 528cedf8602SSascha Hauer * @phy_dev_name: the device name of the phy 529cedf8602SSascha Hauer * 530cedf8602SSascha Hauer * Fills the phy_bind structure with the dev_name and phy_dev_name. This will 531cedf8602SSascha Hauer * be used when the phy driver registers the phy and when the controller 532cedf8602SSascha Hauer * requests this phy. 533cedf8602SSascha Hauer * 534cedf8602SSascha Hauer * To be used by platform specific initialization code. 535cedf8602SSascha Hauer */ 53619d8ceddSDenis Efremov int usb_bind_phy(const char *dev_name, u8 index, 537cedf8602SSascha Hauer const char *phy_dev_name) 538cedf8602SSascha Hauer { 539cedf8602SSascha Hauer struct usb_phy_bind *phy_bind; 540cedf8602SSascha Hauer unsigned long flags; 541cedf8602SSascha Hauer 542cedf8602SSascha Hauer phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL); 543e9d123a5SJosh Boyer if (!phy_bind) 544cedf8602SSascha Hauer return -ENOMEM; 545cedf8602SSascha Hauer 546cedf8602SSascha Hauer phy_bind->dev_name = dev_name; 547cedf8602SSascha Hauer phy_bind->phy_dev_name = phy_dev_name; 548cedf8602SSascha Hauer phy_bind->index = index; 549cedf8602SSascha Hauer 550cedf8602SSascha Hauer spin_lock_irqsave(&phy_lock, flags); 551cedf8602SSascha Hauer list_add_tail(&phy_bind->list, &phy_bind_list); 552cedf8602SSascha Hauer spin_unlock_irqrestore(&phy_lock, flags); 553cedf8602SSascha Hauer 554cedf8602SSascha Hauer return 0; 555cedf8602SSascha Hauer } 556cedf8602SSascha Hauer EXPORT_SYMBOL_GPL(usb_bind_phy); 557df9f7b31SKiran Raparthy 558df9f7b31SKiran Raparthy /** 559df9f7b31SKiran Raparthy * usb_phy_set_event - set event to phy event 560df9f7b31SKiran Raparthy * @x: the phy returned by usb_get_phy(); 561df9f7b31SKiran Raparthy * 562df9f7b31SKiran Raparthy * This sets event to phy event 563df9f7b31SKiran Raparthy */ 564df9f7b31SKiran Raparthy void usb_phy_set_event(struct usb_phy *x, unsigned long event) 565df9f7b31SKiran Raparthy { 566df9f7b31SKiran Raparthy x->last_event = event; 567df9f7b31SKiran Raparthy } 568df9f7b31SKiran Raparthy EXPORT_SYMBOL_GPL(usb_phy_set_event); 569