linux-can.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support
@ 2021-04-25 12:23 Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 01/14] can: mcp251xfd: mcp251xfd_irq(): stop timestamping worker in case error in IRQ Marc Kleine-Budde
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp, Magnus Aagaard Sørensen

Hello,

this series first adds some cleanups to the mcp251xfd driver and then
adds PLL support. The PLL support is based on a patchset by Magnus
Aagaard Sørensen.

regards,
Marc




^ permalink raw reply	[flat|nested] 15+ messages in thread

* [can-next-rfc 01/14] can: mcp251xfd: mcp251xfd_irq(): stop timestamping worker in case error in IRQ
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 02/14] can: mcp251xfd: mcp251xfd_tef_obj_read(): fix typo in error message Marc Kleine-Budde
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

In case an error occurred in the IRQ handler, the chip status is
dumped via devcoredump and all IRQs are disabled, but the chip stays
powered for further analysis.

The chip is in an undefined state and will not receive any CAN frames,
so shut down the timestamping worker, which reads the TBC register
regularly, too. This avoids any CRC read error messages if there is a
communication problem with the chip.

Fixes: efd8d98dfb90 ("can: mcp251xfd: add HW timestamp infrastructure")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 970dc570e7a5..f139d04e89d8 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -2300,6 +2300,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
 		   err, priv->regs_status.intf);
 	mcp251xfd_dump(priv);
 	mcp251xfd_chip_interrupts_disable(priv);
+	mcp251xfd_timestamp_stop(priv);
 
 	return handled;
 }

base-commit: b2f0ca00e6b34bd57c9298a869ea133699e8ec39
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 02/14] can: mcp251xfd: mcp251xfd_tef_obj_read(): fix typo in error message
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 01/14] can: mcp251xfd: mcp251xfd_irq(): stop timestamping worker in case error in IRQ Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 03/14] can: mcp251xfd: mcp251xfd_regmap_crc_read(): ignore CRC error only if solely OSC register is read Marc Kleine-Budde
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch fixes a typo in the error message in
mcp251xfd_tef_obj_read(), if trying to read too many objects.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index f139d04e89d8..1d267dfedead 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -1336,7 +1336,7 @@ mcp251xfd_tef_obj_read(const struct mcp251xfd_priv *priv,
 	     len > tx_ring->obj_num ||
 	     offset + len > tx_ring->obj_num)) {
 		netdev_err(priv->ndev,
-			   "Trying to read to many TEF objects (max=%d, offset=%d, len=%d).\n",
+			   "Trying to read too many TEF objects (max=%d, offset=%d, len=%d).\n",
 			   tx_ring->obj_num, offset, len);
 		return -ERANGE;
 	}
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 03/14] can: mcp251xfd: mcp251xfd_regmap_crc_read(): ignore CRC error only if solely OSC register is read
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 01/14] can: mcp251xfd: mcp251xfd_irq(): stop timestamping worker in case error in IRQ Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 02/14] can: mcp251xfd: mcp251xfd_tef_obj_read(): fix typo in error message Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 04/14] can: mcp251xfd: mcp251xfd_reg_invalid(): rename from mcp251xfd_osc_invalid() Marc Kleine-Budde
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

MCP251XFD_REG_OSC is the first ever reg we read from. The chip may be
in deep sleep and the SPI transfer (i.e. the assertion of the CS) will
wake the chip up. This takes about 3ms. The CRC of this transfer is
wrong, or there isn't a chip at all, in this case the CRC will be
wrong, too. The driver ignores the CRC error and returns the read data
to the caller.

To avoid any confusion, this patch changes the
mcp251xfd_regmap_crc_read() function to only ignore the CRC error if
solely the OSC register is read. So when reading multiple registers at
once the CRC is returned.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
index 297491516a26..e026247812aa 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
@@ -369,7 +369,7 @@ mcp251xfd_regmap_crc_read(void *context,
 		 * to the caller. It will take care of both cases.
 		 *
 		 */
-		if (reg == MCP251XFD_REG_OSC) {
+		if (reg == MCP251XFD_REG_OSC && val_len == sizeof(__le32)) {
 			err = 0;
 			goto out;
 		}
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 04/14] can: mcp251xfd: mcp251xfd_reg_invalid(): rename from mcp251xfd_osc_invalid()
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (2 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 03/14] can: mcp251xfd: mcp251xfd_regmap_crc_read(): ignore CRC error only if solely OSC register is read Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 05/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): factor out into separate function Marc Kleine-Budde
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch renames mcp251xfd_osc_invalid() to mcp251xfd_reg_invalid(),
as it will be used for other registers than the "osc" register in a
later patch.

This patch also moves this function to more towards the beginning of
the file, to be available for other functions, too.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 1d267dfedead..45850521000c 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -504,6 +504,11 @@ static int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
 	return 0;
 }
 
+static inline bool mcp251xfd_reg_invalid(u32 reg)
+{
+	return reg == 0x0 || reg == 0xffffffff;
+}
+
 static inline int
 mcp251xfd_chip_get_mode(const struct mcp251xfd_priv *priv, u8 *mode)
 {
@@ -567,11 +572,6 @@ mcp251xfd_chip_set_mode_nowait(const struct mcp251xfd_priv *priv,
 	return __mcp251xfd_chip_set_mode(priv, mode_req, true);
 }
 
-static inline bool mcp251xfd_osc_invalid(u32 reg)
-{
-	return reg == 0x0 || reg == 0xffffffff;
-}
-
 static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv)
 {
 	u32 osc, osc_reference, osc_mask;
@@ -600,7 +600,7 @@ static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv)
 				       (osc & osc_mask) == osc_reference,
 				       MCP251XFD_OSC_STAB_SLEEP_US,
 				       MCP251XFD_OSC_STAB_TIMEOUT_US);
-	if (mcp251xfd_osc_invalid(osc)) {
+	if (mcp251xfd_reg_invalid(osc)) {
 		netdev_err(priv->ndev,
 			   "Failed to detect %s (osc=0x%08x).\n",
 			   mcp251xfd_get_model_str(priv), osc);
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 05/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): factor out into separate function
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (3 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 04/14] can: mcp251xfd: mcp251xfd_reg_invalid(): rename from mcp251xfd_osc_invalid() Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 06/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): improve chip detection and error handling Marc Kleine-Budde
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch factors out mcp251xfd_chip_wait_for_osc_ready() into a
separate function, it will be used in several places in the next
patches.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 45 +++++++++++--------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 45850521000c..c7c6d07ac175 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -572,6 +572,32 @@ mcp251xfd_chip_set_mode_nowait(const struct mcp251xfd_priv *priv,
 	return __mcp251xfd_chip_set_mode(priv, mode_req, true);
 }
 
+static int
+mcp251xfd_chip_wait_for_osc_ready(const struct mcp251xfd_priv *priv,
+				  u32 osc_reference, u32 osc_mask)
+{
+	u32 osc;
+	int err;
+
+	err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_OSC, osc,
+				       (osc & osc_mask) == osc_reference,
+				       MCP251XFD_OSC_STAB_SLEEP_US,
+				       MCP251XFD_OSC_STAB_TIMEOUT_US);
+	if (mcp251xfd_reg_invalid(osc)) {
+		netdev_err(priv->ndev,
+			   "Failed to detect %s (osc=0x%08x).\n",
+			   mcp251xfd_get_model_str(priv), osc);
+		return -ENODEV;
+	} else if (err == -ETIMEDOUT) {
+		netdev_err(priv->ndev,
+			   "Timeout waiting for Oscillator Ready (osc=0x%08x, osc_reference=0x%08x)\n",
+			   osc, osc_reference);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv)
 {
 	u32 osc, osc_reference, osc_mask;
@@ -595,24 +621,7 @@ static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv)
 	if (err)
 		return err;
 
-	/* Wait for "Oscillator Ready" bit */
-	err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_OSC, osc,
-				       (osc & osc_mask) == osc_reference,
-				       MCP251XFD_OSC_STAB_SLEEP_US,
-				       MCP251XFD_OSC_STAB_TIMEOUT_US);
-	if (mcp251xfd_reg_invalid(osc)) {
-		netdev_err(priv->ndev,
-			   "Failed to detect %s (osc=0x%08x).\n",
-			   mcp251xfd_get_model_str(priv), osc);
-		return -ENODEV;
-	} else if (err == -ETIMEDOUT) {
-		netdev_err(priv->ndev,
-			   "Timeout waiting for Oscillator Ready (osc=0x%08x, osc_reference=0x%08x)\n",
-			   osc, osc_reference);
-		return -ETIMEDOUT;
-	}
-
-	return err;
+	return mcp251xfd_chip_wait_for_osc_ready(priv, osc_reference, osc_mask);
 }
 
 static int mcp251xfd_chip_softreset_do(const struct mcp251xfd_priv *priv)
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 06/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): improve chip detection and error handling
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (4 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 05/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): factor out into separate function Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 07/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): prepare for PLL support Marc Kleine-Budde
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

The function mcp251xfd_chip_wait_for_osc_ready() polls the Oscillator
Control Register for the oscillator to get ready.

This is the first register the driver reads from. Reading implausible
values (all bits set or unset) can be caused by the chip starting up
after power on, waking up after sleep, or by the chip not being preset
at all. Add check for implausible register content
mcp251xfd_reg_invalid() to the regmap_read_poll_timeout() loop.

In case of a regmap_read_poll_timeout() returns a fatal error (and not
a timeout), forward it to the caller.

As mcp251xfd_chip_wait_for_osc_ready() will be called after the probe
function has finished, (currently during ifup), move error message
about failed chip detection from there into the probe function.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 24 ++++++++++++-------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index c7c6d07ac175..0b7a4e317890 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -580,22 +580,25 @@ mcp251xfd_chip_wait_for_osc_ready(const struct mcp251xfd_priv *priv,
 	int err;
 
 	err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_OSC, osc,
+				       !mcp251xfd_reg_invalid(osc) &&
 				       (osc & osc_mask) == osc_reference,
 				       MCP251XFD_OSC_STAB_SLEEP_US,
 				       MCP251XFD_OSC_STAB_TIMEOUT_US);
