mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 08:33:17 +02:00
Merge patch series "can: rcar_canfd: Add transceiver support"
Geert Uytterhoeven <geert+renesas@glider.be> says: This patch series adds transceiver support to the Renesas R-Car CAN-FD driver, and improves the printing of error messages, as requested by Vincent. Link: https://lore.kernel.org/all/cover.1679414936.git.geert+renesas@glider.be Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
commit
f6b53d1b38
|
|
@ -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 @@ static int rcar_canfd_open(struct net_device *ndev)
|
|||
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] = { 0, };
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user