[PATCH 1/3] can: mcp251xfd: automatic transceiver standby control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Added a device tree option xceiver_standby, which if present will cause GPIO to be placed in GPIO mode, with automatic transceiver control enabled.

Added a flag to the summary message printed following successful initialisation, to help debug it being enabled.

Have checked with a logic analyser that GPIO0 transitions from high to low as expected when the interface is brought up, and low to high when taken down.

I've renamed mcp251xfd_chip_rx_int_disable to mcp251xfd_chip_configure_gpio trying to reflect its new role, considering that it doesn't just manage the rx interrupt anymore. Perhaps separate functions updating the bits independently might be better?

Signed-off-by: Phil Greenland <phil@xxxxxxxxxxxxxxx>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 56 ++++++++++---------
 drivers/net/can/spi/mcp251xfd/mcp251xfd.h     |  2 +
 2 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index e16dc482f..9ee2c69c5 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -801,40 +801,37 @@ static int mcp251xfd_set_bittiming(const struct mcp251xfd_priv *priv)
 	return regmap_write(priv->map_reg, MCP251XFD_REG_TDC, val);
 }
 
-static int mcp251xfd_chip_rx_int_enable(const struct mcp251xfd_priv *priv)
+static int mcp251xfd_chip_configure_gpio(const struct mcp251xfd_priv *priv,
+					 bool rx_int_enable)
 {
-	u32 val;
-
-	if (!priv->rx_int)
-		return 0;
+	u32 val = 0;
 
 	/* Configure GPIOs:
-	 * - PIN0: GPIO Input
-	 * - PIN1: GPIO Input/RX Interrupt
+	 * - PIN0: GPIO Input/Transceiver standby (if enabled)
+	 * - PIN1: GPIO Input/RX Interrupt (if enabled)
 	 *
 	 * PIN1 must be Input, otherwise there is a glitch on the
 	 * rx-INT line. It happens between setting the PIN as output
 	 * (in the first byte of the SPI transfer) and configuring the
 	 * PIN as interrupt (in the last byte of the SPI transfer).
 	 */
-	val = MCP251XFD_REG_IOCON_PM0 | MCP251XFD_REG_IOCON_TRIS1 |
-		MCP251XFD_REG_IOCON_TRIS0;
-	return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val);
-}
+	if (priv->xceiver_standby) {
+		/* Transceiver control enabled, place in GPIO mode with auto transceiver standby */
+		val |= MCP251XFD_REG_IOCON_PM0 | MCP251XFD_REG_IOCON_XSTBYEN;
+	} else {
+		/* Transceiver control disabled, place in GPIO mode and tristate */
+		val |= MCP251XFD_REG_IOCON_PM0 | MCP251XFD_REG_IOCON_TRIS0;
+	}
 
-static int mcp251xfd_chip_rx_int_disable(const struct mcp251xfd_priv *priv)
-{
-	u32 val;
+	if (priv->rx_int && rx_int_enable) {
+		/* INT1 enabled, tristate GPIO1 (overridden by INT enable) */
+		val |= MCP251XFD_REG_IOCON_TRIS1;
 
-	if (!priv->rx_int)
-		return 0;
+	} else {
+		/* INT1 disabled, place in GPIO mode and tristate */
+		val |= MCP251XFD_REG_IOCON_PM1 | MCP251XFD_REG_IOCON_TRIS1;
+	}
 
-	/* Configure GPIOs:
-	 * - PIN0: GPIO Input
-	 * - PIN1: GPIO Input
-	 */
-	val = MCP251XFD_REG_IOCON_PM1 | MCP251XFD_REG_IOCON_PM0 |
-		MCP251XFD_REG_IOCON_TRIS1 | MCP251XFD_REG_IOCON_TRIS0;
 	return regmap_write(priv->map_reg, MCP251XFD_REG_IOCON, val);
 }
 
@@ -1070,7 +1067,7 @@ static int mcp251xfd_chip_stop(struct mcp251xfd_priv *priv,
 	priv->can.state = state;
 
 	mcp251xfd_chip_interrupts_disable(priv);
-	mcp251xfd_chip_rx_int_disable(priv);
+	mcp251xfd_chip_configure_gpio(priv, false);
 	return mcp251xfd_chip_set_mode(priv, MCP251XFD_REG_CON_MODE_SLEEP);
 }
 
@@ -1090,7 +1087,8 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
 	if (err)
 		goto out_chip_stop;
 
-	err = mcp251xfd_chip_rx_int_enable(priv);
+	/* enable rx interrupt */
+	err = mcp251xfd_chip_configure_gpio(priv, true);
 	if (err)
 		goto out_chip_stop;
 
@@ -2645,7 +2643,8 @@ static int mcp251xfd_register_check_rx_int(struct mcp251xfd_priv *priv)
 	if (!priv->rx_int)
 		return 0;
 
-	err = mcp251xfd_chip_rx_int_enable(priv);
+	/* enable rx interrupt */
+	err = mcp251xfd_chip_configure_gpio(priv, true);
 	if (err)
 		return err;
 
@@ -2654,7 +2653,8 @@ static int mcp251xfd_register_check_rx_int(struct mcp251xfd_priv *priv)
 	 */
 	rx_pending = gpiod_get_value_cansleep(priv->rx_int);
 
-	err = mcp251xfd_chip_rx_int_disable(priv);
+	/* disable rx interrupt */
+	err = mcp251xfd_chip_configure_gpio(priv, false);
 	if (err)
 		return err;
 
@@ -2724,11 +2724,12 @@ mcp251xfd_register_done(const struct mcp251xfd_priv *priv)
 		return err;
 
 	netdev_info(priv->ndev,
-		    "%s rev%lu.%lu (%cRX_INT %cMAB_NO_WARN %cCRC_REG %cCRC_RX %cCRC_TX %cECC %cHD c:%u.%02uMHz m:%u.%02uMHz r:%u.%02uMHz e:%u.%02uMHz) successfully initialized.\n",
+		    "%s rev%lu.%lu (%cRX_INT %cXCVR_STBY %cMAB_NO_WARN %cCRC_REG %cCRC_RX %cCRC_TX %cECC %cHD c:%u.%02uMHz m:%u.%02uMHz r:%u.%02uMHz e:%u.%02uMHz) successfully initialized.\n",
 		    mcp251xfd_get_model_str(priv),
 		    FIELD_GET(MCP251XFD_REG_DEVID_ID_MASK, dev_id),
 		    FIELD_GET(MCP251XFD_REG_DEVID_REV_MASK, dev_id),
 		    priv->rx_int ? '+' : '-',
+			priv->xceiver_standby ? '+' : '-',
 		    MCP251XFD_QUIRK_ACTIVE(MAB_NO_WARN),
 		    MCP251XFD_QUIRK_ACTIVE(CRC_REG),
 		    MCP251XFD_QUIRK_ACTIVE(CRC_RX),
@@ -2948,6 +2949,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
 	priv->clk = clk;
 	priv->reg_vdd = reg_vdd;
 	priv->reg_xceiver = reg_xceiver;
+	priv->xceiver_standby = device_property_read_bool(&spi->dev, "xceiver_standby");
 
 	match = device_get_match_data(&spi->dev);
 	if (match)
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
index 0f322daba..ad658faa2 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
@@ -612,6 +612,8 @@ struct mcp251xfd_priv {
 
 	struct mcp251xfd_devtype_data devtype_data;
 	struct can_berr_counter bec;
+
+	bool xceiver_standby;
 };
 
 #define MCP251XFD_IS(_model) \
-- 
2.25.1




[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux