[PATCH 6/7] spi: realtek-rtl: add support to configure bus speed

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

 



The available datasheets for the RTL8381M and RTL9301 state
that the SPI frequency is 50MHz. Set this maximum spi frequency
unless specified otherwise in the device node.

The SPI device on the RTL83xx and RTL93xx SoCs is also accessed
independently by dedicated SPI-NOR (RTL83xx/RTL93xx) and
SPI-NAND (RTL93xx) hardware, which can perform DMA transfers via
the SPI device.
While these devices can set chip selects, they cannot configure
the SPI frequency for a transfer. The clock divider is therefore
configured once during device probe and not changed for individual
transfers as the SPI frequency is a bus property on this platform.

The clock divider setting can take values 0-7, the actual divider
then is:
clock_divider = 2 * (divider_setting + 1)
allowing for clock dividers with values 2-16. The clock used to
derive the SPI clock on the Realtek SoCs is the Lexra bus clock.
When a clock is provided in the SPI device node, we set a clock
divider corresponding to the maximum spi frequency.

Signed-off-by: Birger Koblitz <mail@xxxxxxxxxxxxxxxxx>
---
 drivers/spi/spi-realtek-rtl.c | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-realtek-rtl.c b/drivers/spi/spi-realtek-rtl.c
index 21c0dc16c8cc..91aa7a0348a2 100644
--- a/drivers/spi/spi-realtek-rtl.c
+++ b/drivers/spi/spi-realtek-rtl.c
@@ -5,15 +5,21 @@
 #include <linux/mod_devicetable.h>
 #include <linux/spi/spi.h>
 #include <linux/property.h>
+#include <linux/of.h>
+#include <linux/clk.h>

 struct rtspi {
 	void __iomem *base;
 	u32 dev_flags;
 	u32 cs_all;
+	struct clk *clk;
+	int frequency_div;
 };

 /* SPI Flash Configuration Register */
 #define RTL_SPI_SFCR			0x00
+#define RTL_SPI_SFCR_CLK_DIV_BIT	29
+#define RTL_SPI_SFCR_CLK_DIV_MASK	~(0x7 << RTL_SPI_SFCR_CLK_DIV_BIT)
 #define RTL_SPI_SFCR_RBO		BIT(28)
 #define RTL_SPI_SFCR_WBO		BIT(27)

@@ -208,9 +214,14 @@ static void init_hw(struct rtspi *rtspi)
 {
 	u32 value;

-	/* Turn on big-endian byte ordering */
+	/* Turn on big-endian byte ordering and set clock divider */
 	value = readl(REG(RTL_SPI_SFCR));
 	value |= RTL_SPI_SFCR_RBO | RTL_SPI_SFCR_WBO;
+	if (rtspi->frequency_div >= 0) {
+		value &= RTL_SPI_SFCR_CLK_DIV_MASK;
+		value |= rtspi->frequency_div << RTL_SPI_SFCR_CLK_DIV_BIT;
+	}
+
 	writel(value, REG(RTL_SPI_SFCR));

 	/* Disable CS0-CS3, enable CS */
@@ -222,6 +233,7 @@ static int realtek_rtl_spi_probe(struct platform_device *pdev)
 {
 	struct spi_controller *ctrl;
 	struct rtspi *rtspi;
+	u32 spi_clk;
 	int err;

 	ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*rtspi));
@@ -239,6 +251,20 @@ static int realtek_rtl_spi_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}

+	if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
+				 &ctrl->max_speed_hz))
+		ctrl->max_speed_hz = 50000000; /* 50MHz */
+
+	rtspi->frequency_div = -1;
+	rtspi->clk = devm_clk_get(&pdev->dev, NULL);
+	if (!IS_ERR(rtspi->clk)) {
+		spi_clk = clk_get_rate(rtspi->clk);
+		rtspi->frequency_div = DIV_ROUND_UP(spi_clk, ctrl->max_speed_hz);
+		rtspi->frequency_div = (rtspi->frequency_div / 2) - 1;
+		if (rtspi->frequency_div > 0x7)
+			rtspi->frequency_div = 0x7;
+	}
+
 	init_hw(rtspi);

 	ctrl->dev.of_node = pdev->dev.of_node;
--
2.25.1




[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux