diff mbox series

[v1] can: mcp251xfd: Enable transceiver using gpio

Message ID 20240806090339.785712-1-quic_anupkulk@quicinc.com (mailing list archive)
State Awaiting Upstream
Delegated to: Netdev Maintainers
Headers show
Series [v1] can: mcp251xfd: Enable transceiver using gpio | expand

Checks

Context Check Description
netdev/tree_selection success Series ignored based on subject

Commit Message

Anup Kulkarni Aug. 6, 2024, 9:03 a.m. UTC
Ensure the CAN transceiver is active during mcp251xfd_open() and
inactive during mcp251xfd_close() by utilizing
mcp251xfd_transceiver_mode(). Adjust GPIO_0 to switch between
NORMAL and STANDBY modes of transceiver.

Signed-off-by: Anup Kulkarni <quic_anupkulk@quicinc.com>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 32 +++++++++++++++++++
 drivers/net/can/spi/mcp251xfd/mcp251xfd.h     |  7 ++++
 2 files changed, 39 insertions(+)

Comments

Christophe JAILLET Aug. 6, 2024, 9:20 a.m. UTC | #1
Le 06/08/2024 à 11:03, Anup Kulkarni a écrit :
> Ensure the CAN transceiver is active during mcp251xfd_open() and
> inactive during mcp251xfd_close() by utilizing
> mcp251xfd_transceiver_mode(). Adjust GPIO_0 to switch between
> NORMAL and STANDBY modes of transceiver.
> 
> Signed-off-by: Anup Kulkarni <quic_anupkulk@quicinc.com>
> ---
>   .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 32 +++++++++++++++++++
>   drivers/net/can/spi/mcp251xfd/mcp251xfd.h     |  7 ++++
>   2 files changed, 39 insertions(+)
> 
> diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
> index 3e7526274e34..3b56dc1721a5 100644
> --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
> +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
> @@ -153,6 +153,25 @@ static inline int mcp251xfd_vdd_disable(const struct mcp251xfd_priv *priv)
>   	return regulator_disable(priv->reg_vdd);
>   }
>   
> +static int
> +mcp251xfd_transceiver_mode(const struct mcp251xfd_priv *priv,
> +			   const enum mcp251xfd_xceiver_mode mode)
> +{
> +	int val, pmode, latch;
> +
> +	if (mode == MCP251XFD_XCVR_NORMAL_MODE) {
> +		pmode = MCP251XFD_REG_IOCON_PM0;
> +		latch = 0;
> +	} else if (mode == MCP251XFD_XCVR_STBY_MODE) {
> +		pmode = MCP251XFD_REG_IOCON_PM0;
> +		latch = MCP251XFD_REG_IOCON_LAT0;
> +	} else {
> +		return -EINVAL;
> +	}
> +	val = (pmode | latch) << priv->transceiver_pin;
> +	return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val);
> +}
> +
>   static inline int
>   mcp251xfd_transceiver_enable(const struct mcp251xfd_priv *priv)
>   {
> @@ -1620,6 +1639,10 @@ static int mcp251xfd_open(struct net_device *ndev)
>   	if (err)
>   		goto out_transceiver_disable;
>   
> +	err = mcp251xfd_transceiver_mode(priv, MCP251XFD_XCVR_NORMAL_MODE);
> +	if (err)
> +		goto out_transceiver_disable;
> +
>   	clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
>   	can_rx_offload_enable(&priv->offload);
>   
> @@ -1668,6 +1691,7 @@ static int mcp251xfd_open(struct net_device *ndev)
>   
>   static int mcp251xfd_stop(struct net_device *ndev)
>   {
> +	int err;
>   	struct mcp251xfd_priv *priv = netdev_priv(ndev);
>   
>   	netif_stop_queue(ndev);
> @@ -1678,6 +1702,9 @@ static int mcp251xfd_stop(struct net_device *ndev)
>   	free_irq(ndev->irq, priv);
>   	destroy_workqueue(priv->wq);
>   	can_rx_offload_disable(&priv->offload);
> +	err = mcp251xfd_transceiver_mode(priv, MCP251XFD_XCVR_STBY_MODE);
> +	if (err)
> +		return err;
>   	mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
>   	mcp251xfd_transceiver_disable(priv);
>   	mcp251xfd_ring_free(priv);
> @@ -2051,6 +2078,11 @@ static int mcp251xfd_probe(struct spi_device *spi)
>   					     "Failed to get clock-frequency!\n");
>   	}
>   
> +	err = device_property_read_u32(&spi->dev, "gpio-transceiver-pin", &priv->transceiver_pin);
> +		if (err)

Hi,

looks like indentation is 1 tab too far.

CJ

> +			return dev_err_probe(&spi->dev, err,
> +					     "Failed to get gpio transceiver pin!\n");
> +
>   	/* Sanity check */
>   	if (freq < MCP251XFD_SYSCLOCK_HZ_MIN ||
>   	    freq > MCP251XFD_SYSCLOCK_HZ_MAX) {
> diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
> index dcbbd2b2fae8..14b086814bdb 100644
> --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
> +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
> @@ -614,6 +614,12 @@ enum mcp251xfd_flags {
>   	__MCP251XFD_FLAGS_SIZE__
>   };
>   
> +enum mcp251xfd_xceiver_mode {
> +	MCP251XFD_XCVR_NORMAL_MODE,
> +	MCP251XFD_XCVR_STBY_MODE,
> +	MCP251XFD_XCVR_MODE_NONE
> +};
> +
>   struct mcp251xfd_priv {
>   	struct can_priv can;
>   	struct can_rx_offload offload;
> @@ -670,6 +676,7 @@ struct mcp251xfd_priv {
>   
>   	struct mcp251xfd_devtype_data devtype_data;
>   	struct can_berr_counter bec;
> +	u32 transceiver_pin;
>   };
>   
>   #define MCP251XFD_IS(_model) \
Przemek Kitszel Aug. 6, 2024, 11:03 a.m. UTC | #2
On 8/6/24 11:03, Anup Kulkarni wrote:
> Ensure the CAN transceiver is active during mcp251xfd_open() and
> inactive during mcp251xfd_close() by utilizing
> mcp251xfd_transceiver_mode(). Adjust GPIO_0 to switch between
> NORMAL and STANDBY modes of transceiver.
> 
> Signed-off-by: Anup Kulkarni <quic_anupkulk@quicinc.com>
> ---
>   .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 32 +++++++++++++++++++
>   drivers/net/can/spi/mcp251xfd/mcp251xfd.h     |  7 ++++
>   2 files changed, 39 insertions(+)
> 
> diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
> index 3e7526274e34..3b56dc1721a5 100644
> --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
> +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
> @@ -153,6 +153,25 @@ static inline int mcp251xfd_vdd_disable(const struct mcp251xfd_priv *priv)
>   	return regulator_disable(priv->reg_vdd);
>   }
>   
> +static int
> +mcp251xfd_transceiver_mode(const struct mcp251xfd_priv *priv,
> +			   const enum mcp251xfd_xceiver_mode mode)
> +{
> +	int val, pmode, latch;
> +
> +	if (mode == MCP251XFD_XCVR_NORMAL_MODE) {
> +		pmode = MCP251XFD_REG_IOCON_PM0;
> +		latch = 0;
> +	} else if (mode == MCP251XFD_XCVR_STBY_MODE) {
> +		pmode = MCP251XFD_REG_IOCON_PM0;
> +		latch = MCP251XFD_REG_IOCON_LAT0;
> +	} else {
> +		return -EINVAL;
> +	}

@pmode is always the same, no need for separate assignment
this if-else chain will be better as an switch statement

> +	val = (pmode | latch) << priv->transceiver_pin;

put a newline here

> +	return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val);
> +}
> +
>   static inline int
>   mcp251xfd_transceiver_enable(const struct mcp251xfd_priv *priv)
>   {
> @@ -1620,6 +1639,10 @@ static int mcp251xfd_open(struct net_device *ndev)
>   	if (err)
>   		goto out_transceiver_disable;
>   
> +	err = mcp251xfd_transceiver_mode(priv, MCP251XFD_XCVR_NORMAL_MODE);
> +	if (err)
> +		goto out_transceiver_disable;
> +
>   	clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
>   	can_rx_offload_enable(&priv->offload);
>   
> @@ -1668,6 +1691,7 @@ static int mcp251xfd_open(struct net_device *ndev)
>   
>   static int mcp251xfd_stop(struct net_device *ndev)
>   {
> +	int err;
>   	struct mcp251xfd_priv *priv = netdev_priv(ndev);
>   
>   	netif_stop_queue(ndev);
> @@ -1678,6 +1702,9 @@ static int mcp251xfd_stop(struct net_device *ndev)
>   	free_irq(ndev->irq, priv);
>   	destroy_workqueue(priv->wq);
>   	can_rx_offload_disable(&priv->offload);
> +	err = mcp251xfd_transceiver_mode(priv, MCP251XFD_XCVR_STBY_MODE);
> +	if (err)
> +		return err;

perhaps it would be better to continue here anyway?

>   	mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
>   	mcp251xfd_transceiver_disable(priv);
>   	mcp251xfd_ring_free(priv);
> @@ -2051,6 +2078,11 @@ static int mcp251xfd_probe(struct spi_device *spi)
>   					     "Failed to get clock-frequency!\n");
>   	}
>   
> +	err = device_property_read_u32(&spi->dev, "gpio-transceiver-pin", &priv->transceiver_pin);
> +		if (err)
> +			return dev_err_probe(&spi->dev, err,
> +					     "Failed to get gpio transceiver pin!\n");
> +

