summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMarkus Helgesson <markus.helgesson@stericsson.com>2010-09-22 11:12:24 +0200
committerMichael BRANDT <michael.brandt@stericsson.com>2010-11-04 09:01:38 +0100
commitb7642c0bdf7560c5645eecd59d95760dacd451a4 (patch)
tree086c74f8a72aa2eff010464db2b8e8ece5d58289 /drivers
parent4bcf2f4bbd3674edeb63b4cbfff27b34dfad1cda (diff)
U8500: Add support for SPI
Added SPI support for U8500 ST-Ericsson ID: 269867 ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-10121 Change-Id: Ied17dd39aa1ebc0ee95818c59c7f211ce655b8bf Signed-off-by: Markus Helgesson <markus.helgesson@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/7569 Reviewed-by: Michael BRANDT <michael.brandt@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/u8500_spi.c791
2 files changed, 792 insertions, 0 deletions
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 824d8e740..39699a47a 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -33,6 +33,7 @@ COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
+COBJS-$(CONFIG_U8500_SPI) += u8500_spi.o
COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
COBJS := $(COBJS-y)
diff --git a/drivers/spi/u8500_spi.c b/drivers/spi/u8500_spi.c
new file mode 100644
index 000000000..2a01c5da1
--- /dev/null
+++ b/drivers/spi/u8500_spi.c
@@ -0,0 +1,791 @@
+/*
+* Copyright (C) ST-Ericsson SA 2010
+* Author: Markus Helgesson <Markus.Helgesson@stericsson.com>
+* for ST-Ericsson.
+* License terms: GNU General Public License (GPL), version 2.
+*
+* This driver is influenced by spi-stm.c and stm_spi023.c
+* in the linux kernel.
+*/
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <spi.h>
+
+
+#ifndef CONFIG_U8500
+#error "This driver currently only supports the u8500 platform. Sorry."
+#endif
+
+
+/*#######################################################################
+ Print macros
+#########################################################################
+*/
+#define pr(pre, str, ...)\
+ printf(pre "[%s {%u}] " str "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define pr_err(str, ...) pr("E", str, ##__VA_ARGS__)
+#define pr_warn(str, ...) pr("W", str, ##__VA_ARGS__)
+
+#define dpr(pre, str, ...)\
+ debug(pre "[%s {%u}] " str "\n", __func__, __LINE__, ##__VA_ARGS__)
+#define pr_info(str, ...) dpr("I", str, ##__VA_ARGS__)
+#define pr_dbg(str, ...) dpr("D", str, ##__VA_ARGS__)
+
+
+/*#######################################################################
+ Register locations
+#########################################################################
+*/
+#ifdef U8500_SPI0_BASE
+#define SPI_0_BASE U8500_SPI0_BASE
+#endif
+
+#ifdef U8500_SPI1_BASE
+#define SPI_1_BASE U8500_SPI1_BASE
+#endif
+
+#ifdef U8500_SPI2_BASE
+#define SPI_2_BASE U8500_SPI2_BASE
+#endif
+
+#ifdef U8500_SPI3_BASE
+#define SPI_3_BASE U8500_SPI3_BASE
+#endif
+
+
+/*#######################################################################
+ Macros to access SPI Registers with their offsets
+#########################################################################
+*/
+#define SPI_CR0(r) ((u8 *)r + 0x000)
+#define SPI_CR1(r) ((u8 *)r + 0x004)
+#define SPI_DR(r) ((u8 *)r + 0x008)
+#define SPI_SR(r) ((u8 *)r + 0x00C)
+#define SPI_CPSR(r) ((u8 *)r + 0x010)
+
+/*#######################################################################
+ SPI Control Register 0 - SPI_CR0
+#########################################################################
+*/
+#define SPI_CR0_MASK_DSS ((u32)(0x1FUL << 0))
+#define SPI_CR0_MASK_SPO ((u32)(0x1UL << 6))
+#define SPI_CR0_MASK_SPH ((u32)(0x1UL << 7))
+#define SPI_CR0_MASK_SCR ((u32)(0xFFUL << 8))
+
+/*#######################################################################
+ SPI Control Register 0 - SPI_CR1
+#########################################################################
+*/
+#define SPI_CR1_MASK_SSE ((u32)(0x1UL << 1))
+#define SPI_CR1_MASK_RENDN ((u32)(0x1UL << 4))
+#define SPI_CR1_MASK_TENDN ((u32)(0x1UL << 5))
+
+/*#######################################################################
+ SPI Status Register - SPI_sr
+#########################################################################
+*/
+#define SPI_SR_MASK_TNF ((u32)(0x1UL << 1))
+#define SPI_SR_MASK_RNE ((u32)(0x1UL << 2))
+#define SPI_SR_MASK_BSY ((u32)(0x1UL << 4))
+
+/*#######################################################################
+ SPI Clock Prescale Register - SPI_cpsr
+#########################################################################
+*/
+#define SPI_CPSR_MASK_CPSDVSR ((u32)(0xFFUL << 0))
+
+/*#######################################################################
+ SPI Clock Parameter ranges
+#########################################################################
+*/
+#define MIN_CPSDVR 0x02
+#define MAX_CPSDVR 0xFE
+#define MIN_SCR 0x00
+#define MAX_SCR 0xFF
+#define STM_SPI_CLOCK_FREQ 48000000
+#define STM_SPICTLR_CLOCK_FREQ 48000000
+
+/*#######################################################################
+ Other macros
+#########################################################################
+*/
+#define SPI_REG_WRITE_BITS(reg, val, mask, sb) \
+ ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask))))
+
+#define ENABLE_SPI_CONTROLLER(sss)\
+ (writel((readl(SPI_CR1(sss->base_addr)) | SPI_CR1_MASK_SSE),\
+ SPI_CR1(sss->base_addr)))
+
+#define DISABLE_SPI_CONTROLLER(sss)\
+ (writel((readl(SPI_CR1(sss->base_addr)) & (~SPI_CR1_MASK_SSE)),\
+ SPI_CR1(sss->base_addr)))
+
+#define FLUSH_SPI_RX_FIFO(sss)\
+ do {\
+ while (readl(SPI_SR(sss->base_addr)) & SPI_SR_MASK_RNE)\
+ readl(SPI_DR(sss->base_addr)) ;\
+ } while (readl(SPI_SR(sss->base_addr)) & SPI_SR_MASK_BSY)
+
+#define WAIT_FOR_SPI_CONTROLLER_TO_FINISH(sss)\
+ while (readl(SPI_SR(sss->base_addr)) & SPI_SR_MASK_BSY)\
+ udelay(1)
+
+/*#######################################################################
+ Structures
+#########################################################################
+*/
+struct spi_regs {
+ u32 cr0;
+ u32 cr1;
+ u32 cpsr;
+};
+
+struct stm_spi_slave {
+ struct spi_slave slave;
+ u8 *base_addr;
+ u8 n_bytes;
+ struct spi_regs regs;
+ char dev_name[4];
+};
+
+/* Clock parameters, to set SPI clock at a desired freq */
+struct spi_clock_params {
+ u8 cpsdvsr; /* value from 2 to 254 (even only!) */
+ u8 scr; /* value from 0 to 255 */
+};
+
+struct spi_transfer {
+ u8 *current;
+ u8 *end;
+ u8 dummy_transfer;
+};
+
+/*#######################################################################
+ Local function declarations
+#########################################################################
+*/
+
+/*
+ * to_stm_spi_slave - Converts spi_slave ptr to struct stm_spi_slave ptr
+ */
+static inline struct stm_spi_slave *to_stm_spi_slave(struct spi_slave *slave)
+{
+ return container_of(slave, struct stm_spi_slave, slave);
+}
+
+/*
+ * spi_write - Write FIFO data in Data register
+ *
+ * This function writes data in Tx FIFO till it is not full
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary write ptr trans_data->current
+ * which maintains current write position in transfer buffer
+ */
+static void
+spi_write(struct stm_spi_slave *sss, struct spi_transfer * trans_data);
+
+ /*
+ * spi_read - Read FIFO data in Data register
+ *
+ * This function reads data in Rx FIFO till it is not empty
+ * which is indicated by the status register or our transfer is complete.
+ * It also updates the temporary Read ptr trans_data->current
+ * which maintains current read position in transfer buffer
+ */
+static void
+spi_read(struct stm_spi_slave *sss, struct spi_transfer * trans_data);
+
+ /*
+ * spi023_eff_freq - Calculates the frequency register values
+ */
+static int spi023_eff_freq(int freq, struct spi_clock_params *clk_freq);
+
+
+/*#######################################################################
+ Global function definitions (declared in spi.h)
+#########################################################################
+*/
+
+void spi_init()
+{
+ pr_dbg("");
+ /* nothing to do here */
+}
+
+struct spi_slave *spi_setup_slave(u32 bus, u32 cs, u32 max_hz, u32 mode)
+{
+ struct stm_spi_slave *sss;
+ u8 *base_addr;
+ u8 data_size;
+ struct spi_clock_params clk_freq;
+
+ pr_dbg("bus %u, cs %u, max_hz %u, mode 0x%x", bus, cs, max_hz, mode);
+
+ if (!spi_cs_is_valid(bus, cs)) {
+ pr_err("Invalid bus or cs in SPI configuration!");
+ return NULL;
+ }
+
+ switch (bus) {
+#ifdef SPI_0_BASE
+ case 0:
+ base_addr = (u8 *) SPI_0_BASE;
+ break;
+#endif
+#ifdef SPI_1_BASE
+ case 1:
+ base_addr = (u8 *) SPI_1_BASE;
+ break;
+#endif
+#ifdef SPI_2_BASE
+ case 2:
+ base_addr = (u8 *) SPI_2_BASE;
+ break;
+#endif
+#ifdef SPI_3_BASE
+ case 3:
+ base_addr = (u8 *) SPI_3_BASE;
+ break;
+#endif
+ default:
+ pr_err("Unknown SPI controller for bus %u.", bus);
+ return NULL;
+ }
+
+ clk_freq.scr = 0;
+ clk_freq.cpsdvsr = 0;
+ if (spi023_eff_freq(max_hz, &clk_freq))
+ return NULL;
+
+ pr_dbg("clk_freq.cpsdvsr = %u, clk_freq.scr = %u",
+ clk_freq.cpsdvsr, clk_freq.scr);
+
+ /*
+ * mode parameter bit definition:
+ *
+ * 0x0001 SPI_CPHA - clock phase
+ * 0x0002 SPI_CPOL - clock polarity
+ * 0x0004 NOT USED (reserved for SPI_CS_HIGH)
+ * 0x0008 SPI_LSB_FIRST - per-word bits-on-wire
+ * 0x0010 NOT USED (reserved for SPI_3WIRE)
+ * 0x0020 NOT USED (reserved for SPI_LOOP)
+ * 0x03C0 NOT USED (bits 6--9)
+ * 0x7C00 Data size select (bits 10--14),
+ * Size can be 4--32 bits and value is calculated as
+ * (desired data size - 1) so
+ * 0 0011 - 4-bit data size
+ * 0 0100 - 5 bit data size
+ * ...
+ * 1 1111 - 32-bit data size
+ */
+ data_size = ((mode & 0x7C00) >> 10) + 1;
+ if ((data_size < 4) || (data_size > 32)) {
+ pr_err("Data size %u bits is not supported.", data_size);
+ return NULL;
+ }
+
+ sss = malloc(sizeof(struct stm_spi_slave));
+ if (!sss) {
+ pr_err("Failed to allocate struct. Out of memory?");
+ return NULL;
+ }
+
+ sss->slave.bus = bus;
+ sss->slave.cs = cs;
+ sss->base_addr = base_addr;
+
+ if (data_size > 16)
+ sss->n_bytes = 4;
+ else if (data_size > 8)
+ sss->n_bytes = 2;
+ else
+ sss->n_bytes = 1;
+
+ sss->regs.cr0 = 0;
+ sss->regs.cr1 = 0;
+ sss->regs.cpsr = 0;
+
+ /* data size */
+ SPI_REG_WRITE_BITS(
+ sss->regs.cr0, (data_size-1), SPI_CR0_MASK_DSS, 0);
+
+ /* clock polarity */
+ if (mode & SPI_CPOL)
+ SPI_REG_WRITE_BITS(sss->regs.cr0, 1, SPI_CR0_MASK_SPO, 6);
+
+ /* clock phase */
+ if (mode & SPI_CPHA)
+ SPI_REG_WRITE_BITS(sss->regs.cr0, 1, SPI_CR0_MASK_SPH, 7);
+
+ /* serial clock rate */
+ SPI_REG_WRITE_BITS(sss->regs.cr0, clk_freq.scr, SPI_CR0_MASK_SCR, 8);
+
+ /* endian format */
+ if (mode & SPI_LSB_FIRST) {
+ SPI_REG_WRITE_BITS(sss->regs.cr1, 1, SPI_CR1_MASK_RENDN, 4);
+ SPI_REG_WRITE_BITS(sss->regs.cr1, 1, SPI_CR1_MASK_TENDN, 5);
+ }
+
+ /* clock prescale divisor */
+ SPI_REG_WRITE_BITS(
+ sss->regs.cpsr, clk_freq.cpsdvsr, SPI_CPSR_MASK_CPSDVSR, 0);
+
+ pr_dbg("sss->slave.bus = %u", sss->slave.bus);
+ pr_dbg("sss->slave.cs = %u", sss->slave.cs);
+ pr_dbg("sss->base_addr = 0x%p", sss->base_addr);
+ pr_dbg("sss->regs.cr0 = 0x%x", sss->regs.cr0);
+ pr_dbg("sss->regs.cr1 = 0x%x", sss->regs.cr1);
+ pr_dbg("sss->regs.cpsr = 0x%x", sss->regs.cpsr);
+
+ return (struct spi_slave *) sss;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct stm_spi_slave *sss = to_stm_spi_slave(slave);
+ pr_dbg("slave 0x%p", slave);
+
+ free(sss);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct stm_spi_slave *sss = to_stm_spi_slave(slave);
+ int ret = 0;
+ gpio_config pin_config;
+ gpio_pin clk_pin, frm_pin, txd_pin, rxd_pin;
+ gpio_alt_function altfunc;
+
+ pr_dbg("slave 0x%p", slave);
+
+ /*
+ * 0. Enable the clock to the SPI controller and
+ * configure controller specific information.
+ *
+ * TODO: The GPIO pins below are hardcoded for db8500.
+ */
+ switch (sss->slave.bus) {
+#if defined(SPI_0_BASE) && defined(CONFIG_U8500)
+ case 0:
+ altfunc = GPIO_ALT_SPI_0;
+ clk_pin = GPIO_PIN_220;
+ frm_pin = GPIO_PIN_223;
+ txd_pin = GPIO_PIN_224;
+ rxd_pin = GPIO_PIN_225;
+ u8500_clock_enable(2, 8, -1);
+ break;
+#endif
+#if defined(SPI_1_BASE) && defined(CONFIG_U8500)
+ case 1:
+ altfunc = GPIO_ALT_SPI_1;
+ clk_pin = GPIO_PIN_209;
+ frm_pin = GPIO_PIN_212;
+ txd_pin = GPIO_PIN_213;
+ rxd_pin = GPIO_PIN_214;
+ u8500_clock_enable(2, 2, -1);
+ break;
+#endif
+#if defined(SPI_2_BASE) && defined(CONFIG_U8500)
+ case 2:
+ altfunc = GPIO_ALT_SPI_2;
+ clk_pin = GPIO_PIN_217;
+ frm_pin = GPIO_PIN_216;
+ txd_pin = GPIO_PIN_215;
+ rxd_pin = GPIO_PIN_218;
+ u8500_clock_enable(2, 1, -1);
+
+ /*
+ * For SPI2 on u8500 the GPIO's need to be set to
+ * Other Alt C1 by setting bit 23 in PRCM_GPIOCR
+ * (GPIO muxing control register)
+ *
+ * TODO: This should be done nicer through some driver...
+ */
+ writel(readl(U8500_PRCMU_BASE + 0x138) | (1<<23),
+ (U8500_PRCMU_BASE + 0x138));
+ break;
+#endif
+#if defined(SPI_3_BASE) && defined(CONFIG_U8500)
+ case 3:
+ altfunc = GPIO_ALT_SPI_3;
+ clk_pin = GPIO_PIN_29;
+ frm_pin = GPIO_PIN_31;
+ txd_pin = GPIO_PIN_32;
+ rxd_pin = GPIO_PIN_30;
+ u8500_clock_enable(1, 7, -1);
+ break;
+#endif
+ default:
+ pr_err("Unknown SPI controller for bus %u.", sss->slave.bus);
+ return -1;
+ }
+
+ /* Sets the device name, for instance "SPI2" */
+ strcpy(sss->dev_name, "SPIx");
+ sss->dev_name[3] = ('0' + sss->slave.bus);
+
+
+ /*
+ * 1. Clear SSE bit in SPI_CR1 register. This step is not required
+ * after an hardware or software reset of the device.
+ * The input/output pins are switched to GPIO input mode.
+ */
+ DISABLE_SPI_CONTROLLER(sss);
+
+
+ /*
+ * 2. Empty the receive FIFO. This step is not required after an
+ * hardware or software reset of the device, as the FIFO pointer
+ * will be cleared.
+ */
+ FLUSH_SPI_RX_FIFO(sss);
+
+
+ /*
+ * 3. Program the GPIO on which SPI port signals are attached to
+ * deliver the SPI signals by setting bits alternate function
+ * enable GPIO_AFSLAx = 1b in GPIO register.
+ *
+ * First the GPIO's are configured in software mode so
+ * the pull-up/pull-down configuration is correctly applied.
+ * After that pins are set to the correct alternate mode.
+ */
+ pin_config.dev_name = "SPI_CLK";
+ pin_config.direction = GPIO_DIR_OUTPUT;
+ pin_config.mode = GPIO_MODE_SOFTWARE;
+ pin_config.trig = GPIO_TRIG_DISABLE;
+ ret = gpio_setpinconfig(clk_pin, &pin_config);
+ if (ret != 0) {
+ pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
+ ret, pin_config.dev_name, clk_pin, sss->dev_name);
+ return ret;
+ }
+
+ pin_config.dev_name = "SPI_FRM";
+ ret = gpio_setpinconfig(frm_pin, &pin_config);
+ if (ret != 0) {
+ pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
+ ret, pin_config.dev_name, frm_pin, sss->dev_name);
+ return ret;
+ }
+
+ pin_config.dev_name = "SPI_TXD";
+ ret = gpio_setpinconfig(txd_pin, &pin_config);
+ if (ret != 0) {
+ pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
+ ret, pin_config.dev_name, txd_pin, sss->dev_name);
+ return ret;
+ }
+
+ pin_config.dev_name = "SPI_RXD";
+ pin_config.direction = GPIO_DIR_INPUT;
+ ret = gpio_setpinconfig(rxd_pin, &pin_config);
+ if (ret != 0) {
+ pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
+ ret, pin_config.dev_name, rxd_pin, sss->dev_name);
+ return ret;
+ }
+
+ ret = gpio_altfuncenable(altfunc, sss->dev_name);
+ if (ret != 0) {
+ pr_err("Error %i when configuring '%s' to %i",
+ ret, sss->dev_name, altfunc);
+ return ret;
+ }
+
+
+ /*
+ * 4. Program the SPI clock prescale register, SPI_CPSR,
+ * then the configuration registers SPI_CR0 and SPI_CR1.
+ */
+ writel(sss->regs.cpsr, SPI_CPSR(sss->base_addr));
+ writel(sss->regs.cr0, SPI_CR0(sss->base_addr));
+ writel(sss->regs.cr1, SPI_CR1(sss->base_addr));
+
+
+ /*
+ * The remaining steps are done during the transfer:
+ *
+ * 5. write at least one word to the TxFIFO.
+ * 6. The transmit FIFO can optionally be filled before
+ * enabling the SPI.
+ * 7. Set SSE = 1b to enable the SPI operation.
+ */
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ pr_dbg("slave 0x%p", slave);
+
+ /* nothing to do here */
+}
+
+
+int spi_xfer(struct spi_slave *slave, u32 bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct stm_spi_slave *sss = to_stm_spi_slave(slave);
+ const u32 n_bytes = bitlen / 8;
+ int ret = 0;
+ int rx_max_tries;
+ struct spi_transfer tx;
+ struct spi_transfer rx;
+
+ pr_dbg("slave 0x%p, bitlen %u, dout 0x%p, din 0x%p, flags 0x%lx",
+ slave, bitlen, dout, din, flags);
+
+ if ((dout == NULL) && (din == NULL)) {
+ flags |= SPI_XFER_END;
+ pr_err("Both dout and din are NULL so there is nothing to do.");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Only accept bit lengths which are byte multiples and
+ * can be divided in chunks according to the configured
+ * data size set (DSS) according to
+ *
+ * DSS, bits n_bytes
+ * 3--8 n*1
+ * 9--16 n*2
+ * 17--32 n*4
+ *
+ * For instance, if DSS is 18 the driver will read 4 bytes from
+ * dout and write it to the SPI controller which will send the
+ * first 18 bits and simply discard the remaining 14 bits.
+ */
+ if ((bitlen % 8) || (n_bytes % sss->n_bytes)) {
+ flags |= SPI_XFER_END;
+ pr_err("bitlen is %u but %u is required for configured data size.",
+ bitlen, (sss->n_bytes * 8));
+ ret = -2;
+ goto end;
+ }
+
+ /*
+ * The SPI protocol works with both a write and a read, so if the user
+ * has not asked for a read or write we need to do a dummy one instead.
+ */
+ tx.dummy_transfer = ((dout == NULL) ? 1 : 0);
+ rx.dummy_transfer = ((din == NULL) ? 1 : 0);
+
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
+
+ tx.current = (u8 *) dout;
+ tx.end = tx.current + n_bytes;
+ rx.current = (u8 *) din;
+ rx.end = rx.current + n_bytes;
+
+ while (tx.current < tx.end) {
+ DISABLE_SPI_CONTROLLER(sss);
+ spi_read(sss, &rx);
+ spi_write(sss, &tx);
+ ENABLE_SPI_CONTROLLER(sss);
+ WAIT_FOR_SPI_CONTROLLER_TO_FINISH(sss);
+ }
+
+ /* try getting remaining rx bytes, if any */
+ rx_max_tries = 10;
+ while ((rx.current < rx.end) && (rx_max_tries--)) {
+ spi_read(sss, &rx);
+ WAIT_FOR_SPI_CONTROLLER_TO_FINISH(sss);
+ }
+
+end:
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
+
+ pr_dbg("returning with %i", ret);
+
+ return ret;
+}
+
+
+int spi_cs_is_valid(u32 bus, u32 cs)
+{
+ pr_dbg("bus %u, cs %u", bus, cs);
+
+ if (((bus >= 0) && (bus < 4)) && (cs == 0))
+ return 1;
+ else
+ return 0;
+}
+
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+ struct stm_spi_slave *sss = to_stm_spi_slave(slave);
+ pr_dbg("slave 0x%p", slave);
+
+ FLUSH_SPI_RX_FIFO(sss);
+ ENABLE_SPI_CONTROLLER(sss);
+}
+
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+ struct stm_spi_slave *sss = to_stm_spi_slave(slave);
+ pr_dbg("slave 0x%p", slave);
+
+ DISABLE_SPI_CONTROLLER(sss);
+}
+
+
+
+/*#######################################################################
+ Local function definitions
+#########################################################################
+*/
+
+/*
+ * spi023_eff_freq() is copied from stm_spi023.c
+ * with as few changes as possible.
+ */
+static int spi023_eff_freq(int freq, struct spi_clock_params *clk_freq)
+{
+ /* Lets calculate the frequency parameters */
+ u32 cpsdvsr = 2;
+ u32 scr = 0;
+ int freq_found = 0;
+ u32 max_tclk;
+ u32 min_tclk;
+ /* cpsdvscr = 2 & scr 0 */
+ max_tclk = (STM_SPICTLR_CLOCK_FREQ / (MIN_CPSDVR * (1 + MIN_SCR)));
+ /* cpsdvsr = 254 & scr = 255 */
+ min_tclk = (STM_SPICTLR_CLOCK_FREQ / (MAX_CPSDVR * (1 + MAX_SCR)));
+
+ if ((freq <= max_tclk) && (freq >= min_tclk)) {
+ while (cpsdvsr <= MAX_CPSDVR && !freq_found) {
+ while (scr <= MAX_SCR && !freq_found) {
+ if ((STM_SPICTLR_CLOCK_FREQ /
+ (cpsdvsr * (1 + scr))) > freq) {
+ scr += 1;
+ } else {
+ /*
+ * This bool is made TRUE when
+ * effective frequency >= target freq
+ * is found
+ */
+ freq_found = 1;
+ if ((STM_SPICTLR_CLOCK_FREQ /
+ (cpsdvsr * (1 + scr)))
+ != freq) {
+ if (scr == MIN_SCR) {
+ cpsdvsr -= 2;
+ scr = MAX_SCR;
+ } else {
+ scr -= 1;
+ }
+ }
+ }
+ }
+
+ if (!freq_found) {
+ cpsdvsr += 2;
+ scr = MIN_SCR;
+ }
+ }
+
+ if (cpsdvsr != 0) {
+ pr_info("SPI Effec Freq is 0x%x",
+ (STM_SPICTLR_CLOCK_FREQ / (cpsdvsr * (1 + scr)))
+ );
+
+ clk_freq->cpsdvsr = (u8) (cpsdvsr & 0xFF);
+ clk_freq->scr = (u8) (scr & 0xFF);
+
+ pr_dbg("SPI cpsdvsr = %d, scr = %d",
+ clk_freq->cpsdvsr, clk_freq->scr);
+ }
+ } else {
+ /* User is asking for out of range Freq. */
+ pr_err("setup - ctlr data incorrect: Out of Range Frequency");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+static void
+spi_write(struct stm_spi_slave *sss, struct spi_transfer * trans_data)
+{
+ pr_dbg("sss 0x%p, trans_data 0x%p, trans_data->current 0x%p ",
+ sss, trans_data, trans_data->current);
+
+ while ((readl(SPI_SR(sss->base_addr)) & SPI_SR_MASK_TNF)
+ && (trans_data->current < trans_data->end)) {
+ if (trans_data->dummy_transfer) {
+ writel(0x0, SPI_DR(sss->base_addr));
+ pr_dbg("Wrote 0x%08x", 0);
+ } else if (sss->n_bytes == 1) {
+ writeb(*(u8 *) (trans_data->current),
+ SPI_DR(sss->base_addr));
+ pr_dbg("Wrote 0x%08x",
+ (u32)(*(u8 *) (trans_data->current)));
+ } else if (sss->n_bytes == 2) {
+ writew(*(u16 *) (trans_data->current),
+ SPI_DR(sss->base_addr));
+ pr_dbg("Wrote 0x%08x",
+ (u32)(*(u16 *) (trans_data->current)));
+ } else if (sss->n_bytes == 4) {
+ writel(*(u32 *) (trans_data->current),
+ SPI_DR(sss->base_addr));
+ pr_dbg("Wrote 0x%08x",
+ (u32)(*(u32 *) (trans_data->current)));
+ } else {
+ pr_err("Invalid SPI configuration, n_bytes = %u",
+ sss->n_bytes);
+ trans_data->current = trans_data->end;
+ return;
+ }
+
+ trans_data->current += sss->n_bytes;
+ }
+}
+
+
+static void
+spi_read(struct stm_spi_slave *sss, struct spi_transfer * trans_data)
+{
+ pr_dbg("sss 0x%p, trans_data 0x%p, trans_data->current 0x%p ",
+ sss, trans_data, trans_data->current);
+
+ while ((readl(SPI_SR(sss->base_addr)) & SPI_SR_MASK_RNE)
+ && (trans_data->current < trans_data->end)) {
+ if (trans_data->dummy_transfer) {
+ (void)readl(SPI_DR(sss->base_addr));
+ } else if (sss->n_bytes == 1) {
+ *(u8 *) (trans_data->current) =
+ readb(SPI_DR(sss->base_addr));
+ pr_dbg("Read 0x%02x",
+ (u8)(*(u8 *) (trans_data->current)));
+ } else if (sss->n_bytes == 2) {
+ *(u16 *) (trans_data->current) =
+ readw(SPI_DR(sss->base_addr));
+ pr_dbg("Read 0x%04x",
+ (u16)(*(u16 *) (trans_data->current)));
+ } else if (sss->n_bytes == 4) {
+ *(u32 *) (trans_data->current) =
+ readl(SPI_DR(sss->base_addr));
+ pr_dbg("Read 0x%08x",
+ (u32)(*(u32 *) (trans_data->current)));
+ } else {
+ pr_err("Invalid SPI configuration, n_bytes = %u",
+ sss->n_bytes);
+ trans_data->current = trans_data->end;
+ return;
+ }
+
+ trans_data->current += sss->n_bytes;
+ }
+}