@@ -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);