From c4ea142424fc5cb43a2db750cb772e84304e5fb8 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Tue, 6 Jul 2010 17:05:06 +0200 Subject: Use common function to set GPIOs for MX3 and MX5 The patch adds support for setting gpios to the MX51 processor and change name to the corresponding functions for MX31. In this way, it is possible to get rid of nasty #ifdef switches related to the processor type. Signed-off-by: Stefano Babic --- drivers/gpio/Makefile | 2 +- drivers/gpio/mx31_gpio.c | 88 -------------------------------------- drivers/gpio/mxc_gpio.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/spi/mxc_spi.c | 15 ++++--- 4 files changed, 115 insertions(+), 97 deletions(-) delete mode 100644 drivers/gpio/mx31_gpio.c create mode 100644 drivers/gpio/mxc_gpio.c (limited to 'drivers') diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 07d395d898..a0f455223b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -27,7 +27,7 @@ LIB := $(obj)libgpio.a COBJS-$(CONFIG_AT91_GPIO) += at91_gpio.o COBJS-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o -COBJS-$(CONFIG_MX31_GPIO) += mx31_gpio.o +COBJS-$(CONFIG_MXC_GPIO) += mxc_gpio.o COBJS-$(CONFIG_PCA953X) += pca953x.o COBJS-$(CONFIG_S5P) += s5p_gpio.o diff --git a/drivers/gpio/mx31_gpio.c b/drivers/gpio/mx31_gpio.c deleted file mode 100644 index b07f038156..0000000000 --- a/drivers/gpio/mx31_gpio.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2009 - * Guennadi Liakhovetski, DENX Software Engineering, - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include -#include -#include - -/* GPIO port description */ -static unsigned long gpio_ports[] = { - [0] = GPIO1_BASE, - [1] = GPIO2_BASE, - [2] = GPIO3_BASE, -}; - -int mx31_gpio_direction(unsigned int gpio, enum mx31_gpio_direction direction) -{ - unsigned int port = gpio >> 5; - u32 l; - - if (port >= ARRAY_SIZE(gpio_ports)) - return 1; - - gpio &= 0x1f; - - l = __REG(gpio_ports[port] + GPIO_GDIR); - switch (direction) { - case MX31_GPIO_DIRECTION_OUT: - l |= 1 << gpio; - break; - case MX31_GPIO_DIRECTION_IN: - l &= ~(1 << gpio); - } - __REG(gpio_ports[port] + GPIO_GDIR) = l; - - return 0; -} - -void mx31_gpio_set(unsigned int gpio, unsigned int value) -{ - unsigned int port = gpio >> 5; - u32 l; - - if (port >= ARRAY_SIZE(gpio_ports)) - return; - - gpio &= 0x1f; - - l = __REG(gpio_ports[port] + GPIO_DR); - if (value) - l |= 1 << gpio; - else - l &= ~(1 << gpio); - __REG(gpio_ports[port] + GPIO_DR) = l; -} - -int mx31_gpio_get(unsigned int gpio) -{ - unsigned int port = gpio >> 5; - u32 l; - - if (port >= ARRAY_SIZE(gpio_ports)) - return -1; - - gpio &= 0x1f; - - l = (__REG(gpio_ports[port] + GPIO_DR) >> gpio) & 0x01; - - return l; -} diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c new file mode 100644 index 0000000000..663141f1b4 --- /dev/null +++ b/drivers/gpio/mxc_gpio.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009 + * Guennadi Liakhovetski, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#ifdef CONFIG_MX31 +#include +#endif +#ifdef CONFIG_MX51 +#include +#endif +#include +#include + +/* GPIO port description */ +static unsigned long gpio_ports[] = { + [0] = GPIO1_BASE_ADDR, + [1] = GPIO2_BASE_ADDR, + [2] = GPIO3_BASE_ADDR, +#ifdef CONFIG_MX51 + [3] = GPIO4_BASE_ADDR, +#endif +}; + +int mxc_gpio_direction(unsigned int gpio, enum mxc_gpio_direction direction) +{ + unsigned int port = gpio >> 5; + struct gpio_regs *regs; + u32 l; + + if (port >= ARRAY_SIZE(gpio_ports)) + return 1; + + gpio &= 0x1f; + + regs = (struct gpio_regs *)gpio_ports[port]; + + l = readl(®s->gpio_dir); + + switch (direction) { + case MXC_GPIO_DIRECTION_OUT: + l |= 1 << gpio; + break; + case MXC_GPIO_DIRECTION_IN: + l &= ~(1 << gpio); + } + writel(l, ®s->gpio_dir); + + return 0; +} + +void mxc_gpio_set(unsigned int gpio, unsigned int value) +{ + unsigned int port = gpio >> 5; + struct gpio_regs *regs; + u32 l; + + if (port >= ARRAY_SIZE(gpio_ports)) + return; + + gpio &= 0x1f; + + regs = (struct gpio_regs *)gpio_ports[port]; + + l = readl(®s->gpio_dr); + if (value) + l |= 1 << gpio; + else + l &= ~(1 << gpio); + writel(l, ®s->gpio_dr); +} + +int mxc_gpio_get(unsigned int gpio) +{ + unsigned int port = gpio >> 5; + struct gpio_regs *regs; + u32 l; + + if (port >= ARRAY_SIZE(gpio_ports)) + return -1; + + gpio &= 0x1f; + + regs = (struct gpio_regs *)gpio_ports[port]; + + l = (readl(®s->gpio_dr) >> gpio) & 0x01; + + return l; +} diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index e15a63caca..802cd2efb0 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef CONFIG_MX27 /* i.MX27 has a completely wrong register layout and register definitions in the @@ -68,9 +69,6 @@ static unsigned long spi_bases[] = { 0x53f84000, }; -#define OUT MX31_GPIO_DIRECTION_OUT -#define mxc_gpio_direction mx31_gpio_direction -#define mxc_gpio_set mx31_gpio_set #elif defined(CONFIG_MX51) #include #include @@ -111,13 +109,12 @@ static unsigned long spi_bases[] = { CSPI2_BASE_ADDR, CSPI3_BASE_ADDR, }; -#define mxc_gpio_direction(gpio, dir) (0) -#define mxc_gpio_set(gpio, value) {} -#define OUT 1 #else #error "Unsupported architecture" #endif +#define OUT MXC_GPIO_DIRECTION_OUT + struct mxc_spi_slave { struct spi_slave slave; unsigned long base; @@ -126,6 +123,7 @@ struct mxc_spi_slave { u32 cfg_reg; #endif int gpio; + int ss_pol; }; static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) @@ -147,7 +145,7 @@ void spi_cs_activate(struct spi_slave *slave) { struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); if (mxcs->gpio > 0) - mxc_gpio_set(mxcs->gpio, mxcs->ctrl_reg & MXC_CSPICTRL_SSPOL); + mxc_gpio_set(mxcs->gpio, mxcs->ss_pol); } void spi_cs_deactivate(struct spi_slave *slave) @@ -155,7 +153,7 @@ void spi_cs_deactivate(struct spi_slave *slave) struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); if (mxcs->gpio > 0) mxc_gpio_set(mxcs->gpio, - !(mxcs->ctrl_reg & MXC_CSPICTRL_SSPOL)); + !(mxcs->ss_pol)); } #ifdef CONFIG_MX51 @@ -394,6 +392,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, mxcs->slave.bus = bus; mxcs->slave.cs = cs; mxcs->base = spi_bases[bus]; + mxcs->ss_pol = (mode & SPI_CS_HIGH) ? 1 : 0; #ifdef CONFIG_MX51 /* Can be used for i.MX31 too ? */ -- cgit v1.2.1 From 4ec3d2a7456eec28fd5bd33680f5e677ac5b0370 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Wed, 18 Aug 2010 10:22:42 +0200 Subject: MXC: Add watchdog support to serial driver Calls WATCHDOG_RESET() inside serial driver for boards enabling watchdog. Signed-off-by: Stefano Babic --- drivers/serial/serial_mxc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 4b93e7b97f..f96b21f7b1 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -18,6 +18,7 @@ */ #include +#include #ifdef CONFIG_MX31 #include #else @@ -189,7 +190,8 @@ void serial_setbrg (void) int serial_getc (void) { - while (__REG(UART_PHYS + UTS) & UTS_RXEMPTY); + while (__REG(UART_PHYS + UTS) & UTS_RXEMPTY) + WATCHDOG_RESET(); return (__REG(UART_PHYS + URXD) & URXD_RX_DATA); /* mask out status from upper word */ } @@ -198,7 +200,8 @@ void serial_putc (const char c) __REG(UART_PHYS + UTXD) = c; /* wait for transmitter to be ready */ - while(!(__REG(UART_PHYS + UTS) & UTS_TXEMPTY)); + while (!(__REG(UART_PHYS + UTS) & UTS_TXEMPTY)) + WATCHDOG_RESET(); /* If \n, also do \r */ if (c == '\n') -- cgit v1.2.1 From 9f481e95baaca2a5a739f930c16b1cc485b0c1f3 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Mon, 23 Aug 2010 20:41:19 +0200 Subject: MXC: Correct SPI_CPOL setting in SPI driver The handling of the SPI_CPOL bit inside the SPI driver was wrong. As reported by the manual, the meaning of the SSPOL inside the configuration register is the same as reported by SPI specification (0 if low in idle, 1 is high on idle). The driver inverts this logic. Because this patch sets the logic as specified, it is required to clear the CPOL bit in the configuration file to adapt to the correct logic. Signed-off-by: Stefano Babic Signed-off-by: David Jander --- drivers/spi/mxc_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 802cd2efb0..c6c8f60c30 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -215,7 +215,7 @@ static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs, if (mode & SPI_CS_HIGH) ss_pol = 1; - if (!(mode & SPI_CPOL)) + if (mode & SPI_CPOL) sclkpol = 1; if (mode & SPI_CPHA) @@ -412,7 +412,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, if (mode & SPI_CPHA) ctrl_reg |= MXC_CSPICTRL_PHA; - if (!(mode & SPI_CPOL)) + if (mode & SPI_CPOL) ctrl_reg |= MXC_CSPICTRL_POL; if (mode & SPI_CS_HIGH) ctrl_reg |= MXC_CSPICTRL_SSPOL; -- cgit v1.2.1 From 2f721d17339ee22bbc14fb0bb1dad20b82871923 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Fri, 20 Aug 2010 12:05:03 +0200 Subject: MXC: Fix byte-ordering in SPI driver for i.MX31/i.MX51 The actual SPI driver for i.MX31 and i.MX51 controller use a wrong byte ordering, because it is supposed to work only with Freescale's devices, as the Power Controllers (PMIC). The driver is not suitable for general purposes, because the buffers passed to spi_xfer must be 32-bit aligned, as it is used mainly to send integer to PMIC devices. The patch drops any kind of limitation and makes the driver useful with devices controlled sending commands composed by single bytes (or by a odd number of bytes), such as spi flash, sensor, etc. Because the byte ordering is changed, any current driver using this controller must be adapted, too. Signed-off-by: Stefano Babic --- drivers/misc/fsl_pmic.c | 10 +++- drivers/spi/mxc_spi.c | 149 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 118 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/fsl_pmic.c b/drivers/misc/fsl_pmic.c index dca0a1d57e..5ee1de176e 100644 --- a/drivers/misc/fsl_pmic.c +++ b/drivers/misc/fsl_pmic.c @@ -46,6 +46,7 @@ void pmic_spi_free(struct spi_slave *slave) u32 pmic_reg(u32 reg, u32 val, u32 write) { u32 pmic_tx, pmic_rx; + u32 tmp; if (!slave) { slave = pmic_spi_probe(); @@ -65,7 +66,9 @@ u32 pmic_reg(u32 reg, u32 val, u32 write) pmic_tx = (write << 31) | (reg << 25) | (val & 0x00FFFFFF); - if (spi_xfer(slave, 4 << 3, &pmic_tx, &pmic_rx, + tmp = cpu_to_be32(pmic_tx); + + if (spi_xfer(slave, 4 << 3, &tmp, &pmic_rx, SPI_XFER_BEGIN | SPI_XFER_END)) { spi_release_bus(slave); return -1; @@ -73,7 +76,8 @@ u32 pmic_reg(u32 reg, u32 val, u32 write) if (write) { pmic_tx &= ~(1 << 31); - if (spi_xfer(slave, 4 << 3, &pmic_tx, &pmic_rx, + tmp = cpu_to_be32(pmic_tx); + if (spi_xfer(slave, 4 << 3, &tmp, &pmic_rx, SPI_XFER_BEGIN | SPI_XFER_END)) { spi_release_bus(slave); return -1; @@ -81,7 +85,7 @@ u32 pmic_reg(u32 reg, u32 val, u32 write) } spi_release_bus(slave); - return pmic_rx; + return cpu_to_be32(pmic_rx); } void pmic_reg_write(u32 reg, u32 value) diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index c6c8f60c30..d558137c9d 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -62,6 +62,7 @@ #define MXC_CSPICTRL_MAXBITS 0x1f #define MXC_CSPIPERIOD_32KHZ (1 << 15) +#define MAX_SPI_BYTES 4 static unsigned long spi_bases[] = { 0x43fa4000, @@ -95,6 +96,7 @@ static unsigned long spi_bases[] = { #define MXC_CSPICTRL_RXOVF (1 << 6) #define MXC_CSPIPERIOD_32KHZ (1 << 15) +#define MAX_SPI_BYTES 32 /* Bit position inside CTRL register to be associated with SS */ #define MXC_CSPICTRL_CHAN 18 @@ -252,13 +254,15 @@ static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs, } #endif -static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen, - unsigned long flags) +int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, + const u8 *dout, u8 *din, unsigned long flags) { struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + int nbytes = (bitlen + 7) / 8; + u32 data, cnt, i; - if (flags & SPI_XFER_BEGIN) - spi_cs_activate(slave); + debug("%s: bitlen %d dout 0x%x din 0x%x\n", + __func__, bitlen, (u32)dout, (u32)din); mxcs->ctrl_reg = (mxcs->ctrl_reg & ~MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS)) | @@ -273,8 +277,46 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen, reg_write(mxcs->base + MXC_CSPISTAT, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); - debug("Sending SPI 0x%x\n", data); - reg_write(mxcs->base + MXC_CSPITXDATA, data); + /* + * The SPI controller works only with words, + * check if less than a word is sent. + * Access to the FIFO is only 32 bit + */ + if (bitlen % 32) { + data = 0; + cnt = (bitlen % 32) / 8; + if (dout) { + for (i = 0; i < cnt; i++) { + data = (data << 8) | (*dout++ & 0xFF); + } + } + debug("Sending SPI 0x%x\n", data); + + reg_write(mxcs->base + MXC_CSPITXDATA, data); + nbytes -= cnt; + } + + data = 0; + + while (nbytes > 0) { + data = 0; + if (dout) { + /* Buffer is not 32-bit aligned */ + if ((unsigned long)dout & 0x03) { + data = 0; + for (i = 0; i < 4; i++, data <<= 8) { + data = (data << 8) | (*dout++ & 0xFF); + } + } else { + data = *(u32 *)dout; + data = cpu_to_be32(data); + } + dout += 4; + } + debug("Sending SPI 0x%x\n", data); + reg_write(mxcs->base + MXC_CSPITXDATA, data); + nbytes -= 4; + } /* FIFO is written, now starts the transfer setting the XCH bit */ reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg | @@ -288,49 +330,78 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen, reg_write(mxcs->base + MXC_CSPISTAT, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); - data = reg_read(mxcs->base + MXC_CSPIRXDATA); - debug("SPI Rx: 0x%x\n", data); + nbytes = (bitlen + 7) / 8; - if (flags & SPI_XFER_END) - spi_cs_deactivate(slave); + cnt = nbytes % 32; - return data; + if (bitlen % 32) { + data = reg_read(mxcs->base + MXC_CSPIRXDATA); + cnt = (bitlen % 32) / 8; + debug("SPI Rx unaligned: 0x%x\n", data); + if (din) { + for (i = 0; i < cnt; i++, data >>= 8) { + *din++ = data & 0xFF; + } + } + nbytes -= cnt; + } + + while (nbytes > 0) { + u32 tmp; + tmp = reg_read(mxcs->base + MXC_CSPIRXDATA); + data = cpu_to_be32(tmp); + debug("SPI Rx: 0x%x 0x%x\n", tmp, data); + cnt = min(nbytes, sizeof(data)); + if (din) { + memcpy(din, &data, cnt); + din += cnt; + } + nbytes -= cnt; + } + + return 0; } + int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { - int n_blks = (bitlen + 31) / 32; - u32 *out_l, *in_l; - int i; + int n_bytes = (bitlen + 7) / 8; + int n_bits; + int ret; + u32 blk_size; + u8 *p_outbuf = (u8 *)dout; + u8 *p_inbuf = (u8 *)din; - if ((int)dout & 3 || (int)din & 3) { - printf("Error: unaligned buffers in: %p, out: %p\n", din, dout); - return 1; - } + if (!slave) + return -1; - /* This driver is currently partly broken, alert the user */ - if (bitlen > 16 && (bitlen % 32)) { - printf("Error: SPI transfer with bitlen=%d is broken.\n", - bitlen); - return 1; + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + while (n_bytes > 0) { + + if (n_bytes < MAX_SPI_BYTES) + blk_size = n_bytes; + else + blk_size = MAX_SPI_BYTES; + + n_bits = blk_size * 8; + + ret = spi_xchg_single(slave, n_bits, p_outbuf, p_inbuf, 0); + + if (ret) + return ret; + if (dout) + p_outbuf += blk_size; + if (din) + p_inbuf += blk_size; + n_bytes -= blk_size; } - for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout; - i < n_blks; - i++, in_l++, out_l++, bitlen -= 32) { - u32 data = spi_xchg_single(slave, *out_l, bitlen, flags); - - /* Check if we're only transfering 8 or 16 bits */ - if (!i) { - if (bitlen < 9) - *(u8 *)din = data; - else if (bitlen < 17) - *(u16 *)din = data; - else - *in_l = data; - } + if (flags & SPI_XFER_END) { + spi_cs_deactivate(slave); } return 0; @@ -378,8 +449,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, return NULL; mxcs = malloc(sizeof(struct mxc_spi_slave)); - if (!mxcs) + if (!mxcs) { + puts("mxc_spi: SPI Slave not allocated !\n"); return NULL; + } ret = decode_cs(mxcs, cs); if (ret < 0) { -- cgit v1.2.1