diff options
Diffstat (limited to 'drivers/net/can/rcar/rcar_canfd.c')
| -rw-r--r-- | drivers/net/can/rcar/rcar_canfd.c | 71 | 
1 files changed, 45 insertions, 26 deletions
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index ef4e1b9a9e1e..963c42f43755 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -35,6 +35,7 @@  #include <linux/netdevice.h>  #include <linux/of.h>  #include <linux/of_device.h> +#include <linux/phy/phy.h>  #include <linux/platform_device.h>  #include <linux/reset.h>  #include <linux/types.h> @@ -530,6 +531,7 @@ struct rcar_canfd_channel {  	struct net_device *ndev;  	struct rcar_canfd_global *gpriv;	/* Controller reference */  	void __iomem *base;			/* Register base address */ +	struct phy *transceiver;		/* Optional transceiver */  	struct napi_struct napi;  	u32 tx_head;				/* Incremented on xmit */  	u32 tx_tail;				/* Incremented on xmit done */ @@ -1413,16 +1415,22 @@ static int rcar_canfd_open(struct net_device *ndev)  	struct rcar_canfd_global *gpriv = priv->gpriv;  	int err; +	err = phy_power_on(priv->transceiver); +	if (err) { +		netdev_err(ndev, "failed to power on PHY: %pe\n", ERR_PTR(err)); +		return err; +	} +  	/* Peripheral clock is already enabled in probe */  	err = clk_prepare_enable(gpriv->can_clk);  	if (err) { -		netdev_err(ndev, "failed to enable CAN clock, error %d\n", err); -		goto out_clock; +		netdev_err(ndev, "failed to enable CAN clock: %pe\n", ERR_PTR(err)); +		goto out_phy;  	}  	err = open_candev(ndev);  	if (err) { -		netdev_err(ndev, "open_candev() failed, error %d\n", err); +		netdev_err(ndev, "open_candev() failed: %pe\n", ERR_PTR(err));  		goto out_can_clock;  	} @@ -1437,7 +1445,8 @@ out_close:  	close_candev(ndev);  out_can_clock:  	clk_disable_unprepare(gpriv->can_clk); -out_clock: +out_phy: +	phy_power_off(priv->transceiver);  	return err;  } @@ -1480,6 +1489,7 @@ static int rcar_canfd_close(struct net_device *ndev)  	napi_disable(&priv->napi);  	clk_disable_unprepare(gpriv->can_clk);  	close_candev(ndev); +	phy_power_off(priv->transceiver);  	return 0;  } @@ -1711,7 +1721,7 @@ static const struct ethtool_ops rcar_canfd_ethtool_ops = {  };  static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, -				    u32 fcan_freq) +				    u32 fcan_freq, struct phy *transceiver)  {  	const struct rcar_canfd_hw_info *info = gpriv->info;  	struct platform_device *pdev = gpriv->pdev; @@ -1721,10 +1731,9 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,  	int err = -ENODEV;  	ndev = alloc_candev(sizeof(*priv), RCANFD_FIFO_DEPTH); -	if (!ndev) { -		dev_err(dev, "alloc_candev() failed\n"); +	if (!ndev)  		return -ENOMEM; -	} +  	priv = netdev_priv(ndev);  	ndev->netdev_ops = &rcar_canfd_netdev_ops; @@ -1732,8 +1741,11 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,  	ndev->flags |= IFF_ECHO;  	priv->ndev = ndev;  	priv->base = gpriv->base; +	priv->transceiver = transceiver;  	priv->channel = ch;  	priv->gpriv = gpriv; +	if (transceiver) +		priv->can.bitrate_max = transceiver->attrs.max_link_rate;  	priv->can.clock.freq = fcan_freq;  	dev_info(dev, "can_clk rate is %u\n", priv->can.clock.freq); @@ -1764,8 +1776,8 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,  				       rcar_canfd_channel_err_interrupt, 0,  				       irq_name, priv);  		if (err) { -			dev_err(dev, "devm_request_irq CH Err(%d) failed, error %d\n", -				err_irq, err); +			dev_err(dev, "devm_request_irq CH Err %d failed: %pe\n", +				err_irq, ERR_PTR(err));  			goto fail;  		}  		irq_name = devm_kasprintf(dev, GFP_KERNEL, "canfd.ch%d_trx", @@ -1778,8 +1790,8 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,  				       rcar_canfd_channel_tx_interrupt, 0,  				       irq_name, priv);  		if (err) { -			dev_err(dev, "devm_request_irq Tx (%d) failed, error %d\n", -				tx_irq, err); +			dev_err(dev, "devm_request_irq Tx %d failed: %pe\n", +				tx_irq, ERR_PTR(err));  			goto fail;  		}  	} @@ -1810,7 +1822,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,  	gpriv->ch[priv->channel] = priv;  	err = register_candev(ndev);  	if (err) { -		dev_err(dev, "register_candev() failed, error %d\n", err); +		dev_err(dev, "register_candev() failed: %pe\n", ERR_PTR(err));  		goto fail_candev;  	}  	dev_info(dev, "device registered (channel %u)\n", priv->channel); @@ -1836,6 +1848,7 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch)  static int rcar_canfd_probe(struct platform_device *pdev)  { +	struct phy *transceivers[RCANFD_NUM_CHANNELS] = { NULL, };  	const struct rcar_canfd_hw_info *info;  	struct device *dev = &pdev->dev;  	void __iomem *addr; @@ -1857,9 +1870,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)  	for (i = 0; i < info->max_channels; ++i) {  		name[7] = '0' + i;  		of_child = of_get_child_by_name(dev->of_node, name); -		if (of_child && of_device_is_available(of_child)) +		if (of_child && of_device_is_available(of_child)) {  			channels_mask |= BIT(i); +			transceivers[i] = devm_of_phy_optional_get(dev, +							of_child, NULL); +		}  		of_node_put(of_child); +		if (IS_ERR(transceivers[i])) +			return PTR_ERR(transceivers[i]);  	}  	if (info->shared_global_irqs) { @@ -1948,16 +1966,16 @@ static int rcar_canfd_probe(struct platform_device *pdev)  				       rcar_canfd_channel_interrupt, 0,  				       "canfd.ch_int", gpriv);  		if (err) { -			dev_err(dev, "devm_request_irq(%d) failed, error %d\n", -				ch_irq, err); +			dev_err(dev, "devm_request_irq %d failed: %pe\n", +				ch_irq, ERR_PTR(err));  			goto fail_dev;  		}  		err = devm_request_irq(dev, g_irq, rcar_canfd_global_interrupt,  				       0, "canfd.g_int", gpriv);  		if (err) { -			dev_err(dev, "devm_request_irq(%d) failed, error %d\n", -				g_irq, err); +			dev_err(dev, "devm_request_irq %d failed: %pe\n", +				g_irq, ERR_PTR(err));  			goto fail_dev;  		}  	} else { @@ -1966,8 +1984,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)  				       "canfd.g_recc", gpriv);  		if (err) { -			dev_err(dev, "devm_request_irq(%d) failed, error %d\n", -				g_recc_irq, err); +			dev_err(dev, "devm_request_irq %d failed: %pe\n", +				g_recc_irq, ERR_PTR(err));  			goto fail_dev;  		} @@ -1975,8 +1993,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)  				       rcar_canfd_global_err_interrupt, 0,  				       "canfd.g_err", gpriv);  		if (err) { -			dev_err(dev, "devm_request_irq(%d) failed, error %d\n", -				g_err_irq, err); +			dev_err(dev, "devm_request_irq %d failed: %pe\n", +				g_err_irq, ERR_PTR(err));  			goto fail_dev;  		}  	} @@ -1993,14 +2011,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)  	/* Enable peripheral clock for register access */  	err = clk_prepare_enable(gpriv->clkp);  	if (err) { -		dev_err(dev, "failed to enable peripheral clock, error %d\n", -			err); +		dev_err(dev, "failed to enable peripheral clock: %pe\n", +			ERR_PTR(err));  		goto fail_reset;  	}  	err = rcar_canfd_reset_controller(gpriv);  	if (err) { -		dev_err(dev, "reset controller failed\n"); +		dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));  		goto fail_clk;  	} @@ -2035,7 +2053,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)  	}  	for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) { -		err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq); +		err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq, +					       transceivers[ch]);  		if (err)  			goto fail_channel;  	}  |