[PATCH 1/6] spi-imx: add CSPI and eCSPI support for i.MX51 MCU

Jason Wang jason77.wang at gmail.com
Thu Sep 2 03:51:59 EDT 2010


There are 3 SPI controllers on i.MX51, one is called CSPI and is
100% compatible with the one on i.MX35, the other two are called
eCSPI and are not compatible with existing controllers on other
i.MX platforms, here we add support of these three controllers in
the imx spi driver.

Signed-off-by: Jason Wang <jason77.wang at gmail.com>
---
 drivers/spi/spi_imx.c |  135 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 131 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 7972e90..8d9c9da 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -155,6 +155,120 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
 	return 7;
 }
 
+/* MX51 eCSPI post divider */
+static unsigned int spi_imx_clkdiv_3(unsigned int fin,
+		unsigned int fspi)
+{
+	int i, div = 1;
+
+	for (i = 0; i < 15; i++) {
+		if (fspi * div >= fin)
+			return i;
+		div <<= 1;
+	}
+
+	return 15;
+}
+
+#define MX51_INTREG_TEEN		(1 << 0)
+#define MX51_INTREG_RREN		(1 << 3)
+
+#define MX51_CSPICTRL_ENABLE		(1 << 0)
+#define MX51_CSPICTRL_XCH		(1 << 2)
+
+#define MX51_CSPICTRL_BL_SHIFT		20
+#define MX51_CSPICTRL_CS_SHIFT		18
+#define MX51_CSPICTRL_DR_SHIFT		8
+#define MX51_CSPICTRL_MODE_SHIFT	4
+#define MX51_CSPICONF_PHA_SHIFT		0
+#define MX51_CSPICONF_POL_SHIFT		4
+#define MX51_CSPICONF_SSPOL_SHIFT	12
+#define MX51_CSPICONF_SSCTL_SHIFT	8
+
+#define MX51_CSPICTRL_CSMASK		0x3
+#define MX51_CSPIINT			0x10
+#define MX51_CSPICONF			0xC
+#define MX51_CSPISTATUS			0x18
+#define MX51_STATUS_RR			(1 << 3)
+
+#define MAX_CHIPSELECT_NUM 4
+
+static int get_chipselect(struct spi_imx_data *spi_imx,
+			  struct spi_imx_config *config)
+{
+	int i;
+
+	for (i = 0; i < MAX_CHIPSELECT_NUM; i++) {
+		if (config->cs == spi_imx->chipselect[i])
+			return i;
+	}
+
+	return -EINVAL;
+}
+static void mx51_intctrl(struct spi_imx_data *spi_imx, int enable)
+{
+	unsigned int val = 0;
+
+	if (enable & MXC_INT_TE)
+		val |= MX51_INTREG_TEEN;
+	if (enable & MXC_INT_RR)
+		val |= MX51_INTREG_RREN;
+
+	writel(val, spi_imx->base + MX51_CSPIINT);
+}
+
+static void mx51_trigger(struct spi_imx_data *spi_imx)
+{
+	unsigned int reg;
+
+	reg = readl(spi_imx->base + MXC_CSPICTRL);
+	reg |= MX51_CSPICTRL_XCH;
+	writel(reg, spi_imx->base + MXC_CSPICTRL);
+}
+
+static int mx51_config(struct spi_imx_data *spi_imx,
+		struct spi_imx_config *config)
+{
+	unsigned int config_reg = 0;
+	unsigned int ctrl_reg = MX51_CSPICTRL_ENABLE;
+	int chan;
+
+	chan = get_chipselect(spi_imx, config);
+	if (chan < 0)
+		return chan;
+	ctrl_reg |= (chan & MX51_CSPICTRL_CSMASK) << MX51_CSPICTRL_CS_SHIFT;
+	ctrl_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) <<
+		MX51_CSPICTRL_MODE_SHIFT;
+	ctrl_reg |= spi_imx_clkdiv_3(spi_imx->spi_clk, config->speed_hz) <<
+		MX51_CSPICTRL_DR_SHIFT;
+
+	ctrl_reg |= (config->bpw - 1) << MX51_CSPICTRL_BL_SHIFT;
+
+
+	if (config->mode & SPI_CPHA)
+		config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) <<
+			MX51_CSPICONF_PHA_SHIFT;
+	if (config->mode & SPI_CPOL)
+		config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) <<
+			MX51_CSPICONF_POL_SHIFT;
+	if (config->mode & SPI_CS_HIGH)
+		config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) <<
+			MX51_CSPICONF_SSPOL_SHIFT;
+
+	config_reg |= (1 << (chan & MX51_CSPICTRL_CSMASK)) <<
+		MX51_CSPICONF_SSCTL_SHIFT;
+
+	writel(ctrl_reg, spi_imx->base + MXC_CSPICTRL);
+	writel(config_reg, spi_imx->base + MX51_CSPICONF);
+
+	return 0;
+}
+
+static int mx51_rx_available(struct spi_imx_data *spi_imx)
+{
+	return readl(spi_imx->base + MX51_CSPISTATUS) & MX51_STATUS_RR;
+}
+
 #define MX31_INTREG_TEEN	(1 << 0)
 #define MX31_INTREG_RREN	(1 << 3)
 
@@ -209,7 +323,7 @@ static int mx31_config(struct spi_imx_data *spi_imx,
 
 	if (cpu_is_mx31())
 		reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
-	else if (cpu_is_mx25() || cpu_is_mx35()) {
+	else if (cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()) {
 		reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
 		reg |= MX31_CSPICTRL_SSCTL;
 	}
@@ -223,7 +337,7 @@ static int mx31_config(struct spi_imx_data *spi_imx,
 	if (config->cs < 0) {
 		if (cpu_is_mx31())
 			reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT;
-		else if (cpu_is_mx25() || cpu_is_mx35())
+		else if (cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())
 			reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT;
 	}
 
@@ -567,7 +681,14 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
 		goto out_iounmap;
 	}
 
-	if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) {
+	/* i.MX51 has two eCSPI and one CSPI controllers, eCSPI controllers are
+	 * not compatible with existing SPI controllers on other i.MX platforms,
+	 * while CSPI controller is 100% compatible with the one on the i.MX35.
+	 * We set the platform device id to 2 for this CSPI at i.MX51 board init
+	 * level to distinguish it from two eCSPI controllers.
+	 */
+	if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35() ||
+	    (cpu_is_mx51() && (pdev->id == 2))) {
 		spi_imx->intctrl = mx31_intctrl;
 		spi_imx->config = mx31_config;
 		spi_imx->trigger = mx31_trigger;
@@ -582,6 +703,11 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
 		spi_imx->config = mx1_config;
 		spi_imx->trigger = mx1_trigger;
 		spi_imx->rx_available = mx1_rx_available;
+	} else if (cpu_is_mx51()) {
+		spi_imx->intctrl = mx51_intctrl;
+		spi_imx->config = mx51_config;
+		spi_imx->trigger = mx51_trigger;
+		spi_imx->rx_available = mx51_rx_available;
 	} else
 		BUG();
 
@@ -599,7 +725,8 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
 		writel(1, spi_imx->base + MXC_RESET);
 
 	/* drain receive buffer */
-	if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35())
+	if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35() ||
+	    (cpu_is_mx51() && (pdev->id == 2)))
 		while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR)
 			readl(spi_imx->base + MXC_CSPIRXDATA);
 
-- 
1.5.6.5




More information about the linux-arm-kernel mailing list