diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index ad4f577c1ef7..48b7a67336b5 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "m_can.h" @@ -1827,6 +1828,7 @@ static int m_can_close(struct net_device *dev) close_candev(dev); + reset_control_assert(cdev->rst); m_can_clk_stop(cdev); phy_power_off(cdev->transceiver); @@ -2069,11 +2071,15 @@ static int m_can_open(struct net_device *dev) if (err) goto out_phy_power_off; + err = reset_control_deassert(cdev->rst); + if (err) + goto exit_disable_clks; + /* open the can device */ err = open_candev(dev); if (err) { netdev_err(dev, "failed to open can device\n"); - goto exit_disable_clks; + goto out_reset_control_assert; } if (cdev->is_peripheral) @@ -2129,6 +2135,8 @@ static int m_can_open(struct net_device *dev) else napi_disable(&cdev->napi); close_candev(dev); +out_reset_control_assert: + reset_control_assert(cdev->rst); exit_disable_clks: m_can_clk_stop(cdev); out_phy_power_off: @@ -2417,15 +2425,24 @@ int m_can_class_register(struct m_can_classdev *cdev) } } + cdev->rst = devm_reset_control_get_optional_shared(cdev->dev, NULL); + if (IS_ERR(cdev->rst)) + return dev_err_probe(cdev->dev, PTR_ERR(cdev->rst), + "Failed to get reset line\n"); + ret = m_can_clk_start(cdev); if (ret) return ret; + ret = reset_control_deassert(cdev->rst); + if (ret) + goto clk_disable; + if (cdev->is_peripheral) { ret = can_rx_offload_add_manual(cdev->net, &cdev->offload, NAPI_POLL_WEIGHT); if (ret) - goto clk_disable; + goto out_reset_control_assert; } if (!cdev->net->irq) { @@ -2454,8 +2471,10 @@ int m_can_class_register(struct m_can_classdev *cdev) KBUILD_MODNAME, cdev->net->irq, cdev->version); /* Probe finished - * Stop clocks. They will be reactivated once the M_CAN device is opened + * Assert reset and stop clocks. + * They will be reactivated once the M_CAN device is opened */ + reset_control_assert(cdev->rst); m_can_clk_stop(cdev); return 0; @@ -2463,6 +2482,8 @@ int m_can_class_register(struct m_can_classdev *cdev) rx_offload_del: if (cdev->is_peripheral) can_rx_offload_del(&cdev->offload); +out_reset_control_assert: + reset_control_assert(cdev->rst); clk_disable: m_can_clk_stop(cdev); diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index bd4746c63af3..7b7600697c6b 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -86,6 +86,7 @@ struct m_can_classdev { struct device *dev; struct clk *hclk; struct clk *cclk; + struct reset_control *rst; struct workqueue_struct *tx_wq; struct phy *transceiver;