diff options
-rw-r--r-- | board/pcm038/pcm038.c | 15 | ||||
-rw-r--r-- | drivers/spi/imx_spi.c | 65 | ||||
-rw-r--r-- | include/asm-arm/arch-imx/spi.h | 27 |
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_*/ |