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

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.com


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parents 22d8e8d6 25000fc7
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -46,6 +46,9 @@ properties:
    $ref: /schemas/types.yaml#/definitions/uint32
    description: CAN Tx mailbox buffer count (CAN FD)

  resets:
    maxItems: 1

required:
  - compatible
  - reg
+21 −4
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/can/error.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>

#define DRIVER_NAME	"xilinx_can"

@@ -200,6 +201,7 @@ struct xcan_devtype_data {
 * @can_clk:			Pointer to struct clk
 * @devtype:			Device type specific constants
 * @transceiver:		Optional pointer to associated CAN transceiver
 * @rstc:			Pointer to reset control
 */
struct xcan_priv {
	struct can_priv can;
@@ -218,6 +220,7 @@ struct xcan_priv {
	struct clk *can_clk;
	struct xcan_devtype_data devtype;
	struct phy *transceiver;
	struct reset_control *rstc;
};

/* CAN Bittiming constants as per Xilinx CAN specs */
@@ -1799,6 +1802,16 @@ static int xcan_probe(struct platform_device *pdev)
	priv->can.do_get_berr_counter = xcan_get_berr_counter;
	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
					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) {
		priv->can.data_bittiming_const =
@@ -1827,7 +1840,7 @@ static int xcan_probe(struct platform_device *pdev)
	/* Get IRQ for the device */
	ret = platform_get_irq(pdev, 0);
	if (ret < 0)
		goto err_free;
		goto err_reset;

	ndev->irq = ret;

@@ -1843,21 +1856,21 @@ static int xcan_probe(struct platform_device *pdev)
	if (IS_ERR(priv->can_clk)) {
		ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
				    "device clock not found\n");
		goto err_free;
		goto err_reset;
	}

	priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
	if (IS_ERR(priv->bus_clk)) {
		ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
				    "bus clock not found\n");
		goto err_free;
		goto err_reset;
	}

	transceiver = devm_phy_optional_get(&pdev->dev, NULL);
	if (IS_ERR(transceiver)) {
		ret = PTR_ERR(transceiver);
		dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
		goto err_free;
		goto err_reset;
	}
	priv->transceiver = transceiver;

@@ -1904,6 +1917,8 @@ static int xcan_probe(struct platform_device *pdev)
err_disableclks:
	pm_runtime_put(priv->dev);
	pm_runtime_disable(&pdev->dev);
err_reset:
	reset_control_assert(priv->rstc);
err_free:
	free_candev(ndev);
err:
@@ -1920,9 +1935,11 @@ static int xcan_probe(struct platform_device *pdev)
static void xcan_remove(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);
	struct xcan_priv *priv = netdev_priv(ndev);

	unregister_candev(ndev);
	pm_runtime_disable(&pdev->dev);
	reset_control_assert(priv->rstc);
	free_candev(ndev);
}