+	if (err != -ETIMEDOUT)
+		return err;
+
 	if (mcp251xfd_reg_invalid(osc)) {
 		netdev_err(priv->ndev,
-			   "Failed to detect %s (osc=0x%08x).\n",
-			   mcp251xfd_get_model_str(priv), osc);
+			   "Failed to read Oscillator Configuration Register (osc=0x%08x).\n",
+			   osc);
 		return -ENODEV;
-	} else if (err == -ETIMEDOUT) {
-		netdev_err(priv->ndev,
-			   "Timeout waiting for Oscillator Ready (osc=0x%08x, osc_reference=0x%08x)\n",
-			   osc, osc_reference);
-		return -ETIMEDOUT;
 	}
 
-	return 0;
+	netdev_err(priv->ndev,
+		   "Timeout waiting for Oscillator Ready (osc=0x%08x, osc_reference=0x%08x)\n",
+		   osc, osc_reference);
+
+	return -ETIMEDOUT;
 }
 
 static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv)
@@ -2995,8 +2998,11 @@ static int mcp251xfd_probe(struct spi_device *spi)
 		goto out_free_candev;
 
 	err = mcp251xfd_register(priv);
-	if (err)
+	if (err) {
+		dev_err_probe(&spi->dev, err, "Failed to detect %s.\n",
+			      mcp251xfd_get_model_str(priv));
 		goto out_free_candev;
+	}
 
 	return 0;
 
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 07/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): prepare for PLL support
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (5 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 06/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): improve chip detection and error handling Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 08/14] can: mcp251xfd: mcp251xfd_chip_softreset_check(): wait for OSC ready before accessing chip Marc Kleine-Budde
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

The function mcp251xfd_chip_wait_for_osc_ready() polls the Oscillator
Control Register for the oscillator to get ready. By passing the
appropriate parameters (osc_reference and osc_mask) it can also poll
for PLL ready.

This patch adjusts the error message if the Oscillator and/or PLL fail
to get ready.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 25 +++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 0b7a4e317890..2579b5aa1710 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -114,6 +114,22 @@ static const char *mcp251xfd_get_mode_str(const u8 mode)
 	return "<unknown>";
 }
 
+static const char *
+mcp251xfd_get_osc_str(const u32 osc, const u32 osc_reference)
+{
+	switch (~osc & osc_reference &
+		(MCP251XFD_REG_OSC_OSCRDY | MCP251XFD_REG_OSC_PLLRDY)) {
+	case MCP251XFD_REG_OSC_PLLRDY:
+		return "PLL";
+	case MCP251XFD_REG_OSC_OSCRDY:
+		return "Oscillator";
+	case MCP251XFD_REG_OSC_PLLRDY | MCP251XFD_REG_OSC_OSCRDY:
+		return "Oscillator/PLL";
+	}
+
+	return "<unknown>";
+}
+
 static inline int mcp251xfd_vdd_enable(const struct mcp251xfd_priv *priv)
 {
 	if (!priv->reg_vdd)
@@ -595,8 +611,9 @@ mcp251xfd_chip_wait_for_osc_ready(const struct mcp251xfd_priv *priv,
 	}
 
 	netdev_err(priv->ndev,
-		   "Timeout waiting for Oscillator Ready (osc=0x%08x, osc_reference=0x%08x)\n",
-		   osc, osc_reference);
+		   "Timeout waiting for %s ready (osc=0x%08x, osc_reference=0x%08x, osc_mask=0x%08x).\n",
+		   mcp251xfd_get_osc_str(osc, osc_reference),
+		   osc, osc_reference, osc_mask);
 
 	return -ETIMEDOUT;
 }
@@ -624,6 +641,10 @@ static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv)
 	if (err)
 		return err;
 
+	/* Sometimes the PLL is stuck enabled, the controller never
+	 * sets the OSC Ready bit, and we get an -ETIMEDOUT. Our
+	 * caller takes care of retry.
+	 */
 	return mcp251xfd_chip_wait_for_osc_ready(priv, osc_reference, osc_mask);
 }
 
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 08/14] can: mcp251xfd: mcp251xfd_chip_softreset_check(): wait for OSC ready before accessing chip
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (6 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 07/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): prepare for PLL support Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 09/14] can: mcp251xfd: mcp251xfd_chip_timestamp_init(): factor out into separate function Marc Kleine-Budde
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch changes the order of reading the Mode and Oscillator Ready
bits.

Instead of reading the Mode of the chip directly after reset, first
wait for the oscillator to get ready and the chip to fully start up.
Read the Mode after this.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 29 ++++++++-----------
 1 file changed, 12 insertions(+), 17 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 2579b5aa1710..4d5384a9eb34 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -670,34 +670,29 @@ static int mcp251xfd_chip_softreset_do(const struct mcp251xfd_priv *priv)
 
 static int mcp251xfd_chip_softreset_check(const struct mcp251xfd_priv *priv)
 {
-	u32 osc, osc_reference;
+	u32 osc_reference, osc_mask;
 	u8 mode;
 	int err;
 
-	err = mcp251xfd_chip_get_mode(priv, &mode);
-	if (err)
-		return err;
-
-	if (mode != MCP251XFD_REG_CON_MODE_CONFIG) {
-		netdev_info(priv->ndev,
-			    "Controller not in Config Mode after reset, but in %s Mode (%u).\n",
-			    mcp251xfd_get_mode_str(mode), mode);
-		return -ETIMEDOUT;
-	}
-
+	/* Check for reset defaults of OSC reg.
+	 * This will take care of stabilization period.
+	 */
 	osc_reference = MCP251XFD_REG_OSC_OSCRDY |
 		FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK,
 			   MCP251XFD_REG_OSC_CLKODIV_10);
+	osc_mask = osc_reference | MCP251XFD_REG_OSC_PLLRDY;
+	err = mcp251xfd_chip_wait_for_osc_ready(priv, osc_reference, osc_mask);
+	if (err)
+		return err;
 
-	/* check reset defaults of OSC reg */
-	err = regmap_read(priv->map_reg, MCP251XFD_REG_OSC, &osc);
+	err = mcp251xfd_chip_get_mode(priv, &mode);
 	if (err)
 		return err;
 
-	if (osc != osc_reference) {
+	if (mode != MCP251XFD_REG_CON_MODE_CONFIG) {
 		netdev_info(priv->ndev,
-			    "Controller failed to reset. osc=0x%08x, reference value=0x%08x.\n",
-			    osc, osc_reference);
+			    "Controller not in Config Mode after reset, but in %s Mode (%u).\n",
+			    mcp251xfd_get_mode_str(mode), mode);
 		return -ETIMEDOUT;
 	}
 
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 09/14] can: mcp251xfd: mcp251xfd_chip_timestamp_init(): factor out into separate function
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (7 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 08/14] can: mcp251xfd: mcp251xfd_chip_softreset_check(): wait for OSC ready before accessing chip Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 10/14] can: mcp251xfd: mcp251xfd_chip_wake(): renamed from mcp251xfd_chip_clock_enable() Marc Kleine-Budde
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch factors out the timestamp initialization from the clock
initialization.

This is a preparation patch, where the clock handling must be
initialized separately.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 4d5384a9eb34..d5500315b936 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -742,6 +742,11 @@ static int mcp251xfd_chip_clock_init(const struct mcp251xfd_priv *priv)
 	if (err)
 		return err;
 
+	return 0;
+}
+
+static int mcp251xfd_chip_timestamp_init(const struct mcp251xfd_priv *priv)
+{
 	/* Set Time Base Counter Prescaler to 1.
 	 *
 	 * This means an overflow of the 32 bit Time Base Counter
@@ -1114,6 +1119,10 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
 	if (err)
 		goto out_chip_stop;
 
+	err = mcp251xfd_chip_timestamp_init(priv);
+	if (err)
+		goto out_chip_stop;
+
 	err = mcp251xfd_set_bittiming(priv);
 	if (err)
 		goto out_chip_stop;
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 10/14] can: mcp251xfd: mcp251xfd_chip_wake(): renamed from mcp251xfd_chip_clock_enable()
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (8 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 09/14] can: mcp251xfd: mcp251xfd_chip_timestamp_init(): factor out into separate function Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 11/14] can: mcp251xfd: __mcp251xfd_chip_set_mode(): prepare for PLL support: improve error handling and diagnostics Marc Kleine-Budde
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch renames mcp251xfd_chip_clock_enable() into mcp251xfd_chip_wake() as
this function actually wakes the chip. Additionally the documentation is
adopted.

Co-developed-by: Magnus Aagaard Sørensen <mas@csselectronics.com>
Signed-off-by: Magnus Aagaard Sørensen <mas@csselectronics.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index d5500315b936..734581541d6d 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -618,22 +618,23 @@ mcp251xfd_chip_wait_for_osc_ready(const struct mcp251xfd_priv *priv,
 	return -ETIMEDOUT;
 }
 
-static int mcp251xfd_chip_clock_enable(const struct mcp251xfd_priv *priv)
+static int mcp251xfd_chip_wake(const struct mcp251xfd_priv *priv)
 {
 	u32 osc, osc_reference, osc_mask;
 	int err;
 
-	/* Set Power On Defaults for "Clock Output Divisor" and remove
-	 * "Oscillator Disable" bit.
+	/* For normal sleep on MCP2517FD and MCP2518FD, clearing
+	 * "Oscillator Disable" will wake the chip. For low power mode
+	 * on MCP2518FD, asserting the chip select will wake the
+	 * chip. Writing to the Oscillator register will wake it in
+	 * both cases.
 	 */
 	osc = FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK,
 			 MCP251XFD_REG_OSC_CLKODIV_10);
 	osc_reference = MCP251XFD_REG_OSC_OSCRDY;
 	osc_mask = MCP251XFD_REG_OSC_OSCRDY | MCP251XFD_REG_OSC_PLLRDY;
 
