Commit a0340df7 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Marc Kleine-Budde

can: rcar_canfd: Add transceiver support

Add support for CAN transceivers described as PHYs.

While simple CAN transceivers can do without, this is needed for CAN
transceivers like NXP TJR1443 that need a configuration step (like
pulling standby or enable lines), and/or impose a bitrate limit.
Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: default avatarSimon Horman <simon.horman@corigine.com>
Reviewed-by: default avatarVincent Mailhol <mailhol.vincent@wanadoo.fr>
Link: https://lore.kernel.org/all/1ce907572ac1d4e1733fa6ea7712250f2229cfcb.1679414936.git.geert+renesas@glider.be
[mkl: squash error message update from patch 2]
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 323fe43c
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -530,6 +531,7 @@ struct rcar_canfd_channel { ...@@ -530,6 +531,7 @@ struct rcar_canfd_channel {
struct net_device *ndev; struct net_device *ndev;
struct rcar_canfd_global *gpriv; /* Controller reference */ struct rcar_canfd_global *gpriv; /* Controller reference */
void __iomem *base; /* Register base address */ void __iomem *base; /* Register base address */
struct phy *transceiver; /* Optional transceiver */
struct napi_struct napi; struct napi_struct napi;
u32 tx_head; /* Incremented on xmit */ u32 tx_head; /* Incremented on xmit */
u32 tx_tail; /* Incremented on xmit done */ u32 tx_tail; /* Incremented on xmit done */
...@@ -1413,11 +1415,17 @@ static int rcar_canfd_open(struct net_device *ndev) ...@@ -1413,11 +1415,17 @@ static int rcar_canfd_open(struct net_device *ndev)
struct rcar_canfd_global *gpriv = priv->gpriv; struct rcar_canfd_global *gpriv = priv->gpriv;
int err; 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 */ /* Peripheral clock is already enabled in probe */
err = clk_prepare_enable(gpriv->can_clk); err = clk_prepare_enable(gpriv->can_clk);
if (err) { if (err) {
netdev_err(ndev, "failed to enable CAN clock, error %d\n", err); netdev_err(ndev, "failed to enable CAN clock, error %d\n", err);
goto out_clock; goto out_phy;
} }
err = open_candev(ndev); err = open_candev(ndev);
...@@ -1437,7 +1445,8 @@ static int rcar_canfd_open(struct net_device *ndev) ...@@ -1437,7 +1445,8 @@ static int rcar_canfd_open(struct net_device *ndev)
close_candev(ndev); close_candev(ndev);
out_can_clock: out_can_clock:
clk_disable_unprepare(gpriv->can_clk); clk_disable_unprepare(gpriv->can_clk);
out_clock: out_phy:
phy_power_off(priv->transceiver);
return err; return err;
} }
...@@ -1480,6 +1489,7 @@ static int rcar_canfd_close(struct net_device *ndev) ...@@ -1480,6 +1489,7 @@ static int rcar_canfd_close(struct net_device *ndev)
napi_disable(&priv->napi); napi_disable(&priv->napi);
clk_disable_unprepare(gpriv->can_clk); clk_disable_unprepare(gpriv->can_clk);
close_candev(ndev); close_candev(ndev);
phy_power_off(priv->transceiver);
return 0; return 0;
} }
...@@ -1711,7 +1721,7 @@ static const struct ethtool_ops rcar_canfd_ethtool_ops = { ...@@ -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, 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; const struct rcar_canfd_hw_info *info = gpriv->info;
struct platform_device *pdev = gpriv->pdev; struct platform_device *pdev = gpriv->pdev;
...@@ -1732,8 +1742,11 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch, ...@@ -1732,8 +1742,11 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
ndev->flags |= IFF_ECHO; ndev->flags |= IFF_ECHO;
priv->ndev = ndev; priv->ndev = ndev;
priv->base = gpriv->base; priv->base = gpriv->base;
priv->transceiver = transceiver;
priv->channel = ch; priv->channel = ch;
priv->gpriv = gpriv; priv->gpriv = gpriv;
if (transceiver)
priv->can.bitrate_max = transceiver->attrs.max_link_rate;
priv->can.clock.freq = fcan_freq; priv->can.clock.freq = fcan_freq;
dev_info(dev, "can_clk rate is %u\n", priv->can.clock.freq); dev_info(dev, "can_clk rate is %u\n", priv->can.clock.freq);
...@@ -1836,6 +1849,7 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch) ...@@ -1836,6 +1849,7 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch)
static int rcar_canfd_probe(struct platform_device *pdev) static int rcar_canfd_probe(struct platform_device *pdev)
{ {
struct phy *transceivers[RCANFD_NUM_CHANNELS] = { 0, };
const struct rcar_canfd_hw_info *info; const struct rcar_canfd_hw_info *info;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
void __iomem *addr; void __iomem *addr;
...@@ -1857,9 +1871,14 @@ static int rcar_canfd_probe(struct platform_device *pdev) ...@@ -1857,9 +1871,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)
for (i = 0; i < info->max_channels; ++i) { for (i = 0; i < info->max_channels; ++i) {
name[7] = '0' + i; name[7] = '0' + i;
of_child = of_get_child_by_name(dev->of_node, name); 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); channels_mask |= BIT(i);
transceivers[i] = devm_of_phy_optional_get(dev,
of_child, NULL);
}
of_node_put(of_child); of_node_put(of_child);
if (IS_ERR(transceivers[i]))
return PTR_ERR(transceivers[i]);
} }
if (info->shared_global_irqs) { if (info->shared_global_irqs) {
...@@ -2035,7 +2054,8 @@ static int rcar_canfd_probe(struct platform_device *pdev) ...@@ -2035,7 +2054,8 @@ static int rcar_canfd_probe(struct platform_device *pdev)
} }
for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) { 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) if (err)
goto fail_channel; goto fail_channel;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment