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 |
Context | Check | Description |
---|---|---|
netdev/tree_selection | success | Series ignored based on subject |
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) \
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) \
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
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
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 --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) \
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(+)