summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--board/pcm038/pcm038.c15
-rw-r--r--drivers/spi/imx_spi.c65
-rw-r--r--include/asm-arm/arch-imx/spi.h27
3 files changed, 83 insertions, 24 deletions
diff --git a/board/pcm038/pcm038.c b/board/pcm038/pcm038.c
index 175614632a..78815a985f 100644
--- a/board/pcm038/pcm038.c
+++ b/board/pcm038/pcm038.c
@@ -42,6 +42,7 @@
#include <asm/arch/imxfb.h>
#include <asm/mmu.h>
#include <usb/isp1504.h>
+#include <asm/arch/spi.h>
static struct device_d cfi_dev = {
.name = "cfi_flash",
@@ -84,9 +85,17 @@ static struct device_d fec_dev = {
.platform_data = &fec_info,
};
+static int pcm038_spi_cs[] = {GPIO_PORTD + 28};
+
+static struct spi_imx_master pcm038_spi_0_data = {
+ .chipselect = pcm038_spi_cs,
+ .num_chipselect = ARRAY_SIZE(pcm038_spi_cs),
+};
+
static struct device_d spi_dev = {
.name = "imx_spi",
.map_base = 0x1000e000,
+ .platform_data = &pcm038_spi_0_data,
};
static struct spi_board_info pcm038_spi_board_info[] = {
@@ -229,9 +238,7 @@ static int pcm038_devices_init(void)
PE14_PF_UART1_CTS,
PE15_PF_UART1_RTS,
PD25_PF_CSPI1_RDY,
- PD26_PF_CSPI1_SS2,
- PD27_PF_CSPI1_SS1,
- PD28_PF_CSPI1_SS0,
+ GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT,
PD29_PF_CSPI1_SCLK,
PD30_PF_CSPI1_MISO,
PD31_PF_CSPI1_MOSI,
@@ -302,6 +309,8 @@ static int pcm038_devices_init(void)
PCCR0 |= PCCR0_CSPI1_EN;
PCCR1 |= PCCR1_PERCLK2_EN;
+ gpio_direction_output(GPIO_PORTD | 28, 0);
+ gpio_set_value(GPIO_PORTD | 28, 0);
spi_register_board_info(pcm038_spi_board_info, ARRAY_SIZE(pcm038_spi_board_info));
register_device(&spi_dev);
diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c
index 81302022f8..8a483082ef 100644
--- a/drivers/spi/imx_spi.c
+++ b/drivers/spi/imx_spi.c
@@ -24,6 +24,8 @@
#include <spi/spi.h>
#include <xfuncs.h>
#include <asm/io.h>
+#include <gpio.h>
+#include <asm/arch/spi.h>
#define MXC_CSPIRXDATA 0x00
#define MXC_CSPITXDATA 0x04
@@ -53,23 +55,20 @@
#define MXC_CSPISTAT_TE (1 << 0)
#define MXC_CSPISTAT_TH (1 << 1)
#define MXC_CSPISTAT_TF (1 << 2)
-#define MXC_CSPISTAT_RR (1 << 3)
-#define MXC_CSPISTAT_RH (1 << 4)
-#define MXC_CSPISTAT_RF (1 << 5)
-#define MXC_CSPISTAT_RO (1 << 6)
-#define MXC_CSPISTAT_TC_0_7 (1 << 7)
-#define MXC_CSPISTAT_TC_0_5 (1 << 8)
-#define MXC_CSPISTAT_TC_0_4 (1 << 8)
-#define MXC_CSPISTAT_TC_0_0 (1 << 3)
-#define MXC_CSPISTAT_BO_0_7 0
-#define MXC_CSPISTAT_BO_0_5 (1 << 7)
-#define MXC_CSPISTAT_BO_0_4 (1 << 7)
-#define MXC_CSPISTAT_BO_0_0 (1 << 8)
+#define MXC_CSPISTAT_RR (1 << 4)
+#define MXC_CSPISTAT_RH (1 << 5)
+#define MXC_CSPISTAT_RF (1 << 6)
+#define MXC_CSPISTAT_RO (1 << 7)
#define MXC_CSPIPERIOD_32KHZ (1 << 15)
#define MXC_CSPITEST_LBC (1 << 14)
+struct imx_spi {
+ struct spi_master master;
+ int *chipselect;
+};
+
static int imx_spi_setup(struct spi_device *spi)
{
debug("%s mode 0x%08x bits_per_word: %d speed: %d\n",
@@ -89,7 +88,7 @@ static unsigned int spi_xchg_single(ulong base, unsigned int data)
writel(cfg_reg, base + MXC_CSPICTRL);
- while (readl(base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH);
+ while (!(readl(base + MXC_CSPIINT) & MXC_CSPISTAT_RR));
return readl(base + MXC_CSPIRXDATA);
}
@@ -97,23 +96,41 @@ static unsigned int spi_xchg_single(ulong base, unsigned int data)
static void mxc_spi_chipselect(struct spi_device *spi, int is_active)
{
struct spi_master *master = spi->master;
+ struct imx_spi *imx = container_of(master, struct imx_spi, master);
ulong base = master->dev->map_base;
+ unsigned int cs = 0;
+ int gpio = imx->chipselect[spi->chip_select];
u32 ctrl_reg;
- ctrl_reg = MXC_CSPICTRL_CS(spi->chip_select)
- | MXC_CSPICTRL_BITCOUNT(spi->bits_per_word - 1)
+ if (spi->mode & SPI_CS_HIGH)
+ cs = 1;
+
+ if (!is_active) {
+ if (gpio >= 0)
+ gpio_set_value(gpio, !cs);
+ return;
+ }
+
+ ctrl_reg = MXC_CSPICTRL_BITCOUNT(spi->bits_per_word - 1)
| MXC_CSPICTRL_DATARATE(7) /* FIXME: calculate data rate */
| MXC_CSPICTRL_ENABLE
| MXC_CSPICTRL_MASTER;
+ if (gpio < 0) {
+ ctrl_reg |= MXC_CSPICTRL_CS(gpio + 32);
+ }
+
if (spi->mode & SPI_CPHA)
ctrl_reg |= MXC_CSPICTRL_PHA;
- if (!(spi->mode & SPI_CPOL))
+ if (spi->mode & SPI_CPOL)
ctrl_reg |= MXC_CSPICTRL_LOWPOL;
if (spi->mode & SPI_CS_HIGH)
ctrl_reg |= MXC_CSPICTRL_HIGHSSPOL;
writel(ctrl_reg, base + MXC_CSPICTRL);
+
+ if (gpio >= 0)
+ gpio_set_value(gpio, cs);
}
static int imx_spi_transfer(struct spi_device *spi, struct spi_message *mesg)
@@ -134,28 +151,34 @@ static int imx_spi_transfer(struct spi_device *spi, struct spi_message *mesg)
i++;
}
}
+
+ mxc_spi_chipselect(spi, 0);
+
return 0;
}
static int imx_spi_probe(struct device_d *dev)
{
struct spi_master *master;
+ struct imx_spi *imx;
+ struct spi_imx_master *pdata = dev->platform_data;
- debug("%s\n", __FUNCTION__);
-
- master = xzalloc(sizeof(struct spi_master));
- debug("master: %p %d\n", master, sizeof(struct spi_master));
+ imx = xzalloc(sizeof(*imx));
+ master = &imx->master;
master->dev = dev;
master->setup = imx_spi_setup;
master->transfer = imx_spi_transfer;
- master->num_chipselect = 1; /* FIXME: Board dependent */
+ master->num_chipselect = pdata->num_chipselect;
+ imx->chipselect = pdata->chipselect;
writel(MXC_CSPICTRL_ENABLE | MXC_CSPICTRL_MASTER,
dev->map_base + MXC_CSPICTRL);
writel(MXC_CSPIPERIOD_32KHZ,
dev->map_base + MXC_CSPIPERIOD);
+ while (readl(dev->map_base + MXC_CSPIINT) & MXC_CSPISTAT_RR)
+ readl(dev->map_base + MXC_CSPIRXDATA);
writel(0, dev->map_base + MXC_CSPIINT);
spi_register_master(master);
diff --git a/include/asm-arm/arch-imx/spi.h b/include/asm-arm/arch-imx/spi.h
new file mode 100644
index 0000000000..08be445e8e
--- /dev/null
+++ b/include/asm-arm/arch-imx/spi.h
@@ -0,0 +1,27 @@
+
+#ifndef __MACH_SPI_H_
+#define __MACH_SPI_H_
+
+/*
+ * struct spi_imx_master - device.platform_data for SPI controller devices.
+ * @chipselect: Array of chipselects for this master. Numbers >= 0 mean gpio
+ * pins, numbers < 0 mean internal CSPI chipselects according
+ * to MXC_SPI_CS(). Normally you want to use gpio based chip
+ * selects as the CSPI module tries to be intelligent about
+ * when to assert the chipselect: The CSPI module deasserts the
+ * chipselect once it runs out of input data. The other problem
+ * is that it is not possible to mix between high active and low
+ * active chipselects on one single bus using the internal
+ * chipselects. Unfortunately Freescale decided to put some
+ * chipselects on dedicated pins which are not usable as gpios,
+ * so we have to support the internal chipselects.
+ * @num_chipselect: ARRAY_SIZE(chipselect)
+ */
+struct spi_imx_master {
+ int *chipselect;
+ int num_chipselect;
+};
+
+#define MXC_SPI_CS(no) ((no) - 32)
+
+#endif /* __MACH_SPI_H_*/