mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	phy: core: Add consumer device link support
In order to enforce suspend/resume ordering, this commit creates link between phy consumers and phy devices. This link avoids to suspend phy before phy consumers. Signed-off-by: Alexandre Torgue <alexandre.torgue@st.com> [jonathanh@nvidia.com: Fix an abort when of_phy_get() returns error] Signed-off-by: Jonathan Hunter <jonathanh@nvidia.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
This commit is contained in:
		
							parent
							
								
									24dbe0aaa0
								
							
						
					
					
						commit
						987351e1ea
					
				
					 4 changed files with 53 additions and 9 deletions
				
			
		| 
						 | 
				
			
			@ -29,7 +29,7 @@ static void devm_phy_release(struct device *dev, void *res)
 | 
			
		|||
{
 | 
			
		||||
	struct phy *phy = *(struct phy **)res;
 | 
			
		||||
 | 
			
		||||
	phy_put(phy);
 | 
			
		||||
	phy_put(dev, phy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void devm_phy_provider_release(struct device *dev, void *res)
 | 
			
		||||
| 
						 | 
				
			
			@ -566,12 +566,12 @@ struct phy *of_phy_get(struct device_node *np, const char *con_id)
 | 
			
		|||
EXPORT_SYMBOL_GPL(of_phy_get);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * phy_put() - release the PHY
 | 
			
		||||
 * @phy: the phy returned by phy_get()
 | 
			
		||||
 * of_phy_put() - release the PHY
 | 
			
		||||
 * @phy: the phy returned by of_phy_get()
 | 
			
		||||
 *
 | 
			
		||||
 * Releases a refcount the caller received from phy_get().
 | 
			
		||||
 * Releases a refcount the caller received from of_phy_get().
 | 
			
		||||
 */
 | 
			
		||||
void phy_put(struct phy *phy)
 | 
			
		||||
void of_phy_put(struct phy *phy)
 | 
			
		||||
{
 | 
			
		||||
	if (!phy || IS_ERR(phy))
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -584,6 +584,20 @@ void phy_put(struct phy *phy)
 | 
			
		|||
	module_put(phy->ops->owner);
 | 
			
		||||
	put_device(&phy->dev);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(of_phy_put);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * phy_put() - release the PHY
 | 
			
		||||
 * @dev: device that wants to release this phy
 | 
			
		||||
 * @phy: the phy returned by phy_get()
 | 
			
		||||
 *
 | 
			
		||||
 * Releases a refcount the caller received from phy_get().
 | 
			
		||||
 */
 | 
			
		||||
void phy_put(struct device *dev, struct phy *phy)
 | 
			
		||||
{
 | 
			
		||||
	device_link_remove(dev, &phy->dev);
 | 
			
		||||
	of_phy_put(phy);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(phy_put);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -651,6 +665,7 @@ struct phy *phy_get(struct device *dev, const char *string)
 | 
			
		|||
{
 | 
			
		||||
	int index = 0;
 | 
			
		||||
	struct phy *phy;
 | 
			
		||||
	struct device_link *link;
 | 
			
		||||
 | 
			
		||||
	if (string == NULL) {
 | 
			
		||||
		dev_WARN(dev, "missing string\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -672,6 +687,13 @@ struct phy *phy_get(struct device *dev, const char *string)
 | 
			
		|||
 | 
			
		||||
	get_device(&phy->dev);
 | 
			
		||||
 | 
			
		||||
	link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
 | 
			
		||||
	if (!link) {
 | 
			
		||||
		dev_err(dev, "failed to create device link to %s\n",
 | 
			
		||||
			dev_name(phy->dev.parent));
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return phy;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(phy_get);
 | 
			
		||||
| 
						 | 
				
			
			@ -765,6 +787,7 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
 | 
			
		|||
			    const char *con_id)
 | 
			
		||||
{
 | 
			
		||||
	struct phy **ptr, *phy;
 | 
			
		||||
	struct device_link *link;
 | 
			
		||||
 | 
			
		||||
	ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
 | 
			
		||||
	if (!ptr)
 | 
			
		||||
| 
						 | 
				
			
			@ -776,6 +799,14 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
 | 
			
		|||
		devres_add(dev, ptr);
 | 
			
		||||
	} else {
 | 
			
		||||
		devres_free(ptr);
 | 
			
		||||
		return phy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
 | 
			
		||||
	if (!link) {
 | 
			
		||||
		dev_err(dev, "failed to create device link to %s\n",
 | 
			
		||||
			dev_name(phy->dev.parent));
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return phy;
 | 
			
		||||
| 
						 | 
				
			
			@ -798,6 +829,7 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
 | 
			
		|||
				     int index)
 | 
			
		||||
{
 | 
			
		||||
	struct phy **ptr, *phy;
 | 
			
		||||
	struct device_link *link;
 | 
			
		||||
 | 
			
		||||
	ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
 | 
			
		||||
	if (!ptr)
 | 
			
		||||
| 
						 | 
				
			
			@ -819,6 +851,13 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
 | 
			
		|||
	*ptr = phy;
 | 
			
		||||
	devres_add(dev, ptr);
 | 
			
		||||
 | 
			
		||||
	link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
 | 
			
		||||
	if (!link) {
 | 
			
		||||
		dev_err(dev, "failed to create device link to %s\n",
 | 
			
		||||
			dev_name(phy->dev.parent));
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return phy;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev)
 | 
			
		|||
	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
 | 
			
		||||
 | 
			
		||||
	if (priv->phy) {
 | 
			
		||||
		phy_put(priv->phy);
 | 
			
		||||
		phy_put(&pdev->dev, priv->phy);
 | 
			
		||||
		priv->phy = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ static int usbhs_rza2_hardware_exit(struct platform_device *pdev)
 | 
			
		|||
{
 | 
			
		||||
	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
 | 
			
		||||
 | 
			
		||||
	phy_put(priv->phy);
 | 
			
		||||
	phy_put(&pdev->dev, priv->phy);
 | 
			
		||||
	priv->phy = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -234,7 +234,8 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
 | 
			
		|||
			    const char *con_id);
 | 
			
		||||
struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
 | 
			
		||||
				     int index);
 | 
			
		||||
void phy_put(struct phy *phy);
 | 
			
		||||
void of_phy_put(struct phy *phy);
 | 
			
		||||
void phy_put(struct device *dev, struct phy *phy);
 | 
			
		||||
void devm_phy_put(struct device *dev, struct phy *phy);
 | 
			
		||||
struct phy *of_phy_get(struct device_node *np, const char *con_id);
 | 
			
		||||
struct phy *of_phy_simple_xlate(struct device *dev,
 | 
			
		||||
| 
						 | 
				
			
			@ -419,7 +420,11 @@ static inline struct phy *devm_of_phy_get_by_index(struct device *dev,
 | 
			
		|||
	return ERR_PTR(-ENOSYS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void phy_put(struct phy *phy)
 | 
			
		||||
static inline void of_phy_put(struct phy *phy)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void phy_put(struct device *dev, struct phy *phy)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue