From: Viken Dadhaniya Date: Sat, 21 Mar 2026 13:50:31 +0000 (+0530) Subject: can: mcp251xfd: add support for XSTBYEN transceiver standby control X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ae20301b6119257f533332836c46d8e8824433dd;p=thirdparty%2Fkernel%2Flinux.git can: mcp251xfd: add support for XSTBYEN transceiver standby control The MCP251xFD has a dedicated transceiver standby control function on the INT0/GPIO0/XSTBY pin, controlled by the XSTBYEN bit in IOCON. When enabled, the hardware automatically manages the transceiver standby state: the pin is driven low when the controller is active and high when it enters Sleep mode. Enable this feature when the 'microchip,xstbyen' device tree property is present. Signed-off-by: Viken Dadhaniya Link: https://patch.msgid.link/20260321135031.3107408-3-viken.dadhaniya@oss.qualcomm.com Signed-off-by: Marc Kleine-Budde --- diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index 9c86df08c2c53..92a86083c8962 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -764,6 +764,31 @@ static void mcp251xfd_chip_stop(struct mcp251xfd_priv *priv, mcp251xfd_chip_set_mode(priv, MCP251XFD_REG_CON_MODE_CONFIG); } +static int mcp251xfd_chip_xstbyen_enable(const struct mcp251xfd_priv *priv) +{ + /* Configure the INT0/GPIO0/XSTBY pin as transceiver standby control: + * + * - XSTBYEN=1: route the pin to the transceiver standby function + * - TRIS0=0: set output direction; the reset default is 1 (input), + * which leaves the pin floating HIGH and keeps the + * transceiver in standby regardless of XSTBYEN + * - LAT0=0: drive pin LOW => transceiver active (not in standby) + * + * All three bits are included in the mask; only XSTBYEN is set in + * val, so TRIS0 and LAT0 are cleared to 0 atomically. + * + * Pin behaviour by mode: + * - Config mode: controlled by LAT0 (LAT0=0 => LOW => active) + * - Normal mode: hardware drives pin LOW (active) + * - Sleep mode: hardware drives pin HIGH (standby) + */ + return regmap_update_bits(priv->map_reg, MCP251XFD_REG_IOCON, + MCP251XFD_REG_IOCON_XSTBYEN | + MCP251XFD_REG_IOCON_TRIS0 | + MCP251XFD_REG_IOCON_LAT0, + MCP251XFD_REG_IOCON_XSTBYEN); +} + static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv) { int err; @@ -796,6 +821,12 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv) priv->can.state = CAN_STATE_ERROR_ACTIVE; + if (priv->xstbyen) { + err = mcp251xfd_chip_xstbyen_enable(priv); + if (err) + goto out_chip_stop; + } + err = mcp251xfd_chip_set_normal_mode(priv); if (err) goto out_chip_stop; @@ -1805,6 +1836,11 @@ static int mcp251xfd_gpio_request(struct gpio_chip *chip, unsigned int offset) u32 pin_mask = MCP251XFD_REG_IOCON_PM(offset); int ret; + if (priv->xstbyen && offset == 0) { + netdev_err(priv->ndev, "Can't use GPIO 0 with XSTBYEN!\n"); + return -EINVAL; + } + if (priv->rx_int && offset == 1) { netdev_err(priv->ndev, "Can't use GPIO 1 with RX-INT!\n"); return -EINVAL; @@ -2271,6 +2307,7 @@ static int mcp251xfd_probe(struct spi_device *spi) priv->pll_enable = pll_enable; priv->reg_vdd = reg_vdd; priv->reg_xceiver = reg_xceiver; + priv->xstbyen = device_property_present(&spi->dev, "microchip,xstbyen"); priv->devtype_data = *(struct mcp251xfd_devtype_data *)spi_get_device_match_data(spi); /* Errata Reference: diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h index 085d7101e595e..d3f4704e26780 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h @@ -672,6 +672,7 @@ struct mcp251xfd_priv { struct gpio_desc *rx_int; struct clk *clk; bool pll_enable; + bool xstbyen; struct regulator *reg_vdd; struct regulator *reg_xceiver;