-	/* Note:
-	 *
-	 * If the controller is in Sleep Mode the following write only
+	/* If the controller is in Sleep Mode the following write only
 	 * removes the "Oscillator Disable" bit and powers it up. All
 	 * other bits are unaffected.
 	 */
@@ -653,10 +654,10 @@ static int mcp251xfd_chip_softreset_do(const struct mcp251xfd_priv *priv)
 	const __be16 cmd = mcp251xfd_cmd_reset();
 	int err;
 
-	/* The Set Mode and SPI Reset command only seems to works if
-	 * the controller is not in Sleep Mode.
+	/* The Set Mode and SPI Reset command only works if the
+	 * controller is not in Sleep Mode.
 	 */
-	err = mcp251xfd_chip_clock_enable(priv);
+	err = mcp251xfd_chip_wake(priv);
 	if (err)
 		return err;
 
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 11/14] can: mcp251xfd: __mcp251xfd_chip_set_mode(): prepare for PLL support: improve error handling and diagnostics
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (9 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 10/14] can: mcp251xfd: mcp251xfd_chip_wake(): renamed from mcp251xfd_chip_clock_enable() Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 12/14] can: mcp251xfd: mcp251xfd_chip_clock_init(): prepare for PLL support, wait for OSC ready Marc Kleine-Budde
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch prepares the __mcp251xfd_chip_set_mode() function for PLL
support by adding more error checks and diagnostics.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 39 ++++++++++++++-----
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index 734581541d6d..d90bf995e223 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -544,34 +544,55 @@ static int
 __mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv,
 			  const u8 mode_req, bool nowait)
 {
-	u32 con, con_reqop;
+	u32 con = 0, con_reqop, osc = 0;
+	u8 mode;
 	int err;
 
 	con_reqop = FIELD_PREP(MCP251XFD_REG_CON_REQOP_MASK, mode_req);
 	err = regmap_update_bits(priv->map_reg, MCP251XFD_REG_CON,
 				 MCP251XFD_REG_CON_REQOP_MASK, con_reqop);
-	if (err)
+	if (err == -EBADMSG) {
+		netdev_err(priv->ndev,
+			   "Failed to set Requested Operation Mode.\n");
+
+		return -ENODEV;
+	} else if (err) {
 		return err;
+	}
 
 	if (mode_req == MCP251XFD_REG_CON_MODE_SLEEP || nowait)
 		return 0;
 
 	err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_CON, con,
+				       !mcp251xfd_reg_invalid(con) &&
 				       FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK,
 						 con) == mode_req,
 				       MCP251XFD_POLL_SLEEP_US,
 				       MCP251XFD_POLL_TIMEOUT_US);
-	if (err) {
-		u8 mode = FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK, con);
+	if (err != -ETIMEDOUT && err != -EBADMSG)
+		return err;
+
+	/* Ignore return value.
+	 * Print below error messages, even if this fails.
+	 */
+	regmap_read(priv->map_reg, MCP251XFD_REG_OSC, &osc);
 
+	if (mcp251xfd_reg_invalid(con)) {
 		netdev_err(priv->ndev,
-			   "Controller failed to enter mode %s Mode (%u) and stays in %s Mode (%u).\n",
-			   mcp251xfd_get_mode_str(mode_req), mode_req,
-			   mcp251xfd_get_mode_str(mode), mode);
-		return err;
+			   "Failed to read CAN Control Register (con=0x%08x, osc=0x%08x).\n",
+			   con, osc);
+
+		return -ENODEV;
 	}
 
-	return 0;
+	mode = FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK, con);
+	netdev_err(priv->ndev,
+		   "Controller failed to enter mode %s Mode (%u) and stays in %s Mode (%u) (con=0x%08x, osc=0x%08x).\n",
+		   mcp251xfd_get_mode_str(mode_req), mode_req,
+		   mcp251xfd_get_mode_str(mode), mode,
+		   con, osc);
+
+	return -ETIMEDOUT;
 }
 
 static inline int
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 12/14] can: mcp251xfd: mcp251xfd_chip_clock_init(): prepare for PLL support, wait for OSC ready
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (10 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 11/14] can: mcp251xfd: __mcp251xfd_chip_set_mode(): prepare for PLL support: improve error handling and diagnostics Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:23 ` [can-next-rfc 13/14] can: mcp251xfd: mcp251xfd_register(): prepare to activate PLL after softreset Marc Kleine-Budde
  2021-04-25 12:24 ` [can-next-rfc 14/14] can: mcp251xfd: add support for internal PLL Marc Kleine-Budde
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

This patch prepares the mcp251xfd_chip_clock_init() function for PLL
support.

