summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2014-03-20 09:20:36 +0000
committerBrian Norris <computersforpeace@gmail.com>2014-03-20 04:17:14 -0700
commit3c8b85b340c7a6b47d50c12c03661c23a5858b88 (patch)
tree3023497f1e5d493abb80d3c03428b707a2eef19c
parent86f309fd8fb291039a3776593a0b2a9d86c895ab (diff)
mtd: st_spi_fsm: Supply framework for device requests
The FSM hardware works by setting a predetermined sequence of register writes. Rather than open coding them inside each functional block we're going to define them in a series of formatted 'sequence structures'. This patch provides the framework which shall be used for every action. Acked-by Angus Clark <angus.clark@st.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
-rw-r--r--drivers/mtd/devices/st_spi_fsm.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
index 7048ea75bf27..5e22c8688197 100644
--- a/drivers/mtd/devices/st_spi_fsm.c
+++ b/drivers/mtd/devices/st_spi_fsm.c
@@ -194,6 +194,8 @@
#define STFSM_FLASH_SAFE_FREQ 10000000UL /* 10 MHz */
+#define STFSM_MAX_WAIT_SEQ_MS 1000 /* FSM execution time */
+
struct stfsm {
struct device *dev;
void __iomem *base;
@@ -204,6 +206,24 @@ struct stfsm {
uint32_t fifo_dir_delay;
};
+struct stfsm_seq {
+ uint32_t data_size;
+ uint32_t addr1;
+ uint32_t addr2;
+ uint32_t addr_cfg;
+ uint32_t seq_opc[5];
+ uint32_t mode;
+ uint32_t dummy;
+ uint32_t status;
+ uint8_t seq[16];
+ uint32_t seq_cfg;
+} __packed __aligned(4);
+
+static inline int stfsm_is_idle(struct stfsm *fsm)
+{
+ return readl(fsm->base + SPI_FAST_SEQ_STA) & 0x10;
+}
+
static inline uint32_t stfsm_fifo_available(struct stfsm *fsm)
{
return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f;
@@ -225,6 +245,42 @@ static void stfsm_clear_fifo(struct stfsm *fsm)
}
}
+static inline void stfsm_load_seq(struct stfsm *fsm,
+ const struct stfsm_seq *seq)
+{
+ void __iomem *dst = fsm->base + SPI_FAST_SEQ_TRANSFER_SIZE;
+ const uint32_t *src = (const uint32_t *)seq;
+ int words = sizeof(*seq) / sizeof(*src);
+
+ BUG_ON(!stfsm_is_idle(fsm));
+
+ while (words--) {
+ writel(*src, dst);
+ src++;
+ dst += 4;
+ }
+}
+
+static void stfsm_wait_seq(struct stfsm *fsm)
+{
+ unsigned long deadline;
+ int timeout = 0;
+
+ deadline = jiffies + msecs_to_jiffies(STFSM_MAX_WAIT_SEQ_MS);
+
+ while (!timeout) {
+ if (time_after_eq(jiffies, deadline))
+ timeout = 1;
+
+ if (stfsm_is_idle(fsm))
+ return;
+
+ cond_resched();
+ }
+
+ dev_err(fsm->dev, "timeout on sequence completion\n");
+}
+
static int stfsm_set_mode(struct stfsm *fsm, uint32_t mode)
{
int ret, timeout = 10;