Commit 2e12d79f authored by Marc Kleine-Budde's avatar Marc Kleine-Budde

Merge patch series "can: xilinx_can: Add support for reset"

Michal Simek <michal.simek@amd.com> says:

IP core has option reset line which can be wired that's why add
support for optional reset.

Changes in v2:
- Add Conor's ACK
- Fix use-after-free in xcan_remove reported by Marc.
- Link to v1: https://lore.kernel.org/all/cover.1689084227.git.michal.simek@amd.com

Link: https://lore.kernel.org/all/cover.1689164442.git.michal.simek@amd.comSigned-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 22d8e8d6 25000fc7
...@@ -46,6 +46,9 @@ properties: ...@@ -46,6 +46,9 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: CAN Tx mailbox buffer count (CAN FD) description: CAN Tx mailbox buffer count (CAN FD)
resets:
maxItems: 1
required: required:
- compatible - compatible
- reg - reg
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h>
#define DRIVER_NAME "xilinx_can" #define DRIVER_NAME "xilinx_can"
...@@ -200,6 +201,7 @@ struct xcan_devtype_data { ...@@ -200,6 +201,7 @@ struct xcan_devtype_data {
* @can_clk: Pointer to struct clk * @can_clk: Pointer to struct clk
* @devtype: Device type specific constants * @devtype: Device type specific constants
* @transceiver: Optional pointer to associated CAN transceiver * @transceiver: Optional pointer to associated CAN transceiver
* @rstc: Pointer to reset control
*/ */
struct xcan_priv { struct xcan_priv {
struct can_priv can; struct can_priv can;
...@@ -218,6 +220,7 @@ struct xcan_priv { ...@@ -218,6 +220,7 @@ struct xcan_priv {
struct clk *can_clk; struct clk *can_clk;
struct xcan_devtype_data devtype; struct xcan_devtype_data devtype;
struct phy *transceiver; struct phy *transceiver;
struct reset_control *rstc;
}; };
/* CAN Bittiming constants as per Xilinx CAN specs */ /* CAN Bittiming constants as per Xilinx CAN specs */
...@@ -1799,6 +1802,16 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1799,6 +1802,16 @@ static int xcan_probe(struct platform_device *pdev)
priv->can.do_get_berr_counter = xcan_get_berr_counter; priv->can.do_get_berr_counter = xcan_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_BERR_REPORTING; CAN_CTRLMODE_BERR_REPORTING;
priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
if (IS_ERR(priv->rstc)) {
dev_err(&pdev->dev, "Cannot get CAN reset.\n");
ret = PTR_ERR(priv->rstc);
goto err_free;
}
ret = reset_control_reset(priv->rstc);
if (ret)
goto err_free;
if (devtype->cantype == XAXI_CANFD) { if (devtype->cantype == XAXI_CANFD) {
priv->can.data_bittiming_const = priv->can.data_bittiming_const =
...@@ -1827,7 +1840,7 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1827,7 +1840,7 @@ static int xcan_probe(struct platform_device *pdev)
/* Get IRQ for the device */ /* Get IRQ for the device */
ret = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
if (ret < 0) if (ret < 0)
goto err_free; goto err_reset;
ndev->irq = ret; ndev->irq = ret;
...@@ -1843,21 +1856,21 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1843,21 +1856,21 @@ static int xcan_probe(struct platform_device *pdev)
if (IS_ERR(priv->can_clk)) { if (IS_ERR(priv->can_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk), ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
"device clock not found\n"); "device clock not found\n");
goto err_free; goto err_reset;
} }
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name); priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
if (IS_ERR(priv->bus_clk)) { if (IS_ERR(priv->bus_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk), ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
"bus clock not found\n"); "bus clock not found\n");
goto err_free; goto err_reset;
} }
transceiver = devm_phy_optional_get(&pdev->dev, NULL); transceiver = devm_phy_optional_get(&pdev->dev, NULL);
if (IS_ERR(transceiver)) { if (IS_ERR(transceiver)) {
ret = PTR_ERR(transceiver); ret = PTR_ERR(transceiver);
dev_err_probe(&pdev->dev, ret, "failed to get phy\n"); dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
goto err_free; goto err_reset;
} }
priv->transceiver = transceiver; priv->transceiver = transceiver;
...@@ -1904,6 +1917,8 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1904,6 +1917,8 @@ static int xcan_probe(struct platform_device *pdev)
err_disableclks: err_disableclks:
pm_runtime_put(priv->dev); pm_runtime_put(priv->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
err_reset:
reset_control_assert(priv->rstc);
err_free: err_free:
free_candev(ndev); free_candev(ndev);
err: err:
...@@ -1920,9 +1935,11 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1920,9 +1935,11 @@ static int xcan_probe(struct platform_device *pdev)
static void xcan_remove(struct platform_device *pdev) static void xcan_remove(struct platform_device *pdev)
{ {
struct net_device *ndev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct xcan_priv *priv = netdev_priv(ndev);
unregister_candev(ndev); unregister_candev(ndev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
reset_control_assert(priv->rstc);
free_candev(ndev); free_candev(ndev);
} }
......
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