Loading Documentation/phy.txt +8 −3 Original line number Diff line number Diff line Loading @@ -61,9 +61,9 @@ struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, The PHY drivers can use one of the above 2 APIs to create the PHY by passing the device pointer, phy ops and init_data. phy_ops is a set of function pointers for performing PHY operations such as init, exit, power_on and power_off. *init_data* is mandatory to get a reference to the PHY in the case of non-dt boot. See section *Board File Initialization* on how init_data should be used. init, exit, power_on, power_off, suspend, resume and advertise_quirks. *init_data* is mandatory to get a reference to the PHY in the case of non-dt boot. See section *Board File Initialization* on how init_data should be used. Inorder to dereference the private data (in phy_ops), the phy provider driver can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in Loading @@ -76,6 +76,7 @@ it. This framework provides the following APIs to get a reference to the PHY. struct phy *phy_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *devm_phy_get_by_index(struct device *dev, int index) phy_get and devm_phy_get can be used to get the PHY. In the case of dt boot, the string arguments should contain the phy name as given in the dt data and Loading @@ -83,6 +84,10 @@ in the case of non-dt boot, it should contain the label of the PHY. The only difference between the two APIs is that devm_phy_get associates the device with the PHY using devres on successful PHY get. On driver detach, release function is invoked on the the devres data and devres data is freed. devm_phy_get_by_index can also be used to get the PHY. In this case, the index is that of the relevant phy devm_phy_get_by_index is using phy_get_by_index that tries to match the given index with #phy-cells attribute in dt file, on every phys in "phys" list. 5. Releasing a reference to the PHY Loading drivers/phy/phy-core.c +100 −7 Original line number Diff line number Diff line Loading @@ -239,24 +239,87 @@ out: } EXPORT_SYMBOL_GPL(phy_power_off); int phy_suspend(struct phy *phy) { int ret = -ENOTSUPP; if (!phy->ops->suspend) return ret; mutex_lock(&phy->mutex); if (--phy->resume_count == 0) { ret = phy->ops->suspend(phy); if (ret) { dev_err(&phy->dev, "phy suspend failed --> %d\n", ret); /* reverting the resume_count since suspend failed */ phy->resume_count++; goto out; } } out: mutex_unlock(&phy->mutex); return ret; } EXPORT_SYMBOL(phy_suspend); int phy_resume(struct phy *phy) { int ret = -ENOTSUPP; if (!phy->ops->resume) return ret; mutex_lock(&phy->mutex); if (phy->resume_count++ == 0) { ret = phy->ops->resume(phy); if (ret) { dev_err(&phy->dev, "phy resume failed --> %d\n", ret); /* reverting the resume_count since resume failed */ phy->resume_count--; goto out; } } out: mutex_unlock(&phy->mutex); return ret; } EXPORT_SYMBOL(phy_resume); void phy_advertise_quirks(struct phy *phy) { if (phy->ops->advertise_quirks) { mutex_lock(&phy->mutex); phy->ops->advertise_quirks(phy); mutex_unlock(&phy->mutex); } } EXPORT_SYMBOL(phy_advertise_quirks); /** * of_phy_get() - lookup and obtain a reference to a phy by phandle * phy_get_by_index() - lookup and obtain a reference to a phy by index * @dev: device that requests this phy * @index: the index of the phy * * Returns the phy associated with the given phandle value, * Returns the phy associated with the given index value, * after getting a refcount to it or -ENODEV if there is no such phy or * -EPROBE_DEFER if there is a phandle to the phy, but the device is * -EPROBE_DEFER if there is an index to the phy, but the device is * not yet loaded. This function uses of_xlate call back function provided * while registering the phy_provider to find the phy instance. */ static struct phy *of_phy_get(struct device *dev, int index) struct phy *phy_get_by_index(struct device *dev, int index) { int ret; struct phy_provider *phy_provider; struct phy *phy = NULL; struct of_phandle_args args; if (!dev || !(dev->of_node)) { dev_err(dev, "%s dev %p", __func__, dev); return ERR_PTR(-ENODEV); } ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells", index, &args); if (ret) { Loading @@ -281,6 +344,36 @@ err0: return phy; } EXPORT_SYMBOL(phy_get_by_index); /** * devm_phy_get_by_index() - lookup and obtain a reference to a phy by index * @dev: device that requests this phy * @index: the index of the phy * * Gets the phy using phy_get_by_index(), and associates a device * with it using devres. On driver detach, release function is invoked * on the devres data, then, devres data is freed. */ struct phy *devm_phy_get_by_index(struct device *dev, int index) { struct phy **ptr, *phy; ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); phy = phy_get_by_index(dev, index); if (!IS_ERR(phy)) { *ptr = phy; devres_add(dev, ptr); } else { devres_free(ptr); } return phy; } EXPORT_SYMBOL(devm_phy_get_by_index); /** * phy_put() - release the PHY Loading Loading @@ -370,15 +463,15 @@ struct phy *phy_get(struct device *dev, const char *string) if (dev->of_node) { index = of_property_match_string(dev->of_node, "phy-names", string); phy = of_phy_get(dev, index); phy = phy_get_by_index(dev, index); if (IS_ERR(phy)) { dev_err(dev, "unable to find phy\n"); dev_err(dev, "unable to find phy by index\n"); return phy; } } else { phy = phy_lookup(dev, string); if (IS_ERR(phy)) { dev_err(dev, "unable to find phy\n"); dev_err(dev, "unable to find phy by lookup\n"); return phy; } } Loading include/linux/phy/phy.h +40 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,14 @@ struct phy; * @exit: operation to be performed while exiting * @power_on: powering on the phy * @power_off: powering off the phy * @advertise_quirks: setting specific phy quirks. this api is for an internal use of the device driver, and its purpose is to exteriorize the driver's phy quirks according to phy version (or other parameters), so further behaviour of the driver's phy is based on those quirks. * @suspend: suspending the phy * @resume: resuming the phy * @owner: the module owner containing the ops */ struct phy_ops { Loading @@ -34,6 +42,10 @@ struct phy_ops { int (*exit)(struct phy *phy); int (*power_on)(struct phy *phy); int (*power_off)(struct phy *phy); void (*advertise_quirks)(struct phy *phy); int (*suspend)(struct phy *phy); int (*resume)(struct phy *phy); struct module *owner; }; Loading @@ -46,6 +58,8 @@ struct phy_ops { * @mutex: mutex to protect phy_ops * @init_count: used to protect when the PHY is used by multiple consumers * @power_count: used to protect when the PHY is used by multiple consumers * @resume_count: used to protect when the PHY is used by multiple consumers * that resume and suspend it */ struct phy { struct device dev; Loading @@ -55,6 +69,7 @@ struct phy { struct mutex mutex; int init_count; int power_count; int resume_count; }; /** Loading Loading @@ -125,10 +140,15 @@ void phy_pm_runtime_allow(struct phy *phy); void phy_pm_runtime_forbid(struct phy *phy); int phy_init(struct phy *phy); int phy_exit(struct phy *phy); void phy_advertise_quirks(struct phy *phy); int phy_power_on(struct phy *phy); int phy_power_off(struct phy *phy); int phy_suspend(struct phy *phy); int phy_resume(struct phy *phy); struct phy *phy_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *phy_get_by_index(struct device *dev, int index); struct phy *devm_phy_get_by_index(struct device *dev, int index); void phy_put(struct phy *phy); void devm_phy_put(struct device *dev, struct phy *phy); struct phy *of_phy_simple_xlate(struct device *dev, Loading Loading @@ -199,6 +219,21 @@ static inline int phy_power_off(struct phy *phy) return -ENOSYS; } static inline void phy_advertise_quirks(struct phy *phy) { return; } static inline int phy_suspend(struct phy *phy) { return -ENOSYS; } static inline int phy_resume(struct phy *phy) { return -ENOSYS; } static inline struct phy *phy_get(struct device *dev, const char *string) { return ERR_PTR(-ENOSYS); Loading @@ -209,6 +244,11 @@ static inline struct phy *devm_phy_get(struct device *dev, const char *string) return ERR_PTR(-ENOSYS); } static inline struct phy *devm_phy_get_by_index(struct device *dev, int index) { return ERR_PTR(-ENOSYS); } static inline void phy_put(struct phy *phy) { } Loading Loading
Documentation/phy.txt +8 −3 Original line number Diff line number Diff line Loading @@ -61,9 +61,9 @@ struct phy *devm_phy_create(struct device *dev, const struct phy_ops *ops, The PHY drivers can use one of the above 2 APIs to create the PHY by passing the device pointer, phy ops and init_data. phy_ops is a set of function pointers for performing PHY operations such as init, exit, power_on and power_off. *init_data* is mandatory to get a reference to the PHY in the case of non-dt boot. See section *Board File Initialization* on how init_data should be used. init, exit, power_on, power_off, suspend, resume and advertise_quirks. *init_data* is mandatory to get a reference to the PHY in the case of non-dt boot. See section *Board File Initialization* on how init_data should be used. Inorder to dereference the private data (in phy_ops), the phy provider driver can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in Loading @@ -76,6 +76,7 @@ it. This framework provides the following APIs to get a reference to the PHY. struct phy *phy_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *devm_phy_get_by_index(struct device *dev, int index) phy_get and devm_phy_get can be used to get the PHY. In the case of dt boot, the string arguments should contain the phy name as given in the dt data and Loading @@ -83,6 +84,10 @@ in the case of non-dt boot, it should contain the label of the PHY. The only difference between the two APIs is that devm_phy_get associates the device with the PHY using devres on successful PHY get. On driver detach, release function is invoked on the the devres data and devres data is freed. devm_phy_get_by_index can also be used to get the PHY. In this case, the index is that of the relevant phy devm_phy_get_by_index is using phy_get_by_index that tries to match the given index with #phy-cells attribute in dt file, on every phys in "phys" list. 5. Releasing a reference to the PHY Loading
drivers/phy/phy-core.c +100 −7 Original line number Diff line number Diff line Loading @@ -239,24 +239,87 @@ out: } EXPORT_SYMBOL_GPL(phy_power_off); int phy_suspend(struct phy *phy) { int ret = -ENOTSUPP; if (!phy->ops->suspend) return ret; mutex_lock(&phy->mutex); if (--phy->resume_count == 0) { ret = phy->ops->suspend(phy); if (ret) { dev_err(&phy->dev, "phy suspend failed --> %d\n", ret); /* reverting the resume_count since suspend failed */ phy->resume_count++; goto out; } } out: mutex_unlock(&phy->mutex); return ret; } EXPORT_SYMBOL(phy_suspend); int phy_resume(struct phy *phy) { int ret = -ENOTSUPP; if (!phy->ops->resume) return ret; mutex_lock(&phy->mutex); if (phy->resume_count++ == 0) { ret = phy->ops->resume(phy); if (ret) { dev_err(&phy->dev, "phy resume failed --> %d\n", ret); /* reverting the resume_count since resume failed */ phy->resume_count--; goto out; } } out: mutex_unlock(&phy->mutex); return ret; } EXPORT_SYMBOL(phy_resume); void phy_advertise_quirks(struct phy *phy) { if (phy->ops->advertise_quirks) { mutex_lock(&phy->mutex); phy->ops->advertise_quirks(phy); mutex_unlock(&phy->mutex); } } EXPORT_SYMBOL(phy_advertise_quirks); /** * of_phy_get() - lookup and obtain a reference to a phy by phandle * phy_get_by_index() - lookup and obtain a reference to a phy by index * @dev: device that requests this phy * @index: the index of the phy * * Returns the phy associated with the given phandle value, * Returns the phy associated with the given index value, * after getting a refcount to it or -ENODEV if there is no such phy or * -EPROBE_DEFER if there is a phandle to the phy, but the device is * -EPROBE_DEFER if there is an index to the phy, but the device is * not yet loaded. This function uses of_xlate call back function provided * while registering the phy_provider to find the phy instance. */ static struct phy *of_phy_get(struct device *dev, int index) struct phy *phy_get_by_index(struct device *dev, int index) { int ret; struct phy_provider *phy_provider; struct phy *phy = NULL; struct of_phandle_args args; if (!dev || !(dev->of_node)) { dev_err(dev, "%s dev %p", __func__, dev); return ERR_PTR(-ENODEV); } ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells", index, &args); if (ret) { Loading @@ -281,6 +344,36 @@ err0: return phy; } EXPORT_SYMBOL(phy_get_by_index); /** * devm_phy_get_by_index() - lookup and obtain a reference to a phy by index * @dev: device that requests this phy * @index: the index of the phy * * Gets the phy using phy_get_by_index(), and associates a device * with it using devres. On driver detach, release function is invoked * on the devres data, then, devres data is freed. */ struct phy *devm_phy_get_by_index(struct device *dev, int index) { struct phy **ptr, *phy; ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); phy = phy_get_by_index(dev, index); if (!IS_ERR(phy)) { *ptr = phy; devres_add(dev, ptr); } else { devres_free(ptr); } return phy; } EXPORT_SYMBOL(devm_phy_get_by_index); /** * phy_put() - release the PHY Loading Loading @@ -370,15 +463,15 @@ struct phy *phy_get(struct device *dev, const char *string) if (dev->of_node) { index = of_property_match_string(dev->of_node, "phy-names", string); phy = of_phy_get(dev, index); phy = phy_get_by_index(dev, index); if (IS_ERR(phy)) { dev_err(dev, "unable to find phy\n"); dev_err(dev, "unable to find phy by index\n"); return phy; } } else { phy = phy_lookup(dev, string); if (IS_ERR(phy)) { dev_err(dev, "unable to find phy\n"); dev_err(dev, "unable to find phy by lookup\n"); return phy; } } Loading
include/linux/phy/phy.h +40 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,14 @@ struct phy; * @exit: operation to be performed while exiting * @power_on: powering on the phy * @power_off: powering off the phy * @advertise_quirks: setting specific phy quirks. this api is for an internal use of the device driver, and its purpose is to exteriorize the driver's phy quirks according to phy version (or other parameters), so further behaviour of the driver's phy is based on those quirks. * @suspend: suspending the phy * @resume: resuming the phy * @owner: the module owner containing the ops */ struct phy_ops { Loading @@ -34,6 +42,10 @@ struct phy_ops { int (*exit)(struct phy *phy); int (*power_on)(struct phy *phy); int (*power_off)(struct phy *phy); void (*advertise_quirks)(struct phy *phy); int (*suspend)(struct phy *phy); int (*resume)(struct phy *phy); struct module *owner; }; Loading @@ -46,6 +58,8 @@ struct phy_ops { * @mutex: mutex to protect phy_ops * @init_count: used to protect when the PHY is used by multiple consumers * @power_count: used to protect when the PHY is used by multiple consumers * @resume_count: used to protect when the PHY is used by multiple consumers * that resume and suspend it */ struct phy { struct device dev; Loading @@ -55,6 +69,7 @@ struct phy { struct mutex mutex; int init_count; int power_count; int resume_count; }; /** Loading Loading @@ -125,10 +140,15 @@ void phy_pm_runtime_allow(struct phy *phy); void phy_pm_runtime_forbid(struct phy *phy); int phy_init(struct phy *phy); int phy_exit(struct phy *phy); void phy_advertise_quirks(struct phy *phy); int phy_power_on(struct phy *phy); int phy_power_off(struct phy *phy); int phy_suspend(struct phy *phy); int phy_resume(struct phy *phy); struct phy *phy_get(struct device *dev, const char *string); struct phy *devm_phy_get(struct device *dev, const char *string); struct phy *phy_get_by_index(struct device *dev, int index); struct phy *devm_phy_get_by_index(struct device *dev, int index); void phy_put(struct phy *phy); void devm_phy_put(struct device *dev, struct phy *phy); struct phy *of_phy_simple_xlate(struct device *dev, Loading Loading @@ -199,6 +219,21 @@ static inline int phy_power_off(struct phy *phy) return -ENOSYS; } static inline void phy_advertise_quirks(struct phy *phy) { return; } static inline int phy_suspend(struct phy *phy) { return -ENOSYS; } static inline int phy_resume(struct phy *phy) { return -ENOSYS; } static inline struct phy *phy_get(struct device *dev, const char *string) { return ERR_PTR(-ENOSYS); Loading @@ -209,6 +244,11 @@ static inline struct phy *devm_phy_get(struct device *dev, const char *string) return ERR_PTR(-ENOSYS); } static inline struct phy *devm_phy_get_by_index(struct device *dev, int index) { return ERR_PTR(-ENOSYS); } static inline void phy_put(struct phy *phy) { } Loading