If the PLL is needed ist must be switched on after chip reset. This
should be done in the mcp251xfd_chip_clock_init() function. Prepare
this function to wait for the OSC and PLL to be ready.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index d90bf995e223..d4309afef02e 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -750,7 +750,7 @@ static int mcp251xfd_chip_softreset(const struct mcp251xfd_priv *priv)
 
 static int mcp251xfd_chip_clock_init(const struct mcp251xfd_priv *priv)
 {
-	u32 osc;
+	u32 osc, osc_reference, osc_mask;
 	int err;
 
 	/* Activate Low Power Mode on Oscillator Disable. This only
@@ -760,10 +760,17 @@ static int mcp251xfd_chip_clock_init(const struct mcp251xfd_priv *priv)
 	osc = MCP251XFD_REG_OSC_LPMEN |
 		FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK,
 			   MCP251XFD_REG_OSC_CLKODIV_10);
+	osc_reference = MCP251XFD_REG_OSC_OSCRDY;
+	osc_mask = MCP251XFD_REG_OSC_OSCRDY | MCP251XFD_REG_OSC_PLLRDY;
+
 	err = regmap_write(priv->map_reg, MCP251XFD_REG_OSC, osc);
 	if (err)
 		return err;
 
+	err = mcp251xfd_chip_wait_for_osc_ready(priv, osc_reference, osc_mask);
+	if (err)
+		return err;
+
 	return 0;
 }
 
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 13/14] can: mcp251xfd: mcp251xfd_register(): prepare to activate PLL after softreset
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (11 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 12/14] can: mcp251xfd: mcp251xfd_chip_clock_init(): prepare for PLL support, wait for OSC ready Marc Kleine-Budde
@ 2021-04-25 12:23 ` Marc Kleine-Budde
  2021-04-25 12:24 ` [can-next-rfc 14/14] can: mcp251xfd: add support for internal PLL Marc Kleine-Budde
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:23 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

If the PLL is needed ist must be switched on after chip reset. This
patch adds the required call to mcp251xfd_register().

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index d4309afef02e..ab6d4c26d82c 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -2830,6 +2830,10 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv)
 	if (err)
 		goto out_chip_set_mode_sleep;
 
+	err = mcp251xfd_chip_clock_init(priv);
+	if (err)
+		goto out_chip_set_mode_sleep;
+
 	err = mcp251xfd_register_chip_detect(priv);
 	if (err)
 		goto out_chip_set_mode_sleep;
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [can-next-rfc 14/14] can: mcp251xfd: add support for internal PLL
  2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
                   ` (12 preceding siblings ...)
  2021-04-25 12:23 ` [can-next-rfc 13/14] can: mcp251xfd: mcp251xfd_register(): prepare to activate PLL after softreset Marc Kleine-Budde
@ 2021-04-25 12:24 ` Marc Kleine-Budde
  13 siblings, 0 replies; 15+ messages in thread
From: Marc Kleine-Budde @ 2021-04-25 12:24 UTC (permalink / raw)
  To: linux-can
  Cc: kernel, Manivannan Sadhasivam, Thomas Kopp,
	Magnus Aagaard Sørensen, Marc Kleine-Budde

The PLL is enabled if the configured clock is less than or equal to 10 times
the max clock frequency.

The device will operate with two different SPI speeds. A slow speed determined
by the clock without the PLL enabled, and a fast speed derived from the
frequency with the PLL enabled.

Link: https://lore.kernel.org/r/20201015124401.2766-3-mas@csselectronics.com
Co-developed-by: Magnus Aagaard Sørensen <mas@csselectronics.com>
Signed-off-by: Magnus Aagaard Sørensen <mas@csselectronics.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    | 75 ++++++++++++++-----
 drivers/net/can/spi/mcp251xfd/mcp251xfd.h     |  3 +
 2 files changed, 60 insertions(+), 18 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index ab6d4c26d82c..73b168957ffd 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -560,6 +560,8 @@ __mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv,
 		return err;
 	}
 
+	if (mode_req == MCP251XFD_REG_CON_MODE_SLEEP)
+		priv->spi->max_speed_hz = priv->spi_max_speed_hz_slow;
 	if (mode_req == MCP251XFD_REG_CON_MODE_SLEEP || nowait)
 		return 0;
 
@@ -652,8 +654,13 @@ static int mcp251xfd_chip_wake(const struct mcp251xfd_priv *priv)
 	 */
 	osc = FIELD_PREP(MCP251XFD_REG_OSC_CLKODIV_MASK,
 			 MCP251XFD_REG_OSC_CLKODIV_10);
+
+	/* We cannot check for the PLL ready bit (either set or
+	 * unset), as the PLL might be enabled. This can happen if the
+	 * system reboots, while the mcp251xfd stays powered.
+	 */
 	osc_reference = MCP251XFD_REG_OSC_OSCRDY;
-	osc_mask = MCP251XFD_REG_OSC_OSCRDY | MCP251XFD_REG_OSC_PLLRDY;
+	osc_mask = MCP251XFD_REG_OSC_OSCRDY;
 
 	/* If the controller is in Sleep Mode the following write only
 	 * removes the "Oscillator Disable" bit and powers it up. All
@@ -763,6 +770,11 @@ static int mcp251xfd_chip_clock_init(const struct mcp251xfd_priv *priv)
 	osc_reference = MCP251XFD_REG_OSC_OSCRDY;
 	osc_mask = MCP251XFD_REG_OSC_OSCRDY | MCP251XFD_REG_OSC_PLLRDY;
 
+	if (priv->pll_enable) {
+		osc |= MCP251XFD_REG_OSC_PLLEN;
+		osc_reference |= MCP251XFD_REG_OSC_PLLRDY;
+	}
+
 	err = regmap_write(priv->map_reg, MCP251XFD_REG_OSC, osc);
 	if (err)
 		return err;
@@ -771,6 +783,8 @@ static int mcp251xfd_chip_clock_init(const struct mcp251xfd_priv *priv)
 	if (err)
 		return err;
 
+	priv->spi->max_speed_hz = priv->spi_max_speed_hz_fast;
+
 	return 0;
 }
 
@@ -2730,8 +2744,9 @@ static int mcp251xfd_register_check_rx_int(struct mcp251xfd_priv *priv)
 }
 
 static int
-mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv,
-			      u32 *dev_id, u32 *effective_speed_hz)
+mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
+			      u32 *effective_speed_hz_slow,
+			      u32 *effective_speed_hz_fast)
 {
 	struct mcp251xfd_map_buf_nocrc *buf_rx;
 	struct mcp251xfd_map_buf_nocrc *buf_tx;
@@ -2750,16 +2765,20 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv,
 
 	xfer[0].tx_buf = buf_tx;
 	xfer[0].len = sizeof(buf_tx->cmd);
+	xfer[0].speed_hz = priv->spi_max_speed_hz_slow;
 	xfer[1].rx_buf = buf_rx->data;
 	xfer[1].len = sizeof(dev_id);
+	xfer[1].speed_hz = priv->spi_max_speed_hz_fast;
 
 	mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, MCP251XFD_REG_DEVID);
+
 	err = spi_sync_transfer(priv->spi, xfer, ARRAY_SIZE(xfer));
 	if (err)
 		goto out_kfree_buf_tx;
 
 	*dev_id = be32_to_cpup((__be32 *)buf_rx->data);
-	*effective_speed_hz = xfer->effective_speed_hz;
+	*effective_speed_hz_slow = xfer[0].effective_speed_hz;
+	*effective_speed_hz_fast = xfer[1].effective_speed_hz;
 
  out_kfree_buf_tx:
 	kfree(buf_tx);
@@ -2775,34 +2794,45 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv,
 static int
 mcp251xfd_register_done(const struct mcp251xfd_priv *priv)
 {
-	u32 dev_id, effective_speed_hz;
+	u32 dev_id, effective_speed_hz_slow, effective_speed_hz_fast;
+	unsigned long clk_rate;
 	int err;
 
 	err = mcp251xfd_register_get_dev_id(priv, &dev_id,
-					    &effective_speed_hz);
+					    &effective_speed_hz_slow,
+					    &effective_speed_hz_fast);
 	if (err)
 		return err;
 
+	clk_rate = clk_get_rate(priv->clk);
+
 	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 %cPLL %cMAB_NO_WARN %cCRC_REG %cCRC_RX %cCRC_TX %cECC %cHD o:%lu.%02luMHz c:%u.%02uMHz m:%u.%02uMHz rs:%u.%02uMHz es:%u.%02uMHz rf:%u.%02uMHz ef:%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->pll_enable ? '+' : '-',
 		    MCP251XFD_QUIRK_ACTIVE(MAB_NO_WARN),
 		    MCP251XFD_QUIRK_ACTIVE(CRC_REG),
 		    MCP251XFD_QUIRK_ACTIVE(CRC_RX),
 		    MCP251XFD_QUIRK_ACTIVE(CRC_TX),
 		    MCP251XFD_QUIRK_ACTIVE(ECC),
 		    MCP251XFD_QUIRK_ACTIVE(HALF_DUPLEX),
+		    clk_rate / 1000000,
+		    clk_rate % 1000000 / 1000 / 10,
 		    priv->can.clock.freq / 1000000,
 		    priv->can.clock.freq % 1000000 / 1000 / 10,
 		    priv->spi_max_speed_hz_orig / 1000000,
 		    priv->spi_max_speed_hz_orig % 1000000 / 1000 / 10,
-		    priv->spi->max_speed_hz / 1000000,
-		    priv->spi->max_speed_hz % 1000000 / 1000 / 10,
-		    effective_speed_hz / 1000000,
-		    effective_speed_hz % 1000000 / 1000 / 10);
+		    priv->spi_max_speed_hz_slow / 1000000,
+		    priv->spi_max_speed_hz_slow % 1000000 / 1000 / 10,
+		    effective_speed_hz_slow / 1000000,
+		    effective_speed_hz_slow % 1000000 / 1000 / 10,
+		    priv->spi_max_speed_hz_fast / 1000000,
+		    priv->spi_max_speed_hz_fast % 1000000 / 1000 / 10,
+		    effective_speed_hz_fast / 1000000,
+		    effective_speed_hz_fast % 1000000 / 1000 / 10);
 
 	return 0;
 }
@@ -2927,6 +2957,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
 	struct gpio_desc *rx_int;
 	struct regulator *reg_vdd, *reg_xceiver;
 	struct clk *clk;
+	bool pll_enable = false;
 	u32 freq;
 	int err;
 
@@ -2969,12 +3000,8 @@ static int mcp251xfd_probe(struct spi_device *spi)
 		return -ERANGE;
 	}
 
-	if (freq <= MCP251XFD_SYSCLOCK_HZ_MAX / MCP251XFD_OSC_PLL_MULTIPLIER) {
-		dev_err(&spi->dev,
-			"Oscillator frequency (%u Hz) is too low and PLL is not supported.\n",
-			freq);
-		return -ERANGE;
-	}
+	if (freq <= MCP251XFD_SYSCLOCK_HZ_MAX / MCP251XFD_OSC_PLL_MULTIPLIER)
+		pll_enable = true;
 
 	ndev = alloc_candev(sizeof(struct mcp251xfd_priv),
 			    MCP251XFD_TX_OBJ_NUM_MAX);
@@ -2990,6 +3017,8 @@ static int mcp251xfd_probe(struct spi_device *spi)
 	priv = netdev_priv(ndev);
 	spi_set_drvdata(spi, priv);
 	priv->can.clock.freq = freq;
+	if (pll_enable)
+		priv->can.clock.freq *= MCP251XFD_OSC_PLL_MULTIPLIER;
 	priv->can.do_set_mode = mcp251xfd_set_mode;
 	priv->can.do_get_berr_counter = mcp251xfd_get_berr_counter;
 	priv->can.bittiming_const = &mcp251xfd_bittiming_const;
@@ -3002,6 +3031,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
 	priv->spi = spi;
 	priv->rx_int = rx_int;
 	priv->clk = clk;
+	priv->pll_enable = pll_enable;
 	priv->reg_vdd = reg_vdd;
 	priv->reg_xceiver = reg_xceiver;
 
@@ -3039,7 +3069,16 @@ static int mcp251xfd_probe(struct spi_device *spi)
 	 *
 	 */
 	priv->spi_max_speed_hz_orig = spi->max_speed_hz;
-	spi->max_speed_hz = min(spi->max_speed_hz, freq / 2 / 1000 * 850);
+	priv->spi_max_speed_hz_slow = min(spi->max_speed_hz,
+					  freq / 2 / 1000 * 850);
+	if (priv->pll_enable)
+		priv->spi_max_speed_hz_fast = min(spi->max_speed_hz,
+						  freq *
+						  MCP251XFD_OSC_PLL_MULTIPLIER /
+						  2 / 1000 * 850);
+	else
+		priv->spi_max_speed_hz_fast = priv->spi_max_speed_hz_slow;
+	spi->max_speed_hz = priv->spi_max_speed_hz_slow;
 	spi->bits_per_word = 8;
 	spi->rt = true;
 	err = spi_setup(spi);
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
index 1002f3902ad2..9fd147b0a788 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
@@ -591,6 +591,8 @@ struct mcp251xfd_priv {
 
 	struct spi_device *spi;
 	u32 spi_max_speed_hz_orig;
+	u32 spi_max_speed_hz_fast;
+	u32 spi_max_speed_hz_slow;
 
 	struct mcp251xfd_tef_ring tef[1];
 	struct mcp251xfd_tx_ring tx[1];
@@ -607,6 +609,7 @@ struct mcp251xfd_priv {
 
 	struct gpio_desc *rx_int;
 	struct clk *clk;
+	bool pll_enable;
 	struct regulator *reg_vdd;
 	struct regulator *reg_xceiver;
 
-- 
2.30.2



^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2021-04-25 12:24 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-25 12:23 [RFC]: can-next 2021-04-25: mcp251xfd cleanups and PLL support Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 01/14] can: mcp251xfd: mcp251xfd_irq(): stop timestamping worker in case error in IRQ Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 02/14] can: mcp251xfd: mcp251xfd_tef_obj_read(): fix typo in error message Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 03/14] can: mcp251xfd: mcp251xfd_regmap_crc_read(): ignore CRC error only if solely OSC register is read Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 04/14] can: mcp251xfd: mcp251xfd_reg_invalid(): rename from mcp251xfd_osc_invalid() Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 05/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): factor out into separate function Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 06/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): improve chip detection and error handling Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 07/14] can: mcp251xfd: mcp251xfd_chip_wait_for_osc_ready(): prepare for PLL support Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 08/14] can: mcp251xfd: mcp251xfd_chip_softreset_check(): wait for OSC ready before accessing chip Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 09/14] can: mcp251xfd: mcp251xfd_chip_timestamp_init(): factor out into separate function Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 10/14] can: mcp251xfd: mcp251xfd_chip_wake(): renamed from mcp251xfd_chip_clock_enable() Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 11/14] can: mcp251xfd: __mcp251xfd_chip_set_mode(): prepare for PLL support: improve error handling and diagnostics Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 12/14] can: mcp251xfd: mcp251xfd_chip_clock_init(): prepare for PLL support, wait for OSC ready Marc Kleine-Budde
2021-04-25 12:23 ` [can-next-rfc 13/14] can: mcp251xfd: mcp251xfd_register(): prepare to activate PLL after softreset Marc Kleine-Budde
2021-04-25 12:24 ` [can-next-rfc 14/14] can: mcp251xfd: add support for internal PLL Marc Kleine-Budde

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).