remember to fix it as Christophe J. has pointed out

>   	/* Sanity check */
>   	if (freq < MCP251XFD_SYSCLOCK_HZ_MIN ||
>   	    freq > MCP251XFD_SYSCLOCK_HZ_MAX) {
> diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
> index dcbbd2b2fae8..14b086814bdb 100644
> --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
> +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
> @@ -614,6 +614,12 @@ enum mcp251xfd_flags {
>   	__MCP251XFD_FLAGS_SIZE__
>   };
>   
> +enum mcp251xfd_xceiver_mode {
> +	MCP251XFD_XCVR_NORMAL_MODE,
> +	MCP251XFD_XCVR_STBY_MODE,
> +	MCP251XFD_XCVR_MODE_NONE

no need to add NONE mode if you don't make any use of it,
also the name is not consistent with the other modes

> +};
> +
>   struct mcp251xfd_priv {
>   	struct can_priv can;
>   	struct can_rx_offload offload;
> @@ -670,6 +676,7 @@ struct mcp251xfd_priv {
>   
>   	struct mcp251xfd_devtype_data devtype_data;
>   	struct can_berr_counter bec;
> +	u32 transceiver_pin;
>   };
>   
>   #define MCP251XFD_IS(_model) \
Marc Kleine-Budde Aug. 6, 2024, 8:02 p.m. UTC | #3
On 06.08.2024 14:33:39, Anup Kulkarni wrote:
> Ensure the CAN transceiver is active during mcp251xfd_open() and
> inactive during mcp251xfd_close() by utilizing
> mcp251xfd_transceiver_mode(). Adjust GPIO_0 to switch between
> NORMAL and STANDBY modes of transceiver.

There is still the gpio support patch pending, which I have to review
and test.

https://lore.kernel.org/all/20240522-mcp251xfd-gpio-feature-v3-0-8829970269c5@ew.tq-group.com/

After this has been merged, we can have a look at this patch.

It might actually not be needed anymore, as we can describe a CAN
transceiver switched by a GPIO in the DT. Hopefully we don't run into
some crazy circular dependencies or similar issues.

regards,
Marc
kernel test robot Aug. 7, 2024, 7:47 a.m. UTC | #4
Hi Anup,

kernel test robot noticed the following build warnings:

[auto build test WARNING on mkl-can-next/testing]
[also build test WARNING on net-next/main net/main linus/master v6.11-rc2 next-20240806]
[cannot apply to mani-mhi/mhi-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Anup-Kulkarni/can-mcp251xfd-Enable-transceiver-using-gpio/20240806-175105
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git testing
patch link:    https://lore.kernel.org/r/20240806090339.785712-1-quic_anupkulk%40quicinc.com
patch subject: [PATCH v1] can: mcp251xfd: Enable transceiver using gpio
config: x86_64-buildonly-randconfig-001-20240806 (https://download.01.org/0day-ci/archive/20240807/202408071217.7AvSrhxI-lkp@intel.com/config)
compiler: clang version 18.1.5 (https://github.com/llvm/llvm-project 617a15a9eac96088ae5e9134248d8236e34b91b1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240807/202408071217.7AvSrhxI-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408071217.7AvSrhxI-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c:2081:69: warning: variable 'priv' is uninitialized when used here [-Wuninitialized]
    2081 |         err = device_property_read_u32(&spi->dev, "gpio-transceiver-pin", &priv->transceiver_pin);
         |                                                                            ^~~~
   drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c:2035:29: note: initialize the variable 'priv' to silence this warning
    2035 |         struct mcp251xfd_priv *priv;
         |                                    ^
         |                                     = NULL
   1 warning generated.


vim +/priv +2081 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c

  2031	
  2032	static int mcp251xfd_probe(struct spi_device *spi)
  2033	{
  2034		struct net_device *ndev;
  2035		struct mcp251xfd_priv *priv;
  2036		struct gpio_desc *rx_int;
  2037		struct regulator *reg_vdd, *reg_xceiver;
  2038		struct clk *clk;
  2039		bool pll_enable = false;
  2040		u32 freq = 0;
  2041		int err;
  2042	
  2043		if (!spi->irq)
  2044			return dev_err_probe(&spi->dev, -ENXIO,
  2045					     "No IRQ specified (maybe node \"interrupts-extended\" in DT missing)!\n");
  2046	
  2047		rx_int = devm_gpiod_get_optional(&spi->dev, "microchip,rx-int",
  2048						 GPIOD_IN);
  2049		if (IS_ERR(rx_int))
  2050			return dev_err_probe(&spi->dev, PTR_ERR(rx_int),
  2051					     "Failed to get RX-INT!\n");
  2052	
  2053		reg_vdd = devm_regulator_get_optional(&spi->dev, "vdd");
  2054		if (PTR_ERR(reg_vdd) == -ENODEV)
  2055			reg_vdd = NULL;
  2056		else if (IS_ERR(reg_vdd))
  2057			return dev_err_probe(&spi->dev, PTR_ERR(reg_vdd),
  2058					     "Failed to get VDD regulator!\n");
  2059	
  2060		reg_xceiver = devm_regulator_get_optional(&spi->dev, "xceiver");
  2061		if (PTR_ERR(reg_xceiver) == -ENODEV)
  2062			reg_xceiver = NULL;
  2063		else if (IS_ERR(reg_xceiver))
  2064			return dev_err_probe(&spi->dev, PTR_ERR(reg_xceiver),
  2065					     "Failed to get Transceiver regulator!\n");
  2066	
  2067		clk = devm_clk_get_optional(&spi->dev, NULL);
  2068		if (IS_ERR(clk))
  2069			return dev_err_probe(&spi->dev, PTR_ERR(clk),
  2070					     "Failed to get Oscillator (clock)!\n");
  2071		if (clk) {
  2072			freq = clk_get_rate(clk);
  2073		} else {
  2074			err = device_property_read_u32(&spi->dev, "clock-frequency",
  2075						       &freq);
  2076			if (err)
  2077				return dev_err_probe(&spi->dev, err,
  2078						     "Failed to get clock-frequency!\n");
  2079		}
  2080	
> 2081		err = device_property_read_u32(&spi->dev, "gpio-transceiver-pin", &priv->transceiver_pin);
  2082			if (err)
  2083				return dev_err_probe(&spi->dev, err,
  2084						     "Failed to get gpio transceiver pin!\n");
  2085	
  2086		/* Sanity check */
  2087		if (freq < MCP251XFD_SYSCLOCK_HZ_MIN ||
  2088		    freq > MCP251XFD_SYSCLOCK_HZ_MAX) {
  2089			dev_err(&spi->dev,
  2090				"Oscillator frequency (%u Hz) is too low or high.\n",
  2091				freq);
  2092			return -ERANGE;
  2093		}
  2094	
  2095		if (freq <= MCP251XFD_SYSCLOCK_HZ_MAX / MCP251XFD_OSC_PLL_MULTIPLIER)
  2096			pll_enable = true;
  2097	
  2098		ndev = alloc_candev(sizeof(struct mcp251xfd_priv),
  2099				    MCP251XFD_TX_OBJ_NUM_MAX);
  2100		if (!ndev)
  2101			return -ENOMEM;
  2102	
  2103		SET_NETDEV_DEV(ndev, &spi->dev);
  2104	
  2105		ndev->netdev_ops = &mcp251xfd_netdev_ops;
  2106		ndev->irq = spi->irq;
  2107		ndev->flags |= IFF_ECHO;
  2108	
  2109		priv = netdev_priv(ndev);
  2110		spi_set_drvdata(spi, priv);
  2111		priv->can.clock.freq = freq;
  2112		if (pll_enable)
  2113			priv->can.clock.freq *= MCP251XFD_OSC_PLL_MULTIPLIER;
  2114		priv->can.do_set_mode = mcp251xfd_set_mode;
  2115		priv->can.do_get_berr_counter = mcp251xfd_get_berr_counter;
  2116		priv->can.bittiming_const = &mcp251xfd_bittiming_const;
  2117		priv->can.data_bittiming_const = &mcp251xfd_data_bittiming_const;
  2118		priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
  2119			CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING |
  2120			CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |
  2121			CAN_CTRLMODE_CC_LEN8_DLC;
  2122		set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
  2123		priv->ndev = ndev;
  2124		priv->spi = spi;
  2125		priv->rx_int = rx_int;
  2126		priv->clk = clk;
  2127		priv->pll_enable = pll_enable;
  2128		priv->reg_vdd = reg_vdd;
  2129		priv->reg_xceiver = reg_xceiver;
  2130		priv->devtype_data = *(struct mcp251xfd_devtype_data *)spi_get_device_match_data(spi);
  2131	
  2132		/* Errata Reference:
  2133		 * mcp2517fd: DS80000792C 5., mcp2518fd: DS80000789E 4.,
  2134		 * mcp251863: DS80000984A 4.
  2135		 *
  2136		 * The SPI can write corrupted data to the RAM at fast SPI
  2137		 * speeds:
  2138		 *
  2139		 * Simultaneous activity on the CAN bus while writing data to
  2140		 * RAM via the SPI interface, with high SCK frequency, can
  2141		 * lead to corrupted data being written to RAM.
  2142		 *
  2143		 * Fix/Work Around:
  2144		 * Ensure that FSCK is less than or equal to 0.85 *
  2145		 * (FSYSCLK/2).
  2146		 *
  2147		 * Known good combinations are:
  2148		 *
  2149		 * MCP	ext-clk	SoC			SPI			SPI-clk		max-clk	parent-clk	config
  2150		 *
  2151		 * 2518	20 MHz	allwinner,sun8i-h3	allwinner,sun8i-h3-spi	 8333333 Hz	 83.33%	600000000 Hz	assigned-clocks = <&ccu CLK_SPIx>
  2152		 * 2518	40 MHz	allwinner,sun8i-h3	allwinner,sun8i-h3-spi	16666667 Hz	 83.33%	600000000 Hz	assigned-clocks = <&ccu CLK_SPIx>
  2153		 * 2517	40 MHz	atmel,sama5d27		atmel,at91rm9200-spi	16400000 Hz	 82.00%	 82000000 Hz	default
  2154		 * 2518	40 MHz	atmel,sama5d27		atmel,at91rm9200-spi	16400000 Hz	 82.00%	 82000000 Hz	default
  2155		 * 2518	40 MHz	fsl,imx6dl		fsl,imx51-ecspi		15000000 Hz	 75.00%	 30000000 Hz	default
  2156		 * 2517	20 MHz	fsl,imx8mm		fsl,imx51-ecspi		 8333333 Hz	 83.33%	 16666667 Hz	assigned-clocks = <&clk IMX8MM_CLK_ECSPIx_ROOT>
  2157		 *
  2158		 */
  2159		priv->spi_max_speed_hz_orig = spi->max_speed_hz;
  2160		priv->spi_max_speed_hz_slow = min(spi->max_speed_hz,
  2161						  freq / 2 / 1000 * 850);
  2162		if (priv->pll_enable)
  2163			priv->spi_max_speed_hz_fast = min(spi->max_speed_hz,
  2164							  freq *
  2165							  MCP251XFD_OSC_PLL_MULTIPLIER /
  2166							  2 / 1000 * 850);
  2167		else
  2168			priv->spi_max_speed_hz_fast = priv->spi_max_speed_hz_slow;
  2169		spi->max_speed_hz = priv->spi_max_speed_hz_slow;
  2170		spi->bits_per_word = 8;
  2171		spi->rt = true;
  2172		err = spi_setup(spi);
  2173		if (err)
  2174			goto out_free_candev;
  2175	
  2176		err = mcp251xfd_regmap_init(priv);
  2177		if (err)
  2178			goto out_free_candev;
  2179	
  2180		err = can_rx_offload_add_manual(ndev, &priv->offload,
  2181						MCP251XFD_NAPI_WEIGHT);
  2182		if (err)
  2183			goto out_free_candev;
  2184	
  2185		err = mcp251xfd_register(priv);
  2186		if (err) {
  2187			dev_err_probe(&spi->dev, err, "Failed to detect %s.\n",
  2188				      mcp251xfd_get_model_str(priv));
  2189			goto out_can_rx_offload_del;
  2190		}
  2191	
  2192		return 0;
  2193	
  2194	out_can_rx_offload_del:
  2195		can_rx_offload_del(&priv->offload);
  2196	out_free_candev:
  2197		spi->max_speed_hz = priv->spi_max_speed_hz_orig;
  2198	
  2199		free_candev(ndev);
  2200	
  2201		return err;
  2202	}
  2203
Anup Kulkarni Sept. 9, 2024, 11:20 a.m. UTC | #5
Thanks Marc, for pointing to the thread.
I have internally validated the given patch, and it works fine for me.
Hence we intend to add only DT related change.

Do you plan to merge it in next release or any time by which I can expect the patch to be merged?
Since my DT change is dependent on the given patch. 

Please let me know if you need any support/help in any further validation of the patch.

regards,
Anup

On 8/7/2024 1:32 AM, Marc Kleine-Budde wrote:
> On 06.08.2024 14:33:39, Anup Kulkarni wrote:
>> Ensure the CAN transceiver is active during mcp251xfd_open() and
>> inactive during mcp251xfd_close() by utilizing
>> mcp251xfd_transceiver_mode(). Adjust GPIO_0 to switch between
>> NORMAL and STANDBY modes of transceiver.
> 
> There is still the gpio support patch pending, which I have to review
> and test.
> 
> https://lore.kernel.org/all/20240522-mcp251xfd-gpio-feature-v3-0-8829970269c5@ew.tq-group.com/
> 
> After this has been merged, we can have a look at this patch.
> 
> It might actually not be needed anymore, as we can describe a CAN
> transceiver switched by a GPIO in the DT. Hopefully we don't run into
> some crazy circular dependencies or similar issues.
> 
> regards,
> Marc
>
diff mbox series

Patch

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 3e7526274e34..3b56dc1721a5 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -153,6 +153,25 @@  static inline int mcp251xfd_vdd_disable(const struct mcp251xfd_priv *priv)
 	return regulator_disable(priv->reg_vdd);
 }
 
+static int
+mcp251xfd_transceiver_mode(const struct mcp251xfd_priv *priv,
+			   const enum mcp251xfd_xceiver_mode mode)
+{
+	int val, pmode, latch;
+
+	if (mode == MCP251XFD_XCVR_NORMAL_MODE) {
+		pmode = MCP251XFD_REG_IOCON_PM0;
+		latch = 0;
+	} else if (mode == MCP251XFD_XCVR_STBY_MODE) {
+		pmode = MCP251XFD_REG_IOCON_PM0;
+		latch = MCP251XFD_REG_IOCON_LAT0;
+	} else {
+		return -EINVAL;
+	}
+	val = (pmode | latch) << priv->transceiver_pin;
+	return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val);
+}
+
 static inline int
 mcp251xfd_transceiver_enable(const struct mcp251xfd_priv *priv)
 {
@@ -1620,6 +1639,10 @@  static int mcp251xfd_open(struct net_device *ndev)
 	if (err)
 		goto out_transceiver_disable;
 
+	err = mcp251xfd_transceiver_mode(priv, MCP251XFD_XCVR_NORMAL_MODE);
+	if (err)
+		goto out_transceiver_disable;
+
 	clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
 	can_rx_offload_enable(&priv->offload);
 
@@ -1668,6 +1691,7 @@  static int mcp251xfd_open(struct net_device *ndev)
 
 static int mcp251xfd_stop(struct net_device *ndev)
 {
+	int err;
 	struct mcp251xfd_priv *priv = netdev_priv(ndev);
 
 	netif_stop_queue(ndev);
@@ -1678,6 +1702,9 @@  static int mcp251xfd_stop(struct net_device *ndev)
 	free_irq(ndev->irq, priv);
 	destroy_workqueue(priv->wq);
 	can_rx_offload_disable(&priv->offload);
+	err = mcp251xfd_transceiver_mode(priv, MCP251XFD_XCVR_STBY_MODE);
+	if (err)
+		return err;
 	mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
 	mcp251xfd_transceiver_disable(priv);
 	mcp251xfd_ring_free(priv);
@@ -2051,6 +2078,11 @@  static int mcp251xfd_probe(struct spi_device *spi)
 					     "Failed to get clock-frequency!\n");
 	}
 
+	err = device_property_read_u32(&spi->dev, "gpio-transceiver-pin", &priv->transceiver_pin);
+		if (err)
+			return dev_err_probe(&spi->dev, err,
+					     "Failed to get gpio transceiver pin!\n");
+
 	/* Sanity check */
 	if (freq < MCP251XFD_SYSCLOCK_HZ_MIN ||
 	    freq > MCP251XFD_SYSCLOCK_HZ_MAX) {
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
index dcbbd2b2fae8..14b086814bdb 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
@@ -614,6 +614,12 @@  enum mcp251xfd_flags {
 	__MCP251XFD_FLAGS_SIZE__
 };
 
+enum mcp251xfd_xceiver_mode {
+	MCP251XFD_XCVR_NORMAL_MODE,
+	MCP251XFD_XCVR_STBY_MODE,
+	MCP251XFD_XCVR_MODE_NONE
+};
+
 struct mcp251xfd_priv {
 	struct can_priv can;
 	struct can_rx_offload offload;
@@ -670,6 +676,7 @@  struct mcp251xfd_priv {
 
 	struct mcp251xfd_devtype_data devtype_data;
 	struct can_berr_counter bec;
+	u32 transceiver_pin;
 };
 
 #define MCP251XFD_IS(_model) \