Blame view
drivers/spi/spi-fsl-spi.c
27.8 KB
ccf06998f [PATCH] spi: add ... |
1 |
/* |
b36ece832 spi/mpc8xxx: refa... |
2 |
* Freescale SPI controller driver. |
ccf06998f [PATCH] spi: add ... |
3 4 5 6 |
* * Maintainer: Kumar Gala * * Copyright (C) 2006 Polycom, Inc. |
b36ece832 spi/mpc8xxx: refa... |
7 |
* Copyright 2010 Freescale Semiconductor, Inc. |
ccf06998f [PATCH] spi: add ... |
8 |
* |
4c1fba442 spi_mpc8xxx: Add ... |
9 10 11 12 |
* CPM SPI and QE buffer descriptors mode support: * Copyright (c) 2009 MontaVista Software, Inc. * Author: Anton Vorontsov <avorontsov@ru.mvista.com> * |
ccf06998f [PATCH] spi: add ... |
13 14 15 16 17 18 |
* 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. */ #include <linux/module.h> |
ccf06998f [PATCH] spi: add ... |
19 20 |
#include <linux/types.h> #include <linux/kernel.h> |
ccf06998f [PATCH] spi: add ... |
21 22 23 |
#include <linux/interrupt.h> #include <linux/delay.h> #include <linux/irq.h> |
ccf06998f [PATCH] spi: add ... |
24 25 26 27 |
#include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/platform_device.h> #include <linux/fsl_devices.h> |
4c1fba442 spi_mpc8xxx: Add ... |
28 29 30 |
#include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/mutex.h> |
35b4b3c0c spi_mpc83xx: add ... |
31 32 33 34 |
#include <linux/of.h> #include <linux/of_platform.h> #include <linux/gpio.h> #include <linux/of_gpio.h> |
ccf06998f [PATCH] spi: add ... |
35 |
|
35b4b3c0c spi_mpc83xx: add ... |
36 |
#include <sysdev/fsl_soc.h> |
4c1fba442 spi_mpc8xxx: Add ... |
37 38 |
#include <asm/cpm.h> #include <asm/qe.h> |
b36ece832 spi/mpc8xxx: refa... |
39 |
|
ca632f556 spi: reorganize d... |
40 |
#include "spi-fsl-lib.h" |
ccf06998f [PATCH] spi: add ... |
41 |
|
4c1fba442 spi_mpc8xxx: Add ... |
42 43 44 45 46 47 48 49 |
/* CPM1 and CPM2 are mutually exclusive. */ #ifdef CONFIG_CPM1 #include <asm/cpm1.h> #define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0) #else #include <asm/cpm2.h> #define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0) #endif |
ccf06998f [PATCH] spi: add ... |
50 |
/* SPI Controller registers */ |
b36ece832 spi/mpc8xxx: refa... |
51 |
struct fsl_spi_reg { |
ccf06998f [PATCH] spi: add ... |
52 53 54 55 56 57 58 59 60 61 |
u8 res1[0x20]; __be32 mode; __be32 event; __be32 mask; __be32 command; __be32 transmit; __be32 receive; }; /* SPI Controller mode register definitions */ |
2a485d7ad spi_mpc83xx: supp... |
62 |
#define SPMODE_LOOP (1 << 30) |
ccf06998f [PATCH] spi: add ... |
63 64 65 66 67 68 69 70 |
#define SPMODE_CI_INACTIVEHIGH (1 << 29) #define SPMODE_CP_BEGIN_EDGECLK (1 << 28) #define SPMODE_DIV16 (1 << 27) #define SPMODE_REV (1 << 26) #define SPMODE_MS (1 << 25) #define SPMODE_ENABLE (1 << 24) #define SPMODE_LEN(x) ((x) << 20) #define SPMODE_PM(x) ((x) << 16) |
f29ba280e spi_mpc83xx.c: su... |
71 |
#define SPMODE_OP (1 << 14) |
c9bfcb315 spi_mpc83xx: much... |
72 |
#define SPMODE_CG(x) ((x) << 7) |
ccf06998f [PATCH] spi: add ... |
73 74 75 |
/* * Default for SPI Mode: |
b36ece832 spi/mpc8xxx: refa... |
76 |
* SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk |
ccf06998f [PATCH] spi: add ... |
77 78 79 80 81 82 83 84 85 86 87 |
*/ #define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \ SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf)) /* SPIE register values */ #define SPIE_NE 0x00000200 /* Not empty */ #define SPIE_NF 0x00000100 /* Not full */ /* SPIM register values */ #define SPIM_NE 0x00000200 /* Not empty */ #define SPIM_NF 0x00000100 /* Not full */ |
4c1fba442 spi_mpc8xxx: Add ... |
88 89 90 91 92 93 94 95 |
#define SPIE_TXB 0x00000200 /* Last char is written to tx fifo */ #define SPIE_RXB 0x00000100 /* Last char is written to rx buf */ /* SPCOM register values */ #define SPCOM_STR (1 << 23) /* Start transmit */ #define SPI_PRAM_SIZE 0x100 #define SPI_MRBLR ((unsigned int)PAGE_SIZE) |
b36ece832 spi/mpc8xxx: refa... |
96 97 98 |
static void *fsl_dummy_rx; static DEFINE_MUTEX(fsl_dummy_rx_lock); static int fsl_dummy_rx_refcnt; |
ccf06998f [PATCH] spi: add ... |
99 |
|
b36ece832 spi/mpc8xxx: refa... |
100 |
static void fsl_spi_change_mode(struct spi_device *spi) |
a35c17109 spi_mpc8xxx: Fact... |
101 102 103 |
{ struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi->controller_state; |
b36ece832 spi/mpc8xxx: refa... |
104 105 |
struct fsl_spi_reg *reg_base = mspi->reg_base; __be32 __iomem *mode = ®_base->mode; |
a35c17109 spi_mpc8xxx: Fact... |
106 107 108 109 110 111 112 113 114 115 |
unsigned long flags; if (cs->hw_mode == mpc8xxx_spi_read_reg(mode)) return; /* Turn off IRQs locally to minimize time that SPI is disabled. */ local_irq_save(flags); /* Turn off SPI unit prior changing mode */ mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE); |
a35c17109 spi_mpc8xxx: Fact... |
116 |
|
4c1fba442 spi_mpc8xxx: Add ... |
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
/* When in CPM mode, we need to reinit tx and rx. */ if (mspi->flags & SPI_CPM_MODE) { if (mspi->flags & SPI_QE) { qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock, QE_CR_PROTOCOL_UNSPECIFIED, 0); } else { cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX); if (mspi->flags & SPI_CPM1) { out_be16(&mspi->pram->rbptr, in_be16(&mspi->pram->rbase)); out_be16(&mspi->pram->tbptr, in_be16(&mspi->pram->tbase)); } } } |
f9218c2a6 spi/spi_mpc8xxx: ... |
132 |
mpc8xxx_spi_write_reg(mode, cs->hw_mode); |
a35c17109 spi_mpc8xxx: Fact... |
133 134 |
local_irq_restore(flags); } |
b36ece832 spi/mpc8xxx: refa... |
135 |
static void fsl_spi_chipselect(struct spi_device *spi, int value) |
ccf06998f [PATCH] spi: add ... |
136 |
{ |
575c5807f spi_mpc8xxx: s/83... |
137 |
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); |
364fdbc00 spi_mpc83xx: rewo... |
138 139 |
struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data; bool pol = spi->mode & SPI_CS_HIGH; |
575c5807f spi_mpc8xxx: s/83... |
140 |
struct spi_mpc8xxx_cs *cs = spi->controller_state; |
ccf06998f [PATCH] spi: add ... |
141 |
|
ccf06998f [PATCH] spi: add ... |
142 |
if (value == BITBANG_CS_INACTIVE) { |
364fdbc00 spi_mpc83xx: rewo... |
143 144 |
if (pdata->cs_control) pdata->cs_control(spi, !pol); |
ccf06998f [PATCH] spi: add ... |
145 146 147 |
} if (value == BITBANG_CS_ACTIVE) { |
575c5807f spi_mpc8xxx: s/83... |
148 149 150 151 |
mpc8xxx_spi->rx_shift = cs->rx_shift; mpc8xxx_spi->tx_shift = cs->tx_shift; mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; |
c9bfcb315 spi_mpc83xx: much... |
152 |
|
b36ece832 spi/mpc8xxx: refa... |
153 |
fsl_spi_change_mode(spi); |
a35c17109 spi_mpc8xxx: Fact... |
154 |
|
364fdbc00 spi_mpc83xx: rewo... |
155 156 |
if (pdata->cs_control) pdata->cs_control(spi, pol); |
ccf06998f [PATCH] spi: add ... |
157 158 |
} } |
b36ece832 spi/mpc8xxx: refa... |
159 160 161 162 |
static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs, struct spi_device *spi, struct mpc8xxx_spi *mpc8xxx_spi, int bits_per_word) |
ccf06998f [PATCH] spi: add ... |
163 |
{ |
c9bfcb315 spi_mpc83xx: much... |
164 165 |
cs->rx_shift = 0; cs->tx_shift = 0; |
ccf06998f [PATCH] spi: add ... |
166 |
if (bits_per_word <= 8) { |
575c5807f spi_mpc8xxx: s/83... |
167 168 |
cs->get_rx = mpc8xxx_spi_rx_buf_u8; cs->get_tx = mpc8xxx_spi_tx_buf_u8; |
87ec0e98c spi_mpc8xxx: Turn... |
169 |
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { |
c9bfcb315 spi_mpc83xx: much... |
170 171 |
cs->rx_shift = 16; cs->tx_shift = 24; |
f29ba280e spi_mpc83xx.c: su... |
172 |
} |
ccf06998f [PATCH] spi: add ... |
173 |
} else if (bits_per_word <= 16) { |
575c5807f spi_mpc8xxx: s/83... |
174 175 |
cs->get_rx = mpc8xxx_spi_rx_buf_u16; cs->get_tx = mpc8xxx_spi_tx_buf_u16; |
87ec0e98c spi_mpc8xxx: Turn... |
176 |
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { |
c9bfcb315 spi_mpc83xx: much... |
177 178 |
cs->rx_shift = 16; cs->tx_shift = 16; |
f29ba280e spi_mpc83xx.c: su... |
179 |
} |
ccf06998f [PATCH] spi: add ... |
180 |
} else if (bits_per_word <= 32) { |
575c5807f spi_mpc8xxx: s/83... |
181 182 |
cs->get_rx = mpc8xxx_spi_rx_buf_u32; cs->get_tx = mpc8xxx_spi_tx_buf_u32; |
ccf06998f [PATCH] spi: add ... |
183 184 |
} else return -EINVAL; |
87ec0e98c spi_mpc8xxx: Turn... |
185 |
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE && |
0398fb709 spi/spi_mpc8xxx: ... |
186 |
spi->mode & SPI_LSB_FIRST) { |
c9bfcb315 spi_mpc83xx: much... |
187 |
cs->tx_shift = 0; |
35cc0b975 spi_mpc83xx: fix ... |
188 |
if (bits_per_word <= 8) |
c9bfcb315 spi_mpc83xx: much... |
189 |
cs->rx_shift = 8; |
35cc0b975 spi_mpc83xx: fix ... |
190 |
else |
c9bfcb315 spi_mpc83xx: much... |
191 |
cs->rx_shift = 0; |
35cc0b975 spi_mpc83xx: fix ... |
192 |
} |
575c5807f spi_mpc8xxx: s/83... |
193 194 195 196 |
mpc8xxx_spi->rx_shift = cs->rx_shift; mpc8xxx_spi->tx_shift = cs->tx_shift; mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; |
ccf06998f [PATCH] spi: add ... |
197 |
|
0398fb709 spi/spi_mpc8xxx: ... |
198 199 |
return bits_per_word; } |
b36ece832 spi/mpc8xxx: refa... |
200 201 202 |
static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs, struct spi_device *spi, int bits_per_word) |
0398fb709 spi/spi_mpc8xxx: ... |
203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
{ /* QE uses Little Endian for words > 8 * so transform all words > 8 into 8 bits * Unfortnatly that doesn't work for LSB so * reject these for now */ /* Note: 32 bits word, LSB works iff * tfcr/rfcr is set to CPMFCR_GBL */ if (spi->mode & SPI_LSB_FIRST && bits_per_word > 8) return -EINVAL; if (bits_per_word > 8) return 8; /* pretend its 8 bits */ return bits_per_word; } |
b36ece832 spi/mpc8xxx: refa... |
217 218 |
static int fsl_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) |
0398fb709 spi/spi_mpc8xxx: ... |
219 220 |
{ struct mpc8xxx_spi *mpc8xxx_spi; |
b36ece832 spi/mpc8xxx: refa... |
221 |
int bits_per_word = 0; |
0398fb709 spi/spi_mpc8xxx: ... |
222 |
u8 pm; |
b36ece832 spi/mpc8xxx: refa... |
223 |
u32 hz = 0; |
0398fb709 spi/spi_mpc8xxx: ... |
224 225 226 227 228 229 230 |
struct spi_mpc8xxx_cs *cs = spi->controller_state; mpc8xxx_spi = spi_master_get_devdata(spi->master); if (t) { bits_per_word = t->bits_per_word; hz = t->speed_hz; |
0398fb709 spi/spi_mpc8xxx: ... |
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
} /* spi_transfer level calls that work per-word */ if (!bits_per_word) bits_per_word = spi->bits_per_word; /* Make sure its a bit width we support [4..16, 32] */ if ((bits_per_word < 4) || ((bits_per_word > 16) && (bits_per_word != 32))) return -EINVAL; if (!hz) hz = spi->max_speed_hz; if (!(mpc8xxx_spi->flags & SPI_CPM_MODE)) bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi, mpc8xxx_spi, bits_per_word); else if (mpc8xxx_spi->flags & SPI_QE) bits_per_word = mspi_apply_qe_mode_quirks(cs, spi, bits_per_word); if (bits_per_word < 0) return bits_per_word; |
ccf06998f [PATCH] spi: add ... |
255 256 257 258 |
if (bits_per_word == 32) bits_per_word = 0; else bits_per_word = bits_per_word - 1; |
32421daaf spi_mpc83xx: supp... |
259 |
/* mask out bits we are going to set */ |
c9bfcb315 spi_mpc83xx: much... |
260 261 262 263 |
cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16 | SPMODE_PM(0xF)); cs->hw_mode |= SPMODE_LEN(bits_per_word); |
575c5807f spi_mpc8xxx: s/83... |
264 |
if ((mpc8xxx_spi->spibrg / hz) > 64) { |
53604dbe1 spi_mpc83xx: fix ... |
265 |
cs->hw_mode |= SPMODE_DIV16; |
4f4517c45 spi: Correct SPI ... |
266 |
pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1; |
fd8a11e10 spi_mpc83xx: quie... |
267 268 269 270 |
WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. " "Will use %d Hz instead. ", dev_name(&spi->dev), |
575c5807f spi_mpc8xxx: s/83... |
271 |
hz, mpc8xxx_spi->spibrg / 1024); |
fd8a11e10 spi_mpc83xx: quie... |
272 |
if (pm > 16) |
53604dbe1 spi_mpc83xx: fix ... |
273 |
pm = 16; |
b36ece832 spi/mpc8xxx: refa... |
274 |
} else { |
4f4517c45 spi: Correct SPI ... |
275 |
pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1; |
b36ece832 spi/mpc8xxx: refa... |
276 |
} |
a61f5345e spi: spi_mpc83xx ... |
277 278 279 280 |
if (pm) pm--; cs->hw_mode |= SPMODE_PM(pm); |
a35c17109 spi_mpc8xxx: Fact... |
281 |
|
b36ece832 spi/mpc8xxx: refa... |
282 |
fsl_spi_change_mode(spi); |
c9bfcb315 spi_mpc83xx: much... |
283 284 |
return 0; } |
ccf06998f [PATCH] spi: add ... |
285 |
|
b36ece832 spi/mpc8xxx: refa... |
286 |
static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) |
c9bfcb315 spi_mpc83xx: much... |
287 |
{ |
4c1fba442 spi_mpc8xxx: Add ... |
288 289 290 291 |
struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd; struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd; unsigned int xfer_len = min(mspi->count, SPI_MRBLR); unsigned int xfer_ofs; |
b36ece832 spi/mpc8xxx: refa... |
292 |
struct fsl_spi_reg *reg_base = mspi->reg_base; |
ccf06998f [PATCH] spi: add ... |
293 |
|
4c1fba442 spi_mpc8xxx: Add ... |
294 |
xfer_ofs = mspi->xfer_in_progress->len - mspi->count; |
37880c909 spi/mpc8xxx: fix ... |
295 296 297 298 |
if (mspi->rx_dma == mspi->dma_dummy_rx) out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma); else out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs); |
4c1fba442 spi_mpc8xxx: Add ... |
299 300 |
out_be16(&rx_bd->cbd_datlen, 0); out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP); |
37880c909 spi/mpc8xxx: fix ... |
301 302 303 304 |
if (mspi->tx_dma == mspi->dma_dummy_tx) out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma); else out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs); |
4c1fba442 spi_mpc8xxx: Add ... |
305 306 307 308 309 |
out_be16(&tx_bd->cbd_datlen, xfer_len); out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | BD_SC_LAST); /* start transfer */ |
b36ece832 spi/mpc8xxx: refa... |
310 |
mpc8xxx_spi_write_reg(®_base->command, SPCOM_STR); |
4c1fba442 spi_mpc8xxx: Add ... |
311 |
} |
b36ece832 spi/mpc8xxx: refa... |
312 |
static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, |
4c1fba442 spi_mpc8xxx: Add ... |
313 314 315 |
struct spi_transfer *t, bool is_dma_mapped) { struct device *dev = mspi->dev; |
b36ece832 spi/mpc8xxx: refa... |
316 |
struct fsl_spi_reg *reg_base = mspi->reg_base; |
4c1fba442 spi_mpc8xxx: Add ... |
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
if (is_dma_mapped) { mspi->map_tx_dma = 0; mspi->map_rx_dma = 0; } else { mspi->map_tx_dma = 1; mspi->map_rx_dma = 1; } if (!t->tx_buf) { mspi->tx_dma = mspi->dma_dummy_tx; mspi->map_tx_dma = 0; } if (!t->rx_buf) { mspi->rx_dma = mspi->dma_dummy_rx; mspi->map_rx_dma = 0; } if (mspi->map_tx_dma) { void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */ mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len, DMA_TO_DEVICE); if (dma_mapping_error(dev, mspi->tx_dma)) { dev_err(dev, "unable to map tx dma "); return -ENOMEM; } |
f9218c2a6 spi/spi_mpc8xxx: ... |
346 |
} else if (t->tx_buf) { |
4c1fba442 spi_mpc8xxx: Add ... |
347 348 349 350 351 352 353 354 355 356 357 |
mspi->tx_dma = t->tx_dma; } if (mspi->map_rx_dma) { mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len, DMA_FROM_DEVICE); if (dma_mapping_error(dev, mspi->rx_dma)) { dev_err(dev, "unable to map rx dma "); goto err_rx_dma; } |
f9218c2a6 spi/spi_mpc8xxx: ... |
358 |
} else if (t->rx_buf) { |
4c1fba442 spi_mpc8xxx: Add ... |
359 360 361 362 |
mspi->rx_dma = t->rx_dma; } /* enable rx ints */ |
b36ece832 spi/mpc8xxx: refa... |
363 |
mpc8xxx_spi_write_reg(®_base->mask, SPIE_RXB); |
4c1fba442 spi_mpc8xxx: Add ... |
364 365 366 367 368 |
mspi->xfer_in_progress = t; mspi->count = t->len; /* start CPM transfers */ |
b36ece832 spi/mpc8xxx: refa... |
369 |
fsl_spi_cpm_bufs_start(mspi); |
4c1fba442 spi_mpc8xxx: Add ... |
370 371 372 373 374 375 376 377 |
return 0; err_rx_dma: if (mspi->map_tx_dma) dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); return -ENOMEM; } |
b36ece832 spi/mpc8xxx: refa... |
378 |
static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) |
4c1fba442 spi_mpc8xxx: Add ... |
379 380 381 382 383 384 |
{ struct device *dev = mspi->dev; struct spi_transfer *t = mspi->xfer_in_progress; if (mspi->map_tx_dma) dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); |
338ff2982 spi/spi_mpc8xxx: ... |
385 |
if (mspi->map_rx_dma) |
4c1fba442 spi_mpc8xxx: Add ... |
386 387 388 |
dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE); mspi->xfer_in_progress = NULL; } |
b36ece832 spi/mpc8xxx: refa... |
389 |
static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi, |
4c1fba442 spi_mpc8xxx: Add ... |
390 391 392 |
struct spi_transfer *t, unsigned int len) { u32 word; |
b36ece832 spi/mpc8xxx: refa... |
393 |
struct fsl_spi_reg *reg_base = mspi->reg_base; |
4c1fba442 spi_mpc8xxx: Add ... |
394 395 396 397 |
mspi->count = len; /* enable rx ints */ |
b36ece832 spi/mpc8xxx: refa... |
398 |
mpc8xxx_spi_write_reg(®_base->mask, SPIM_NE); |
4c1fba442 spi_mpc8xxx: Add ... |
399 400 401 |
/* transmit word */ word = mspi->get_tx(mspi); |
b36ece832 spi/mpc8xxx: refa... |
402 |
mpc8xxx_spi_write_reg(®_base->transmit, word); |
4c1fba442 spi_mpc8xxx: Add ... |
403 404 405 |
return 0; } |
b36ece832 spi/mpc8xxx: refa... |
406 |
static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, |
4c1fba442 spi_mpc8xxx: Add ... |
407 408 409 |
bool is_dma_mapped) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); |
b36ece832 spi/mpc8xxx: refa... |
410 |
struct fsl_spi_reg *reg_base; |
4c1fba442 spi_mpc8xxx: Add ... |
411 412 413 |
unsigned int len = t->len; u8 bits_per_word; int ret; |
c9bfcb315 spi_mpc83xx: much... |
414 |
|
b36ece832 spi/mpc8xxx: refa... |
415 |
reg_base = mpc8xxx_spi->reg_base; |
c9bfcb315 spi_mpc83xx: much... |
416 417 418 |
bits_per_word = spi->bits_per_word; if (t->bits_per_word) bits_per_word = t->bits_per_word; |
4c1fba442 spi_mpc8xxx: Add ... |
419 |
|
aa77d96ba spi_mpc83xx: reje... |
420 421 422 423 |
if (bits_per_word > 8) { /* invalid length? */ if (len & 1) return -EINVAL; |
c9bfcb315 spi_mpc83xx: much... |
424 |
len /= 2; |
aa77d96ba spi_mpc83xx: reje... |
425 426 427 428 429 |
} if (bits_per_word > 16) { /* invalid length? */ if (len & 1) return -EINVAL; |
c9bfcb315 spi_mpc83xx: much... |
430 |
len /= 2; |
aa77d96ba spi_mpc83xx: reje... |
431 |
} |
aa77d96ba spi_mpc83xx: reje... |
432 |
|
4c1fba442 spi_mpc8xxx: Add ... |
433 434 |
mpc8xxx_spi->tx = t->tx_buf; mpc8xxx_spi->rx = t->rx_buf; |
c9bfcb315 spi_mpc83xx: much... |
435 |
|
4c1fba442 spi_mpc8xxx: Add ... |
436 |
INIT_COMPLETION(mpc8xxx_spi->done); |
c9bfcb315 spi_mpc83xx: much... |
437 |
|
4c1fba442 spi_mpc8xxx: Add ... |
438 |
if (mpc8xxx_spi->flags & SPI_CPM_MODE) |
b36ece832 spi/mpc8xxx: refa... |
439 |
ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped); |
4c1fba442 spi_mpc8xxx: Add ... |
440 |
else |
b36ece832 spi/mpc8xxx: refa... |
441 |
ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len); |
4c1fba442 spi_mpc8xxx: Add ... |
442 443 |
if (ret) return ret; |
c9bfcb315 spi_mpc83xx: much... |
444 |
|
575c5807f spi_mpc8xxx: s/83... |
445 |
wait_for_completion(&mpc8xxx_spi->done); |
c9bfcb315 spi_mpc83xx: much... |
446 447 |
/* disable rx ints */ |
b36ece832 spi/mpc8xxx: refa... |
448 |
mpc8xxx_spi_write_reg(®_base->mask, 0); |
c9bfcb315 spi_mpc83xx: much... |
449 |
|
4c1fba442 spi_mpc8xxx: Add ... |
450 |
if (mpc8xxx_spi->flags & SPI_CPM_MODE) |
b36ece832 spi/mpc8xxx: refa... |
451 |
fsl_spi_cpm_bufs_complete(mpc8xxx_spi); |
4c1fba442 spi_mpc8xxx: Add ... |
452 |
|
575c5807f spi_mpc8xxx: s/83... |
453 |
return mpc8xxx_spi->count; |
c9bfcb315 spi_mpc83xx: much... |
454 |
} |
b36ece832 spi/mpc8xxx: refa... |
455 |
static void fsl_spi_do_one_msg(struct spi_message *m) |
c9bfcb315 spi_mpc83xx: much... |
456 |
{ |
b9b9af11f spi_mpc83xx: spli... |
457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
struct spi_device *spi = m->spi; struct spi_transfer *t; unsigned int cs_change; const int nsecs = 50; int status; cs_change = 1; status = 0; list_for_each_entry(t, &m->transfers, transfer_list) { if (t->bits_per_word || t->speed_hz) { /* Don't allow changes if CS is active */ status = -EINVAL; if (cs_change) |
b36ece832 spi/mpc8xxx: refa... |
471 |
status = fsl_spi_setup_transfer(spi, t); |
b9b9af11f spi_mpc83xx: spli... |
472 |
if (status < 0) |
c9bfcb315 spi_mpc83xx: much... |
473 |
break; |
b9b9af11f spi_mpc83xx: spli... |
474 |
} |
c9bfcb315 spi_mpc83xx: much... |
475 |
|
b9b9af11f spi_mpc83xx: spli... |
476 |
if (cs_change) { |
b36ece832 spi/mpc8xxx: refa... |
477 |
fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE); |
b9b9af11f spi_mpc83xx: spli... |
478 479 480 481 |
ndelay(nsecs); } cs_change = t->cs_change; if (t->len) |
b36ece832 spi/mpc8xxx: refa... |
482 |
status = fsl_spi_bufs(spi, t, m->is_dma_mapped); |
b9b9af11f spi_mpc83xx: spli... |
483 484 485 |
if (status) { status = -EMSGSIZE; break; |
c9bfcb315 spi_mpc83xx: much... |
486 |
} |
b9b9af11f spi_mpc83xx: spli... |
487 |
m->actual_length += t->len; |
c9bfcb315 spi_mpc83xx: much... |
488 |
|
b9b9af11f spi_mpc83xx: spli... |
489 490 |
if (t->delay_usecs) udelay(t->delay_usecs); |
c9bfcb315 spi_mpc83xx: much... |
491 |
|
b9b9af11f spi_mpc83xx: spli... |
492 |
if (cs_change) { |
c9bfcb315 spi_mpc83xx: much... |
493 |
ndelay(nsecs); |
b36ece832 spi/mpc8xxx: refa... |
494 |
fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); |
b9b9af11f spi_mpc83xx: spli... |
495 |
ndelay(nsecs); |
c9bfcb315 spi_mpc83xx: much... |
496 |
} |
b9b9af11f spi_mpc83xx: spli... |
497 498 499 500 501 502 503 |
} m->status = status; m->complete(m->context); if (status || !cs_change) { ndelay(nsecs); |
b36ece832 spi/mpc8xxx: refa... |
504 |
fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE); |
b9b9af11f spi_mpc83xx: spli... |
505 |
} |
b36ece832 spi/mpc8xxx: refa... |
506 |
fsl_spi_setup_transfer(spi, NULL); |
ccf06998f [PATCH] spi: add ... |
507 |
} |
b36ece832 spi/mpc8xxx: refa... |
508 |
static int fsl_spi_setup(struct spi_device *spi) |
ccf06998f [PATCH] spi: add ... |
509 |
{ |
575c5807f spi_mpc8xxx: s/83... |
510 |
struct mpc8xxx_spi *mpc8xxx_spi; |
b36ece832 spi/mpc8xxx: refa... |
511 |
struct fsl_spi_reg *reg_base; |
ccf06998f [PATCH] spi: add ... |
512 |
int retval; |
c9bfcb315 spi_mpc83xx: much... |
513 |
u32 hw_mode; |
575c5807f spi_mpc8xxx: s/83... |
514 |
struct spi_mpc8xxx_cs *cs = spi->controller_state; |
ccf06998f [PATCH] spi: add ... |
515 516 517 |
if (!spi->max_speed_hz) return -EINVAL; |
c9bfcb315 spi_mpc83xx: much... |
518 519 520 521 522 523 |
if (!cs) { cs = kzalloc(sizeof *cs, GFP_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; } |
575c5807f spi_mpc8xxx: s/83... |
524 |
mpc8xxx_spi = spi_master_get_devdata(spi->master); |
ccf06998f [PATCH] spi: add ... |
525 |
|
b36ece832 spi/mpc8xxx: refa... |
526 |
reg_base = mpc8xxx_spi->reg_base; |
883931612 Fix typos in comm... |
527 |
hw_mode = cs->hw_mode; /* Save original settings */ |
b36ece832 spi/mpc8xxx: refa... |
528 |
cs->hw_mode = mpc8xxx_spi_read_reg(®_base->mode); |
c9bfcb315 spi_mpc83xx: much... |
529 530 531 532 533 534 535 536 537 538 539 540 |
/* mask out bits we are going to set */ cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH | SPMODE_REV | SPMODE_LOOP); if (spi->mode & SPI_CPHA) cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK; if (spi->mode & SPI_CPOL) cs->hw_mode |= SPMODE_CI_INACTIVEHIGH; if (!(spi->mode & SPI_LSB_FIRST)) cs->hw_mode |= SPMODE_REV; if (spi->mode & SPI_LOOP) cs->hw_mode |= SPMODE_LOOP; |
b36ece832 spi/mpc8xxx: refa... |
541 |
retval = fsl_spi_setup_transfer(spi, NULL); |
c9bfcb315 spi_mpc83xx: much... |
542 543 |
if (retval < 0) { cs->hw_mode = hw_mode; /* Restore settings */ |
ccf06998f [PATCH] spi: add ... |
544 |
return retval; |
c9bfcb315 spi_mpc83xx: much... |
545 |
} |
ccf06998f [PATCH] spi: add ... |
546 547 |
return 0; } |
b36ece832 spi/mpc8xxx: refa... |
548 |
static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) |
ccf06998f [PATCH] spi: add ... |
549 |
{ |
4c1fba442 spi_mpc8xxx: Add ... |
550 |
u16 len; |
b36ece832 spi/mpc8xxx: refa... |
551 |
struct fsl_spi_reg *reg_base = mspi->reg_base; |
ccf06998f [PATCH] spi: add ... |
552 |
|
4c1fba442 spi_mpc8xxx: Add ... |
553 554 555 |
dev_dbg(mspi->dev, "%s: bd datlen %d, count %d ", __func__, in_be16(&mspi->rx_bd->cbd_datlen), mspi->count); |
ccf06998f [PATCH] spi: add ... |
556 |
|
4c1fba442 spi_mpc8xxx: Add ... |
557 558 559 560 561 |
len = in_be16(&mspi->rx_bd->cbd_datlen); if (len > mspi->count) { WARN_ON(1); len = mspi->count; } |
ccf06998f [PATCH] spi: add ... |
562 |
|
4c1fba442 spi_mpc8xxx: Add ... |
563 |
/* Clear the events */ |
b36ece832 spi/mpc8xxx: refa... |
564 |
mpc8xxx_spi_write_reg(®_base->event, events); |
ccf06998f [PATCH] spi: add ... |
565 |
|
4c1fba442 spi_mpc8xxx: Add ... |
566 567 |
mspi->count -= len; if (mspi->count) |
b36ece832 spi/mpc8xxx: refa... |
568 |
fsl_spi_cpm_bufs_start(mspi); |
4c1fba442 spi_mpc8xxx: Add ... |
569 570 571 |
else complete(&mspi->done); } |
b36ece832 spi/mpc8xxx: refa... |
572 |
static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) |
4c1fba442 spi_mpc8xxx: Add ... |
573 |
{ |
b36ece832 spi/mpc8xxx: refa... |
574 |
struct fsl_spi_reg *reg_base = mspi->reg_base; |
4c1fba442 spi_mpc8xxx: Add ... |
575 576 |
/* We need handle RX first */ if (events & SPIE_NE) { |
b36ece832 spi/mpc8xxx: refa... |
577 |
u32 rx_data = mpc8xxx_spi_read_reg(®_base->receive); |
4c1fba442 spi_mpc8xxx: Add ... |
578 579 580 |
if (mspi->rx) mspi->get_rx(rx_data, mspi); |
ccf06998f [PATCH] spi: add ... |
581 |
} |
4c1fba442 spi_mpc8xxx: Add ... |
582 |
if ((events & SPIE_NF) == 0) |
ccf06998f [PATCH] spi: add ... |
583 |
/* spin until TX is done */ |
4c1fba442 spi_mpc8xxx: Add ... |
584 |
while (((events = |
b36ece832 spi/mpc8xxx: refa... |
585 |
mpc8xxx_spi_read_reg(®_base->event)) & |
ccf06998f [PATCH] spi: add ... |
586 |
SPIE_NF) == 0) |
9effb959d spi_mpc83xx: fix ... |
587 |
cpu_relax(); |
ccf06998f [PATCH] spi: add ... |
588 |
|
4c1fba442 spi_mpc8xxx: Add ... |
589 |
/* Clear the events */ |
b36ece832 spi/mpc8xxx: refa... |
590 |
mpc8xxx_spi_write_reg(®_base->event, events); |
4c1fba442 spi_mpc8xxx: Add ... |
591 592 593 594 |
mspi->count -= 1; if (mspi->count) { u32 word = mspi->get_tx(mspi); |
b36ece832 spi/mpc8xxx: refa... |
595 |
mpc8xxx_spi_write_reg(®_base->transmit, word); |
ccf06998f [PATCH] spi: add ... |
596 |
} else { |
4c1fba442 spi_mpc8xxx: Add ... |
597 |
complete(&mspi->done); |
ccf06998f [PATCH] spi: add ... |
598 |
} |
4c1fba442 spi_mpc8xxx: Add ... |
599 |
} |
ccf06998f [PATCH] spi: add ... |
600 |
|
b36ece832 spi/mpc8xxx: refa... |
601 |
static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) |
4c1fba442 spi_mpc8xxx: Add ... |
602 603 604 605 |
{ struct mpc8xxx_spi *mspi = context_data; irqreturn_t ret = IRQ_NONE; u32 events; |
b36ece832 spi/mpc8xxx: refa... |
606 |
struct fsl_spi_reg *reg_base = mspi->reg_base; |
4c1fba442 spi_mpc8xxx: Add ... |
607 608 |
/* Get interrupt events(tx/rx) */ |
b36ece832 spi/mpc8xxx: refa... |
609 |
events = mpc8xxx_spi_read_reg(®_base->event); |
4c1fba442 spi_mpc8xxx: Add ... |
610 611 612 613 614 615 616 |
if (events) ret = IRQ_HANDLED; dev_dbg(mspi->dev, "%s: events %x ", __func__, events); if (mspi->flags & SPI_CPM_MODE) |
b36ece832 spi/mpc8xxx: refa... |
617 |
fsl_spi_cpm_irq(mspi, events); |
4c1fba442 spi_mpc8xxx: Add ... |
618 |
else |
b36ece832 spi/mpc8xxx: refa... |
619 |
fsl_spi_cpu_irq(mspi, events); |
ccf06998f [PATCH] spi: add ... |
620 621 622 |
return ret; } |
4c1fba442 spi_mpc8xxx: Add ... |
623 |
|
b36ece832 spi/mpc8xxx: refa... |
624 |
static void *fsl_spi_alloc_dummy_rx(void) |
c9bfcb315 spi_mpc83xx: much... |
625 |
{ |
b36ece832 spi/mpc8xxx: refa... |
626 |
mutex_lock(&fsl_dummy_rx_lock); |
c9bfcb315 spi_mpc83xx: much... |
627 |
|
b36ece832 spi/mpc8xxx: refa... |
628 629 630 631 |
if (!fsl_dummy_rx) fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL); if (fsl_dummy_rx) fsl_dummy_rx_refcnt++; |
c9bfcb315 spi_mpc83xx: much... |
632 |
|
b36ece832 spi/mpc8xxx: refa... |
633 |
mutex_unlock(&fsl_dummy_rx_lock); |
c9bfcb315 spi_mpc83xx: much... |
634 |
|
b36ece832 spi/mpc8xxx: refa... |
635 |
return fsl_dummy_rx; |
c9bfcb315 spi_mpc83xx: much... |
636 |
} |
b36ece832 spi/mpc8xxx: refa... |
637 |
static void fsl_spi_free_dummy_rx(void) |
c9bfcb315 spi_mpc83xx: much... |
638 |
{ |
b36ece832 spi/mpc8xxx: refa... |
639 |
mutex_lock(&fsl_dummy_rx_lock); |
ccf06998f [PATCH] spi: add ... |
640 |
|
b36ece832 spi/mpc8xxx: refa... |
641 |
switch (fsl_dummy_rx_refcnt) { |
4c1fba442 spi_mpc8xxx: Add ... |
642 643 644 645 |
case 0: WARN_ON(1); break; case 1: |
b36ece832 spi/mpc8xxx: refa... |
646 647 |
kfree(fsl_dummy_rx); fsl_dummy_rx = NULL; |
4c1fba442 spi_mpc8xxx: Add ... |
648 649 |
/* fall through */ default: |
b36ece832 spi/mpc8xxx: refa... |
650 |
fsl_dummy_rx_refcnt--; |
4c1fba442 spi_mpc8xxx: Add ... |
651 652 |
break; } |
b36ece832 spi/mpc8xxx: refa... |
653 |
mutex_unlock(&fsl_dummy_rx_lock); |
4c1fba442 spi_mpc8xxx: Add ... |
654 |
} |
b36ece832 spi/mpc8xxx: refa... |
655 |
static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi) |
4c1fba442 spi_mpc8xxx: Add ... |
656 657 |
{ struct device *dev = mspi->dev; |
61c7a080a of: Always use 's... |
658 |
struct device_node *np = dev->of_node; |
4c1fba442 spi_mpc8xxx: Add ... |
659 660 |
const u32 *iprop; int size; |
fb6440955 spi/fsl_spi: fix ... |
661 |
void __iomem *spi_base; |
4c1fba442 spi_mpc8xxx: Add ... |
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
unsigned long pram_ofs = -ENOMEM; /* Can't use of_address_to_resource(), QE muram isn't at 0. */ iprop = of_get_property(np, "reg", &size); /* QE with a fixed pram location? */ if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4) return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE); /* QE but with a dynamic pram location? */ if (mspi->flags & SPI_QE) { pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock, QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs); return pram_ofs; } |
fb6440955 spi/fsl_spi: fix ... |
678 679 680 |
spi_base = of_iomap(np, 1); if (spi_base == NULL) return -EINVAL; |
4c1fba442 spi_mpc8xxx: Add ... |
681 682 683 |
if (mspi->flags & SPI_CPM2) { pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); |
fb6440955 spi/fsl_spi: fix ... |
684 |
out_be16(spi_base, pram_ofs); |
4c1fba442 spi_mpc8xxx: Add ... |
685 |
} else { |
fb6440955 spi/fsl_spi: fix ... |
686 |
struct spi_pram __iomem *pram = spi_base; |
4c1fba442 spi_mpc8xxx: Add ... |
687 688 689 690 691 |
u16 rpbase = in_be16(&pram->rpbase); /* Microcode relocation patch applied? */ if (rpbase) pram_ofs = rpbase; |
fb6440955 spi/fsl_spi: fix ... |
692 693 694 695 |
else { pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64); out_be16(spi_base, pram_ofs); } |
4c1fba442 spi_mpc8xxx: Add ... |
696 |
} |
fb6440955 spi/fsl_spi: fix ... |
697 |
iounmap(spi_base); |
4c1fba442 spi_mpc8xxx: Add ... |
698 699 |
return pram_ofs; } |
b36ece832 spi/mpc8xxx: refa... |
700 |
static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) |
4c1fba442 spi_mpc8xxx: Add ... |
701 702 |
{ struct device *dev = mspi->dev; |
61c7a080a of: Always use 's... |
703 |
struct device_node *np = dev->of_node; |
4c1fba442 spi_mpc8xxx: Add ... |
704 705 706 707 708 709 710 |
const u32 *iprop; int size; unsigned long pram_ofs; unsigned long bds_ofs; if (!(mspi->flags & SPI_CPM_MODE)) return 0; |
b36ece832 spi/mpc8xxx: refa... |
711 |
if (!fsl_spi_alloc_dummy_rx()) |
4c1fba442 spi_mpc8xxx: Add ... |
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 |
return -ENOMEM; if (mspi->flags & SPI_QE) { iprop = of_get_property(np, "cell-index", &size); if (iprop && size == sizeof(*iprop)) mspi->subblock = *iprop; switch (mspi->subblock) { default: dev_warn(dev, "cell-index unspecified, assuming SPI1"); /* fall through */ case 0: mspi->subblock = QE_CR_SUBBLOCK_SPI1; break; case 1: mspi->subblock = QE_CR_SUBBLOCK_SPI2; break; } } |
b36ece832 spi/mpc8xxx: refa... |
731 |
pram_ofs = fsl_spi_cpm_get_pram(mspi); |
4c1fba442 spi_mpc8xxx: Add ... |
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 |
if (IS_ERR_VALUE(pram_ofs)) { dev_err(dev, "can't allocate spi parameter ram "); goto err_pram; } bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) + sizeof(*mspi->rx_bd), 8); if (IS_ERR_VALUE(bds_ofs)) { dev_err(dev, "can't allocate bds "); goto err_bds; } mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dev, mspi->dma_dummy_tx)) { dev_err(dev, "unable to map dummy tx buffer "); goto err_dummy_tx; } |
b36ece832 spi/mpc8xxx: refa... |
753 |
mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR, |
4c1fba442 spi_mpc8xxx: Add ... |
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 |
DMA_FROM_DEVICE); if (dma_mapping_error(dev, mspi->dma_dummy_rx)) { dev_err(dev, "unable to map dummy rx buffer "); goto err_dummy_rx; } mspi->pram = cpm_muram_addr(pram_ofs); mspi->tx_bd = cpm_muram_addr(bds_ofs); mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd)); /* Initialize parameter ram. */ out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd)); out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd)); out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL); out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL); out_be16(&mspi->pram->mrblr, SPI_MRBLR); out_be32(&mspi->pram->rstate, 0); out_be32(&mspi->pram->rdp, 0); out_be16(&mspi->pram->rbptr, 0); out_be16(&mspi->pram->rbc, 0); out_be32(&mspi->pram->rxtmp, 0); out_be32(&mspi->pram->tstate, 0); out_be32(&mspi->pram->tdp, 0); out_be16(&mspi->pram->tbptr, 0); out_be16(&mspi->pram->tbc, 0); out_be32(&mspi->pram->txtmp, 0); return 0; err_dummy_rx: dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); err_dummy_tx: cpm_muram_free(bds_ofs); err_bds: cpm_muram_free(pram_ofs); err_pram: |
b36ece832 spi/mpc8xxx: refa... |
792 |
fsl_spi_free_dummy_rx(); |
4c1fba442 spi_mpc8xxx: Add ... |
793 794 |
return -ENOMEM; } |
b36ece832 spi/mpc8xxx: refa... |
795 |
static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) |
4c1fba442 spi_mpc8xxx: Add ... |
796 797 |
{ struct device *dev = mspi->dev; |
387719c2e spi: Fix WARN whe... |
798 799 |
if (!(mspi->flags & SPI_CPM_MODE)) return; |
4c1fba442 spi_mpc8xxx: Add ... |
800 801 802 803 |
dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE); dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); cpm_muram_free(cpm_muram_offset(mspi->tx_bd)); cpm_muram_free(cpm_muram_offset(mspi->pram)); |
b36ece832 spi/mpc8xxx: refa... |
804 |
fsl_spi_free_dummy_rx(); |
4c1fba442 spi_mpc8xxx: Add ... |
805 |
} |
b36ece832 spi/mpc8xxx: refa... |
806 |
static void fsl_spi_remove(struct mpc8xxx_spi *mspi) |
87ec0e98c spi_mpc8xxx: Turn... |
807 |
{ |
b36ece832 spi/mpc8xxx: refa... |
808 809 |
iounmap(mspi->reg_base); fsl_spi_cpm_free(mspi); |
87ec0e98c spi_mpc8xxx: Turn... |
810 |
} |
b36ece832 spi/mpc8xxx: refa... |
811 812 |
static struct spi_master * __devinit fsl_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) |
ccf06998f [PATCH] spi: add ... |
813 |
{ |
35b4b3c0c spi_mpc83xx: add ... |
814 |
struct fsl_spi_platform_data *pdata = dev->platform_data; |
ccf06998f [PATCH] spi: add ... |
815 |
struct spi_master *master; |
575c5807f spi_mpc8xxx: s/83... |
816 |
struct mpc8xxx_spi *mpc8xxx_spi; |
b36ece832 spi/mpc8xxx: refa... |
817 |
struct fsl_spi_reg *reg_base; |
ccf06998f [PATCH] spi: add ... |
818 819 |
u32 regval; int ret = 0; |
575c5807f spi_mpc8xxx: s/83... |
820 |
master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); |
ccf06998f [PATCH] spi: add ... |
821 822 823 824 |
if (master == NULL) { ret = -ENOMEM; goto err; } |
35b4b3c0c spi_mpc83xx: add ... |
825 |
dev_set_drvdata(dev, master); |
ccf06998f [PATCH] spi: add ... |
826 |
|
b36ece832 spi/mpc8xxx: refa... |
827 828 829 |
ret = mpc8xxx_spi_probe(dev, mem, irq); if (ret) goto err_probe; |
e7db06b5d spi: move more sp... |
830 |
|
b36ece832 spi/mpc8xxx: refa... |
831 |
master->setup = fsl_spi_setup; |
575c5807f spi_mpc8xxx: s/83... |
832 833 |
mpc8xxx_spi = spi_master_get_devdata(master); |
b36ece832 spi/mpc8xxx: refa... |
834 835 |
mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg; mpc8xxx_spi->spi_remove = fsl_spi_remove; |
575c5807f spi_mpc8xxx: s/83... |
836 |
|
b36ece832 spi/mpc8xxx: refa... |
837 |
ret = fsl_spi_cpm_init(mpc8xxx_spi); |
4c1fba442 spi_mpc8xxx: Add ... |
838 839 |
if (ret) goto err_cpm_init; |
87ec0e98c spi_mpc8xxx: Turn... |
840 |
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { |
575c5807f spi_mpc8xxx: s/83... |
841 842 |
mpc8xxx_spi->rx_shift = 16; mpc8xxx_spi->tx_shift = 24; |
f29ba280e spi_mpc83xx.c: su... |
843 |
} |
b36ece832 spi/mpc8xxx: refa... |
844 845 |
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); if (mpc8xxx_spi->reg_base == NULL) { |
ccf06998f [PATCH] spi: add ... |
846 |
ret = -ENOMEM; |
4c1fba442 spi_mpc8xxx: Add ... |
847 |
goto err_ioremap; |
ccf06998f [PATCH] spi: add ... |
848 |
} |
ccf06998f [PATCH] spi: add ... |
849 |
/* Register for SPI Interrupt */ |
b36ece832 spi/mpc8xxx: refa... |
850 851 |
ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq, 0, "fsl_spi", mpc8xxx_spi); |
ccf06998f [PATCH] spi: add ... |
852 853 |
if (ret != 0) |
b36ece832 spi/mpc8xxx: refa... |
854 |
goto free_irq; |
ccf06998f [PATCH] spi: add ... |
855 |
|
b36ece832 spi/mpc8xxx: refa... |
856 |
reg_base = mpc8xxx_spi->reg_base; |
ccf06998f [PATCH] spi: add ... |
857 858 |
/* SPI controller initializations */ |
b36ece832 spi/mpc8xxx: refa... |
859 860 861 862 |
mpc8xxx_spi_write_reg(®_base->mode, 0); mpc8xxx_spi_write_reg(®_base->mask, 0); mpc8xxx_spi_write_reg(®_base->command, 0); mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); |
ccf06998f [PATCH] spi: add ... |
863 864 865 |
/* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; |
87ec0e98c spi_mpc8xxx: Turn... |
866 |
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) |
f29ba280e spi_mpc83xx.c: su... |
867 |
regval |= SPMODE_OP; |
b36ece832 spi/mpc8xxx: refa... |
868 |
mpc8xxx_spi_write_reg(®_base->mode, regval); |
c9bfcb315 spi_mpc83xx: much... |
869 870 871 872 |
ret = spi_register_master(master); if (ret < 0) goto unreg_master; |
ccf06998f [PATCH] spi: add ... |
873 |
|
b36ece832 spi/mpc8xxx: refa... |
874 875 |
dev_info(dev, "at 0x%p (irq = %d), %s mode ", reg_base, |
87ec0e98c spi_mpc8xxx: Turn... |
876 |
mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags)); |
ccf06998f [PATCH] spi: add ... |
877 |
|
35b4b3c0c spi_mpc83xx: add ... |
878 |
return master; |
ccf06998f [PATCH] spi: add ... |
879 |
|
c9bfcb315 spi_mpc83xx: much... |
880 |
unreg_master: |
575c5807f spi_mpc8xxx: s/83... |
881 |
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); |
b36ece832 spi/mpc8xxx: refa... |
882 883 |
free_irq: iounmap(mpc8xxx_spi->reg_base); |
4c1fba442 spi_mpc8xxx: Add ... |
884 |
err_ioremap: |
b36ece832 spi/mpc8xxx: refa... |
885 |
fsl_spi_cpm_free(mpc8xxx_spi); |
4c1fba442 spi_mpc8xxx: Add ... |
886 |
err_cpm_init: |
b36ece832 spi/mpc8xxx: refa... |
887 |
err_probe: |
ccf06998f [PATCH] spi: add ... |
888 |
spi_master_put(master); |
ccf06998f [PATCH] spi: add ... |
889 |
err: |
35b4b3c0c spi_mpc83xx: add ... |
890 |
return ERR_PTR(ret); |
ccf06998f [PATCH] spi: add ... |
891 |
} |
b36ece832 spi/mpc8xxx: refa... |
892 |
static void fsl_spi_cs_control(struct spi_device *spi, bool on) |
35b4b3c0c spi_mpc83xx: add ... |
893 894 |
{ struct device *dev = spi->dev.parent; |
575c5807f spi_mpc8xxx: s/83... |
895 |
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); |
35b4b3c0c spi_mpc83xx: add ... |
896 897 898 899 900 901 |
u16 cs = spi->chip_select; int gpio = pinfo->gpios[cs]; bool alow = pinfo->alow_flags[cs]; gpio_set_value(gpio, on ^ alow); } |
b36ece832 spi/mpc8xxx: refa... |
902 |
static int of_fsl_spi_get_chipselects(struct device *dev) |
35b4b3c0c spi_mpc83xx: add ... |
903 |
{ |
61c7a080a of: Always use 's... |
904 |
struct device_node *np = dev->of_node; |
35b4b3c0c spi_mpc83xx: add ... |
905 |
struct fsl_spi_platform_data *pdata = dev->platform_data; |
575c5807f spi_mpc8xxx: s/83... |
906 |
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); |
35b4b3c0c spi_mpc83xx: add ... |
907 908 909 910 911 912 913 914 915 916 917 918 919 |
unsigned int ngpios; int i = 0; int ret; ngpios = of_gpio_count(np); if (!ngpios) { /* * SPI w/o chip-select line. One SPI device is still permitted * though. */ pdata->max_chipselect = 1; return 0; } |
021415468 spi: takes size o... |
920 |
pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL); |
35b4b3c0c spi_mpc83xx: add ... |
921 922 |
if (!pinfo->gpios) return -ENOMEM; |
021415468 spi: takes size o... |
923 |
memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); |
35b4b3c0c spi_mpc83xx: add ... |
924 |
|
021415468 spi: takes size o... |
925 |
pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags), |
35b4b3c0c spi_mpc83xx: add ... |
926 927 928 929 930 931 932 933 934 935 936 937 938 939 |
GFP_KERNEL); if (!pinfo->alow_flags) { ret = -ENOMEM; goto err_alloc_flags; } for (; i < ngpios; i++) { int gpio; enum of_gpio_flags flags; gpio = of_get_gpio_flags(np, i, &flags); if (!gpio_is_valid(gpio)) { dev_err(dev, "invalid gpio #%d: %d ", i, gpio); |
783058fd5 spi_mpc8xxx: Fix ... |
940 |
ret = gpio; |
35b4b3c0c spi_mpc83xx: add ... |
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 |
goto err_loop; } ret = gpio_request(gpio, dev_name(dev)); if (ret) { dev_err(dev, "can't request gpio #%d: %d ", i, ret); goto err_loop; } pinfo->gpios[i] = gpio; pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW; ret = gpio_direction_output(pinfo->gpios[i], pinfo->alow_flags[i]); if (ret) { dev_err(dev, "can't set output direction for gpio " "#%d: %d ", i, ret); goto err_loop; } } pdata->max_chipselect = ngpios; |
b36ece832 spi/mpc8xxx: refa... |
965 |
pdata->cs_control = fsl_spi_cs_control; |
35b4b3c0c spi_mpc83xx: add ... |
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
return 0; err_loop: while (i >= 0) { if (gpio_is_valid(pinfo->gpios[i])) gpio_free(pinfo->gpios[i]); i--; } kfree(pinfo->alow_flags); pinfo->alow_flags = NULL; err_alloc_flags: kfree(pinfo->gpios); pinfo->gpios = NULL; return ret; } |
b36ece832 spi/mpc8xxx: refa... |
983 |
static int of_fsl_spi_free_chipselects(struct device *dev) |
35b4b3c0c spi_mpc83xx: add ... |
984 985 |
{ struct fsl_spi_platform_data *pdata = dev->platform_data; |
575c5807f spi_mpc8xxx: s/83... |
986 |
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); |
35b4b3c0c spi_mpc83xx: add ... |
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 |
int i; if (!pinfo->gpios) return 0; for (i = 0; i < pdata->max_chipselect; i++) { if (gpio_is_valid(pinfo->gpios[i])) gpio_free(pinfo->gpios[i]); } kfree(pinfo->gpios); kfree(pinfo->alow_flags); return 0; } |
18d306d13 dt/spi: Eliminate... |
1001 |
static int __devinit of_fsl_spi_probe(struct platform_device *ofdev) |
35b4b3c0c spi_mpc83xx: add ... |
1002 1003 |
{ struct device *dev = &ofdev->dev; |
61c7a080a of: Always use 's... |
1004 |
struct device_node *np = ofdev->dev.of_node; |
35b4b3c0c spi_mpc83xx: add ... |
1005 1006 1007 |
struct spi_master *master; struct resource mem; struct resource irq; |
35b4b3c0c spi_mpc83xx: add ... |
1008 |
int ret = -ENOMEM; |
18d306d13 dt/spi: Eliminate... |
1009 |
ret = of_mpc8xxx_spi_probe(ofdev); |
b36ece832 spi/mpc8xxx: refa... |
1010 1011 |
if (ret) return ret; |
35b4b3c0c spi_mpc83xx: add ... |
1012 |
|
b36ece832 spi/mpc8xxx: refa... |
1013 |
ret = of_fsl_spi_get_chipselects(dev); |
35b4b3c0c spi_mpc83xx: add ... |
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 |
if (ret) goto err; ret = of_address_to_resource(np, 0, &mem); if (ret) goto err; ret = of_irq_to_resource(np, 0, &irq); if (!ret) { ret = -EINVAL; goto err; } |
b36ece832 spi/mpc8xxx: refa... |
1026 |
master = fsl_spi_probe(dev, &mem, irq.start); |
35b4b3c0c spi_mpc83xx: add ... |
1027 1028 1029 1030 |
if (IS_ERR(master)) { ret = PTR_ERR(master); goto err; } |
35b4b3c0c spi_mpc83xx: add ... |
1031 1032 1033 |
return 0; err: |
b36ece832 spi/mpc8xxx: refa... |
1034 |
of_fsl_spi_free_chipselects(dev); |
35b4b3c0c spi_mpc83xx: add ... |
1035 1036 |
return ret; } |
b36ece832 spi/mpc8xxx: refa... |
1037 |
static int __devexit of_fsl_spi_remove(struct platform_device *ofdev) |
35b4b3c0c spi_mpc83xx: add ... |
1038 1039 |
{ int ret; |
575c5807f spi_mpc8xxx: s/83... |
1040 |
ret = mpc8xxx_spi_remove(&ofdev->dev); |
35b4b3c0c spi_mpc83xx: add ... |
1041 1042 |
if (ret) return ret; |
b36ece832 spi/mpc8xxx: refa... |
1043 |
of_fsl_spi_free_chipselects(&ofdev->dev); |
35b4b3c0c spi_mpc83xx: add ... |
1044 1045 |
return 0; } |
b36ece832 spi/mpc8xxx: refa... |
1046 |
static const struct of_device_id of_fsl_spi_match[] = { |
35b4b3c0c spi_mpc83xx: add ... |
1047 |
{ .compatible = "fsl,spi" }, |
b36ece832 spi/mpc8xxx: refa... |
1048 |
{} |
35b4b3c0c spi_mpc83xx: add ... |
1049 |
}; |
b36ece832 spi/mpc8xxx: refa... |
1050 |
MODULE_DEVICE_TABLE(of, of_fsl_spi_match); |
35b4b3c0c spi_mpc83xx: add ... |
1051 |
|
18d306d13 dt/spi: Eliminate... |
1052 |
static struct platform_driver of_fsl_spi_driver = { |
4018294b5 of: Remove duplic... |
1053 |
.driver = { |
b36ece832 spi/mpc8xxx: refa... |
1054 |
.name = "fsl_spi", |
4018294b5 of: Remove duplic... |
1055 |
.owner = THIS_MODULE, |
b36ece832 spi/mpc8xxx: refa... |
1056 |
.of_match_table = of_fsl_spi_match, |
4018294b5 of: Remove duplic... |
1057 |
}, |
b36ece832 spi/mpc8xxx: refa... |
1058 1059 |
.probe = of_fsl_spi_probe, .remove = __devexit_p(of_fsl_spi_remove), |
35b4b3c0c spi_mpc83xx: add ... |
1060 1061 1062 1063 |
}; #ifdef CONFIG_MPC832x_RDB /* |
b36ece832 spi/mpc8xxx: refa... |
1064 |
* XXX XXX XXX |
35b4b3c0c spi_mpc83xx: add ... |
1065 1066 1067 1068 1069 |
* This is "legacy" platform driver, was used by the MPC8323E-RDB boards * only. The driver should go away soon, since newer MPC8323E-RDB's device * tree can work with OpenFirmware driver. But for now we support old trees * as well. */ |
575c5807f spi_mpc8xxx: s/83... |
1070 |
static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev) |
35b4b3c0c spi_mpc83xx: add ... |
1071 1072 |
{ struct resource *mem; |
e9a172f07 spi/mpc8xxx: don'... |
1073 |
int irq; |
35b4b3c0c spi_mpc83xx: add ... |
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 |
struct spi_master *master; if (!pdev->dev.platform_data) return -EINVAL; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -EINVAL; irq = platform_get_irq(pdev, 0); |
e9a172f07 spi/mpc8xxx: don'... |
1084 |
if (irq <= 0) |
35b4b3c0c spi_mpc83xx: add ... |
1085 |
return -EINVAL; |
b36ece832 spi/mpc8xxx: refa... |
1086 |
master = fsl_spi_probe(&pdev->dev, mem, irq); |
35b4b3c0c spi_mpc83xx: add ... |
1087 1088 1089 1090 |
if (IS_ERR(master)) return PTR_ERR(master); return 0; } |
575c5807f spi_mpc8xxx: s/83... |
1091 |
static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev) |
35b4b3c0c spi_mpc83xx: add ... |
1092 |
{ |
575c5807f spi_mpc8xxx: s/83... |
1093 |
return mpc8xxx_spi_remove(&pdev->dev); |
35b4b3c0c spi_mpc83xx: add ... |
1094 |
} |
575c5807f spi_mpc8xxx: s/83... |
1095 1096 1097 |
MODULE_ALIAS("platform:mpc8xxx_spi"); static struct platform_driver mpc8xxx_spi_driver = { .probe = plat_mpc8xxx_spi_probe, |
b3a089451 spi/mpc8xxx: don'... |
1098 |
.remove = __devexit_p(plat_mpc8xxx_spi_remove), |
ccf06998f [PATCH] spi: add ... |
1099 |
.driver = { |
575c5807f spi_mpc8xxx: s/83... |
1100 |
.name = "mpc8xxx_spi", |
7e38c3c44 spi: fix platform... |
1101 |
.owner = THIS_MODULE, |
ccf06998f [PATCH] spi: add ... |
1102 1103 |
}, }; |
35b4b3c0c spi_mpc83xx: add ... |
1104 1105 1106 1107 |
static bool legacy_driver_failed; static void __init legacy_driver_register(void) { |
575c5807f spi_mpc8xxx: s/83... |
1108 |
legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver); |
35b4b3c0c spi_mpc83xx: add ... |
1109 1110 1111 1112 1113 1114 |
} static void __exit legacy_driver_unregister(void) { if (legacy_driver_failed) return; |
575c5807f spi_mpc8xxx: s/83... |
1115 |
platform_driver_unregister(&mpc8xxx_spi_driver); |
35b4b3c0c spi_mpc83xx: add ... |
1116 1117 1118 1119 1120 |
} #else static void __init legacy_driver_register(void) {} static void __exit legacy_driver_unregister(void) {} #endif /* CONFIG_MPC832x_RDB */ |
b36ece832 spi/mpc8xxx: refa... |
1121 |
static int __init fsl_spi_init(void) |
ccf06998f [PATCH] spi: add ... |
1122 |
{ |
35b4b3c0c spi_mpc83xx: add ... |
1123 |
legacy_driver_register(); |
18d306d13 dt/spi: Eliminate... |
1124 |
return platform_driver_register(&of_fsl_spi_driver); |
ccf06998f [PATCH] spi: add ... |
1125 |
} |
b36ece832 spi/mpc8xxx: refa... |
1126 |
module_init(fsl_spi_init); |
ccf06998f [PATCH] spi: add ... |
1127 |
|
b36ece832 spi/mpc8xxx: refa... |
1128 |
static void __exit fsl_spi_exit(void) |
ccf06998f [PATCH] spi: add ... |
1129 |
{ |
18d306d13 dt/spi: Eliminate... |
1130 |
platform_driver_unregister(&of_fsl_spi_driver); |
35b4b3c0c spi_mpc83xx: add ... |
1131 |
legacy_driver_unregister(); |
ccf06998f [PATCH] spi: add ... |
1132 |
} |
b36ece832 spi/mpc8xxx: refa... |
1133 |
module_exit(fsl_spi_exit); |
ccf06998f [PATCH] spi: add ... |
1134 1135 |
MODULE_AUTHOR("Kumar Gala"); |
b36ece832 spi/mpc8xxx: refa... |
1136 |
MODULE_DESCRIPTION("Simple Freescale SPI Driver"); |
ccf06998f [PATCH] spi: add ... |
1137 |
MODULE_LICENSE("GPL"); |