diff options
author | Lee Jones <lee.jones@linaro.org> | 2014-03-20 05:20:36 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2014-03-20 07:17:14 -0400 |
commit | 3c8b85b340c7a6b47d50c12c03661c23a5858b88 (patch) | |
tree | 3023497f1e5d493abb80d3c03428b707a2eef19c /drivers/mtd/devices | |
parent | 86f309fd8fb291039a3776593a0b2a9d86c895ab (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>
Diffstat (limited to 'drivers/mtd/devices')
-rw-r--r-- | drivers/mtd/devices/st_spi_fsm.c | 56 |
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 @@ | |||
194 | 194 | ||
195 | #define STFSM_FLASH_SAFE_FREQ 10000000UL /* 10 MHz */ | 195 | #define STFSM_FLASH_SAFE_FREQ 10000000UL /* 10 MHz */ |
196 | 196 | ||
197 | #define STFSM_MAX_WAIT_SEQ_MS 1000 /* FSM execution time */ | ||
198 | |||
197 | struct stfsm { | 199 | struct stfsm { |
198 | struct device *dev; | 200 | struct device *dev; |
199 | void __iomem *base; | 201 | void __iomem *base; |
@@ -204,6 +206,24 @@ struct stfsm { | |||
204 | uint32_t fifo_dir_delay; | 206 | uint32_t fifo_dir_delay; |
205 | }; | 207 | }; |
206 | 208 | ||
209 | struct stfsm_seq { | ||
210 | uint32_t data_size; | ||
211 | uint32_t addr1; | ||
212 | uint32_t addr2; | ||
213 | uint32_t addr_cfg; | ||
214 | uint32_t seq_opc[5]; | ||
215 | uint32_t mode; | ||
216 | uint32_t dummy; | ||
217 | uint32_t status; | ||
218 | uint8_t seq[16]; | ||
219 | uint32_t seq_cfg; | ||
220 | } __packed __aligned(4); | ||
221 | |||
222 | static inline int stfsm_is_idle(struct stfsm *fsm) | ||
223 | { | ||
224 | return readl(fsm->base + SPI_FAST_SEQ_STA) & 0x10; | ||
225 | } | ||
226 | |||
207 | static inline uint32_t stfsm_fifo_available(struct stfsm *fsm) | 227 | static inline uint32_t stfsm_fifo_available(struct stfsm *fsm) |
208 | { | 228 | { |
209 | return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f; | 229 | return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f; |
@@ -225,6 +245,42 @@ static void stfsm_clear_fifo(struct stfsm *fsm) | |||
225 | } | 245 | } |
226 | } | 246 | } |
227 | 247 | ||
248 | static inline void stfsm_load_seq(struct stfsm *fsm, | ||
249 | const struct stfsm_seq *seq) | ||
250 | { | ||
251 | void __iomem *dst = fsm->base + SPI_FAST_SEQ_TRANSFER_SIZE; | ||
252 | const uint32_t *src = (const uint32_t *)seq; | ||
253 | int words = sizeof(*seq) / sizeof(*src); | ||
254 | |||
255 | BUG_ON(!stfsm_is_idle(fsm)); | ||
256 | |||
257 | while (words--) { | ||
258 | writel(*src, dst); | ||
259 | src++; | ||
260 | dst += 4; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | static void stfsm_wait_seq(struct stfsm *fsm) | ||
265 | { | ||
266 | unsigned long deadline; | ||
267 | int timeout = 0; | ||
268 | |||
269 | deadline = jiffies + msecs_to_jiffies(STFSM_MAX_WAIT_SEQ_MS); | ||
270 | |||
271 | while (!timeout) { | ||
272 | if (time_after_eq(jiffies, deadline)) | ||
273 | timeout = 1; | ||
274 | |||
275 | if (stfsm_is_idle(fsm)) | ||
276 | return; | ||
277 | |||
278 | cond_resched(); | ||
279 | } | ||
280 | |||
281 | dev_err(fsm->dev, "timeout on sequence completion\n"); | ||
282 | } | ||
283 | |||
228 | static int stfsm_set_mode(struct stfsm *fsm, uint32_t mode) | 284 | static int stfsm_set_mode(struct stfsm *fsm, uint32_t mode) |
229 | { | 285 | { |
230 | int ret, timeout = 10; | 286 | int ret, timeout = 10; |