Blame view

drivers/spi/spi-fsl-spi.c 27.8 KB
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1
  /*
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
2
   * Freescale SPI controller driver.
ccf06998f   Kumar Gala   [PATCH] spi: add ...
3
4
5
6
   *
   * Maintainer: Kumar Gala
   *
   * Copyright (C) 2006 Polycom, Inc.
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
7
   * Copyright 2010 Freescale Semiconductor, Inc.
ccf06998f   Kumar Gala   [PATCH] spi: add ...
8
   *
4c1fba442   Anton Vorontsov   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   Kumar Gala   [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   Kumar Gala   [PATCH] spi: add ...
19
20
  #include <linux/types.h>
  #include <linux/kernel.h>
ccf06998f   Kumar Gala   [PATCH] spi: add ...
21
22
23
  #include <linux/interrupt.h>
  #include <linux/delay.h>
  #include <linux/irq.h>
ccf06998f   Kumar Gala   [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   Anton Vorontsov   spi_mpc8xxx: Add ...
28
29
30
  #include <linux/dma-mapping.h>
  #include <linux/mm.h>
  #include <linux/mutex.h>
35b4b3c0c   Anton Vorontsov   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   Kumar Gala   [PATCH] spi: add ...
35

35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
36
  #include <sysdev/fsl_soc.h>
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
37
38
  #include <asm/cpm.h>
  #include <asm/qe.h>
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
39

ca632f556   Grant Likely   spi: reorganize d...
40
  #include "spi-fsl-lib.h"
ccf06998f   Kumar Gala   [PATCH] spi: add ...
41

4c1fba442   Anton Vorontsov   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   Kumar Gala   [PATCH] spi: add ...
50
  /* SPI Controller registers */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
51
  struct fsl_spi_reg {
ccf06998f   Kumar Gala   [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   Anton Vorontsov   spi_mpc83xx: supp...
62
  #define	SPMODE_LOOP		(1 << 30)
ccf06998f   Kumar Gala   [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   Joakim Tjernlund   spi_mpc83xx.c: su...
71
  #define	SPMODE_OP		(1 << 14)
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
72
  #define	SPMODE_CG(x)		((x) << 7)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
73
74
75
  
  /*
   * Default for SPI Mode:
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
76
   *	SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
ccf06998f   Kumar Gala   [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   Anton Vorontsov   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   Mingkai Hu   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   Kumar Gala   [PATCH] spi: add ...
99

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
100
  static void fsl_spi_change_mode(struct spi_device *spi)
a35c17109   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
104
105
  	struct fsl_spi_reg *reg_base = mspi->reg_base;
  	__be32 __iomem *mode = &reg_base->mode;
a35c17109   Anton Vorontsov   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   Anton Vorontsov   spi_mpc8xxx: Fact...
116

4c1fba442   Anton Vorontsov   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   Joakim Tjernlund   spi/spi_mpc8xxx: ...
132
  	mpc8xxx_spi_write_reg(mode, cs->hw_mode);
a35c17109   Anton Vorontsov   spi_mpc8xxx: Fact...
133
134
  	local_irq_restore(flags);
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
135
  static void fsl_spi_chipselect(struct spi_device *spi, int value)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
136
  {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
137
  	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
364fdbc00   Anton Vorontsov   spi_mpc83xx: rewo...
138
139
  	struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
  	bool pol = spi->mode & SPI_CS_HIGH;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
140
  	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
141

ccf06998f   Kumar Gala   [PATCH] spi: add ...
142
  	if (value == BITBANG_CS_INACTIVE) {
364fdbc00   Anton Vorontsov   spi_mpc83xx: rewo...
143
144
  		if (pdata->cs_control)
  			pdata->cs_control(spi, !pol);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
145
146
147
  	}
  
  	if (value == BITBANG_CS_ACTIVE) {
575c5807f   Anton Vorontsov   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   Joakim Tjernlund   spi_mpc83xx: much...
152

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
153
  		fsl_spi_change_mode(spi);
a35c17109   Anton Vorontsov   spi_mpc8xxx: Fact...
154

364fdbc00   Anton Vorontsov   spi_mpc83xx: rewo...
155
156
  		if (pdata->cs_control)
  			pdata->cs_control(spi, pol);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
157
158
  	}
  }
b36ece832   Mingkai Hu   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   Kumar Gala   [PATCH] spi: add ...
163
  {
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
164
165
  	cs->rx_shift = 0;
  	cs->tx_shift = 0;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
166
  	if (bits_per_word <= 8) {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
167
168
  		cs->get_rx = mpc8xxx_spi_rx_buf_u8;
  		cs->get_tx = mpc8xxx_spi_tx_buf_u8;
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
169
  		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
170
171
  			cs->rx_shift = 16;
  			cs->tx_shift = 24;
f29ba280e   Joakim Tjernlund   spi_mpc83xx.c: su...
172
  		}
ccf06998f   Kumar Gala   [PATCH] spi: add ...
173
  	} else if (bits_per_word <= 16) {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
174
175
  		cs->get_rx = mpc8xxx_spi_rx_buf_u16;
  		cs->get_tx = mpc8xxx_spi_tx_buf_u16;
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
176
  		if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
177
178
  			cs->rx_shift = 16;
  			cs->tx_shift = 16;
f29ba280e   Joakim Tjernlund   spi_mpc83xx.c: su...
179
  		}
ccf06998f   Kumar Gala   [PATCH] spi: add ...
180
  	} else if (bits_per_word <= 32) {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
181
182
  		cs->get_rx = mpc8xxx_spi_rx_buf_u32;
  		cs->get_tx = mpc8xxx_spi_tx_buf_u32;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
183
184
  	} else
  		return -EINVAL;
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
185
  	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
0398fb709   Joakim Tjernlund   spi/spi_mpc8xxx: ...
186
  	    spi->mode & SPI_LSB_FIRST) {
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
187
  		cs->tx_shift = 0;
35cc0b975   Anton Vorontsov   spi_mpc83xx: fix ...
188
  		if (bits_per_word <= 8)
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
189
  			cs->rx_shift = 8;
35cc0b975   Anton Vorontsov   spi_mpc83xx: fix ...
190
  		else
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
191
  			cs->rx_shift = 0;
35cc0b975   Anton Vorontsov   spi_mpc83xx: fix ...
192
  	}
575c5807f   Anton Vorontsov   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   Kumar Gala   [PATCH] spi: add ...
197

0398fb709   Joakim Tjernlund   spi/spi_mpc8xxx: ...
198
199
  	return bits_per_word;
  }
b36ece832   Mingkai Hu   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   Joakim Tjernlund   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   Mingkai Hu   spi/mpc8xxx: refa...
217
218
  static int fsl_spi_setup_transfer(struct spi_device *spi,
  					struct spi_transfer *t)
0398fb709   Joakim Tjernlund   spi/spi_mpc8xxx: ...
219
220
  {
  	struct mpc8xxx_spi *mpc8xxx_spi;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
221
  	int bits_per_word = 0;
0398fb709   Joakim Tjernlund   spi/spi_mpc8xxx: ...
222
  	u8 pm;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
223
  	u32 hz = 0;
0398fb709   Joakim Tjernlund   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   Joakim Tjernlund   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   Kumar Gala   [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   Anton Vorontsov   spi_mpc83xx: supp...
259
  	/* mask out bits we are going to set */
c9bfcb315   Joakim Tjernlund   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   Anton Vorontsov   spi_mpc8xxx: s/83...
264
  	if ((mpc8xxx_spi->spibrg / hz) > 64) {
53604dbe1   Peter Korsgaard   spi_mpc83xx: fix ...
265
  		cs->hw_mode |= SPMODE_DIV16;
4f4517c45   Ernst Schwab   spi: Correct SPI ...
266
  		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
fd8a11e10   Anton Vorontsov   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   Anton Vorontsov   spi_mpc8xxx: s/83...
271
  			  hz, mpc8xxx_spi->spibrg / 1024);
fd8a11e10   Anton Vorontsov   spi_mpc83xx: quie...
272
  		if (pm > 16)
53604dbe1   Peter Korsgaard   spi_mpc83xx: fix ...
273
  			pm = 16;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
274
  	} else {
4f4517c45   Ernst Schwab   spi: Correct SPI ...
275
  		pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
276
  	}
a61f5345e   Chen Gong   spi: spi_mpc83xx ...
277
278
279
280
  	if (pm)
  		pm--;
  
  	cs->hw_mode |= SPMODE_PM(pm);
a35c17109   Anton Vorontsov   spi_mpc8xxx: Fact...
281

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
282
  	fsl_spi_change_mode(spi);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
283
284
  	return 0;
  }
ccf06998f   Kumar Gala   [PATCH] spi: add ...
285

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
286
  static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
287
  {
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
292
  	struct fsl_spi_reg *reg_base = mspi->reg_base;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
293

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
294
  	xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
37880c909   christophe leroy   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   Anton Vorontsov   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   christophe leroy   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   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
310
  	mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
311
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
312
  static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
313
314
315
  				struct spi_transfer *t, bool is_dma_mapped)
  {
  	struct device *dev = mspi->dev;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
316
  	struct fsl_spi_reg *reg_base = mspi->reg_base;
4c1fba442   Anton Vorontsov   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   Joakim Tjernlund   spi/spi_mpc8xxx: ...
346
  	} else if (t->tx_buf) {
4c1fba442   Anton Vorontsov   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   Joakim Tjernlund   spi/spi_mpc8xxx: ...
358
  	} else if (t->rx_buf) {
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
359
360
361
362
  		mspi->rx_dma = t->rx_dma;
  	}
  
  	/* enable rx ints */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
363
  	mpc8xxx_spi_write_reg(&reg_base->mask, SPIE_RXB);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
364
365
366
367
368
  
  	mspi->xfer_in_progress = t;
  	mspi->count = t->len;
  
  	/* start CPM transfers */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
369
  	fsl_spi_cpm_bufs_start(mspi);
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
378
  static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
4c1fba442   Anton Vorontsov   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   Joakim Tjernlund   spi/spi_mpc8xxx: ...
385
  	if (mspi->map_rx_dma)
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
386
387
388
  		dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
  	mspi->xfer_in_progress = NULL;
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
389
  static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
390
391
392
  				struct spi_transfer *t, unsigned int len)
  {
  	u32 word;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
393
  	struct fsl_spi_reg *reg_base = mspi->reg_base;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
394
395
396
397
  
  	mspi->count = len;
  
  	/* enable rx ints */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
398
  	mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
399
400
401
  
  	/* transmit word */
  	word = mspi->get_tx(mspi);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
402
  	mpc8xxx_spi_write_reg(&reg_base->transmit, word);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
403
404
405
  
  	return 0;
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
406
  static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
407
408
409
  			    bool is_dma_mapped)
  {
  	struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
410
  	struct fsl_spi_reg *reg_base;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
411
412
413
  	unsigned int len = t->len;
  	u8 bits_per_word;
  	int ret;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
414

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
415
  	reg_base = mpc8xxx_spi->reg_base;
c9bfcb315   Joakim Tjernlund   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   Anton Vorontsov   spi_mpc8xxx: Add ...
419

aa77d96ba   Peter Korsgaard   spi_mpc83xx: reje...
420
421
422
423
  	if (bits_per_word > 8) {
  		/* invalid length? */
  		if (len & 1)
  			return -EINVAL;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
424
  		len /= 2;
aa77d96ba   Peter Korsgaard   spi_mpc83xx: reje...
425
426
427
428
429
  	}
  	if (bits_per_word > 16) {
  		/* invalid length? */
  		if (len & 1)
  			return -EINVAL;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
430
  		len /= 2;
aa77d96ba   Peter Korsgaard   spi_mpc83xx: reje...
431
  	}
aa77d96ba   Peter Korsgaard   spi_mpc83xx: reje...
432

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
433
434
  	mpc8xxx_spi->tx = t->tx_buf;
  	mpc8xxx_spi->rx = t->rx_buf;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
435

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
436
  	INIT_COMPLETION(mpc8xxx_spi->done);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
437

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
438
  	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
439
  		ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
440
  	else
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
441
  		ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
442
443
  	if (ret)
  		return ret;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
444

575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
445
  	wait_for_completion(&mpc8xxx_spi->done);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
446
447
  
  	/* disable rx ints */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
448
  	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
449

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
450
  	if (mpc8xxx_spi->flags & SPI_CPM_MODE)
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
451
  		fsl_spi_cpm_bufs_complete(mpc8xxx_spi);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
452

575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
453
  	return mpc8xxx_spi->count;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
454
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
455
  static void fsl_spi_do_one_msg(struct spi_message *m)
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
456
  {
b9b9af11f   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
471
  				status = fsl_spi_setup_transfer(spi, t);
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
472
  			if (status < 0)
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
473
  				break;
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
474
  		}
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
475

b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
476
  		if (cs_change) {
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
477
  			fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
478
479
480
481
  			ndelay(nsecs);
  		}
  		cs_change = t->cs_change;
  		if (t->len)
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
482
  			status = fsl_spi_bufs(spi, t, m->is_dma_mapped);
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
483
484
485
  		if (status) {
  			status = -EMSGSIZE;
  			break;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
486
  		}
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
487
  		m->actual_length += t->len;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
488

b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
489
490
  		if (t->delay_usecs)
  			udelay(t->delay_usecs);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
491

b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
492
  		if (cs_change) {
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
493
  			ndelay(nsecs);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
494
  			fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
495
  			ndelay(nsecs);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
496
  		}
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
497
498
499
500
501
502
503
  	}
  
  	m->status = status;
  	m->complete(m->context);
  
  	if (status || !cs_change) {
  		ndelay(nsecs);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
504
  		fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
b9b9af11f   Anton Vorontsov   spi_mpc83xx: spli...
505
  	}
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
506
  	fsl_spi_setup_transfer(spi, NULL);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
507
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
508
  static int fsl_spi_setup(struct spi_device *spi)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
509
  {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
510
  	struct mpc8xxx_spi *mpc8xxx_spi;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
511
  	struct fsl_spi_reg *reg_base;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
512
  	int retval;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
513
  	u32 hw_mode;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
514
  	struct spi_mpc8xxx_cs	*cs = spi->controller_state;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
515
516
517
  
  	if (!spi->max_speed_hz)
  		return -EINVAL;
c9bfcb315   Joakim Tjernlund   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   Anton Vorontsov   spi_mpc8xxx: s/83...
524
  	mpc8xxx_spi = spi_master_get_devdata(spi->master);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
525

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
526
  	reg_base = mpc8xxx_spi->reg_base;
883931612   Thomas Weber   Fix typos in comm...
527
  	hw_mode = cs->hw_mode; /* Save original settings */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
528
  	cs->hw_mode = mpc8xxx_spi_read_reg(&reg_base->mode);
c9bfcb315   Joakim Tjernlund   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   Mingkai Hu   spi/mpc8xxx: refa...
541
  	retval = fsl_spi_setup_transfer(spi, NULL);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
542
543
  	if (retval < 0) {
  		cs->hw_mode = hw_mode; /* Restore settings */
ccf06998f   Kumar Gala   [PATCH] spi: add ...
544
  		return retval;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
545
  	}
ccf06998f   Kumar Gala   [PATCH] spi: add ...
546
547
  	return 0;
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
548
  static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
549
  {
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
550
  	u16 len;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
551
  	struct fsl_spi_reg *reg_base = mspi->reg_base;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
552

4c1fba442   Anton Vorontsov   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   Kumar Gala   [PATCH] spi: add ...
556

4c1fba442   Anton Vorontsov   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   Kumar Gala   [PATCH] spi: add ...
562

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
563
  	/* Clear the events */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
564
  	mpc8xxx_spi_write_reg(&reg_base->event, events);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
565

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
566
567
  	mspi->count -= len;
  	if (mspi->count)
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
568
  		fsl_spi_cpm_bufs_start(mspi);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
569
570
571
  	else
  		complete(&mspi->done);
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
572
  static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
573
  {
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
574
  	struct fsl_spi_reg *reg_base = mspi->reg_base;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
575
576
  	/* We need handle RX first */
  	if (events & SPIE_NE) {
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
577
  		u32 rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
578
579
580
  
  		if (mspi->rx)
  			mspi->get_rx(rx_data, mspi);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
581
  	}
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
582
  	if ((events & SPIE_NF) == 0)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
583
  		/* spin until TX is done */
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
584
  		while (((events =
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
585
  			mpc8xxx_spi_read_reg(&reg_base->event)) &
ccf06998f   Kumar Gala   [PATCH] spi: add ...
586
  						SPIE_NF) == 0)
9effb959d   Anton Vorontsov   spi_mpc83xx: fix ...
587
  			cpu_relax();
ccf06998f   Kumar Gala   [PATCH] spi: add ...
588

4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
589
  	/* Clear the events */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
590
  	mpc8xxx_spi_write_reg(&reg_base->event, events);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
591
592
593
594
  
  	mspi->count -= 1;
  	if (mspi->count) {
  		u32 word = mspi->get_tx(mspi);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
595
  		mpc8xxx_spi_write_reg(&reg_base->transmit, word);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
596
  	} else {
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
597
  		complete(&mspi->done);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
598
  	}
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
599
  }
ccf06998f   Kumar Gala   [PATCH] spi: add ...
600

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
601
  static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
602
603
604
605
  {
  	struct mpc8xxx_spi *mspi = context_data;
  	irqreturn_t ret = IRQ_NONE;
  	u32 events;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
606
  	struct fsl_spi_reg *reg_base = mspi->reg_base;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
607
608
  
  	/* Get interrupt events(tx/rx) */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
609
  	events = mpc8xxx_spi_read_reg(&reg_base->event);
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
617
  		fsl_spi_cpm_irq(mspi, events);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
618
  	else
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
619
  		fsl_spi_cpu_irq(mspi, events);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
620
621
622
  
  	return ret;
  }
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
623

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
624
  static void *fsl_spi_alloc_dummy_rx(void)
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
625
  {
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
626
  	mutex_lock(&fsl_dummy_rx_lock);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
627

b36ece832   Mingkai Hu   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   Joakim Tjernlund   spi_mpc83xx: much...
632

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
633
  	mutex_unlock(&fsl_dummy_rx_lock);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
634

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
635
  	return fsl_dummy_rx;
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
636
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
637
  static void fsl_spi_free_dummy_rx(void)
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
638
  {
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
639
  	mutex_lock(&fsl_dummy_rx_lock);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
640

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
641
  	switch (fsl_dummy_rx_refcnt) {
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
642
643
644
645
  	case 0:
  		WARN_ON(1);
  		break;
  	case 1:
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
646
647
  		kfree(fsl_dummy_rx);
  		fsl_dummy_rx = NULL;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
648
649
  		/* fall through */
  	default:
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
650
  		fsl_dummy_rx_refcnt--;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
651
652
  		break;
  	}
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
653
  	mutex_unlock(&fsl_dummy_rx_lock);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
654
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
655
  static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
656
657
  {
  	struct device *dev = mspi->dev;
61c7a080a   Grant Likely   of: Always use 's...
658
  	struct device_node *np = dev->of_node;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
659
660
  	const u32 *iprop;
  	int size;
fb6440955   Holger Brunck   spi/fsl_spi: fix ...
661
  	void __iomem *spi_base;
4c1fba442   Anton Vorontsov   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   Holger Brunck   spi/fsl_spi: fix ...
678
679
680
  	spi_base = of_iomap(np, 1);
  	if (spi_base == NULL)
  		return -EINVAL;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
681
682
683
  
  	if (mspi->flags & SPI_CPM2) {
  		pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
fb6440955   Holger Brunck   spi/fsl_spi: fix ...
684
  		out_be16(spi_base, pram_ofs);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
685
  	} else {
fb6440955   Holger Brunck   spi/fsl_spi: fix ...
686
  		struct spi_pram __iomem *pram = spi_base;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
687
688
689
690
691
  		u16 rpbase = in_be16(&pram->rpbase);
  
  		/* Microcode relocation patch applied? */
  		if (rpbase)
  			pram_ofs = rpbase;
fb6440955   Holger Brunck   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   Anton Vorontsov   spi_mpc8xxx: Add ...
696
  	}
fb6440955   Holger Brunck   spi/fsl_spi: fix ...
697
  	iounmap(spi_base);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
698
699
  	return pram_ofs;
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
700
  static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
701
702
  {
  	struct device *dev = mspi->dev;
61c7a080a   Grant Likely   of: Always use 's...
703
  	struct device_node *np = dev->of_node;
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
711
  	if (!fsl_spi_alloc_dummy_rx())
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
731
  	pram_ofs = fsl_spi_cpm_get_pram(mspi);
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
753
  	mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR,
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
792
  	fsl_spi_free_dummy_rx();
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
793
794
  	return -ENOMEM;
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
795
  static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
796
797
  {
  	struct device *dev = mspi->dev;
387719c2e   Jeff Harris   spi: Fix WARN whe...
798
799
  	if (!(mspi->flags & SPI_CPM_MODE))
  		return;
4c1fba442   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
804
  	fsl_spi_free_dummy_rx();
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
805
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
806
  static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
807
  {
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
808
809
  	iounmap(mspi->reg_base);
  	fsl_spi_cpm_free(mspi);
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
810
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
811
812
  static struct spi_master * __devinit fsl_spi_probe(struct device *dev,
  		struct resource *mem, unsigned int irq)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
813
  {
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
814
  	struct fsl_spi_platform_data *pdata = dev->platform_data;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
815
  	struct spi_master *master;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
816
  	struct mpc8xxx_spi *mpc8xxx_spi;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
817
  	struct fsl_spi_reg *reg_base;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
818
819
  	u32 regval;
  	int ret = 0;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
820
  	master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
ccf06998f   Kumar Gala   [PATCH] spi: add ...
821
822
823
824
  	if (master == NULL) {
  		ret = -ENOMEM;
  		goto err;
  	}
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
825
  	dev_set_drvdata(dev, master);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
826

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
827
828
829
  	ret = mpc8xxx_spi_probe(dev, mem, irq);
  	if (ret)
  		goto err_probe;
e7db06b5d   David Brownell   spi: move more sp...
830

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
831
  	master->setup = fsl_spi_setup;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
832
833
  
  	mpc8xxx_spi = spi_master_get_devdata(master);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
834
835
  	mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
  	mpc8xxx_spi->spi_remove = fsl_spi_remove;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
836

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
837
  	ret = fsl_spi_cpm_init(mpc8xxx_spi);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
838
839
  	if (ret)
  		goto err_cpm_init;
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
840
  	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
841
842
  		mpc8xxx_spi->rx_shift = 16;
  		mpc8xxx_spi->tx_shift = 24;
f29ba280e   Joakim Tjernlund   spi_mpc83xx.c: su...
843
  	}
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
844
845
  	mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
  	if (mpc8xxx_spi->reg_base == NULL) {
ccf06998f   Kumar Gala   [PATCH] spi: add ...
846
  		ret = -ENOMEM;
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
847
  		goto err_ioremap;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
848
  	}
ccf06998f   Kumar Gala   [PATCH] spi: add ...
849
  	/* Register for SPI Interrupt */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
850
851
  	ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
  			  0, "fsl_spi", mpc8xxx_spi);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
852
853
  
  	if (ret != 0)
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
854
  		goto free_irq;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
855

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
856
  	reg_base = mpc8xxx_spi->reg_base;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
857
858
  
  	/* SPI controller initializations */
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
859
860
861
862
  	mpc8xxx_spi_write_reg(&reg_base->mode, 0);
  	mpc8xxx_spi_write_reg(&reg_base->mask, 0);
  	mpc8xxx_spi_write_reg(&reg_base->command, 0);
  	mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
863
864
865
  
  	/* Enable SPI interface */
  	regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
866
  	if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
f29ba280e   Joakim Tjernlund   spi_mpc83xx.c: su...
867
  		regval |= SPMODE_OP;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
868
  	mpc8xxx_spi_write_reg(&reg_base->mode, regval);
c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
869
870
871
872
  
  	ret = spi_register_master(master);
  	if (ret < 0)
  		goto unreg_master;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
873

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
874
875
  	dev_info(dev, "at 0x%p (irq = %d), %s mode
  ", reg_base,
87ec0e98c   Anton Vorontsov   spi_mpc8xxx: Turn...
876
  		 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
ccf06998f   Kumar Gala   [PATCH] spi: add ...
877

35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
878
  	return master;
ccf06998f   Kumar Gala   [PATCH] spi: add ...
879

c9bfcb315   Joakim Tjernlund   spi_mpc83xx: much...
880
  unreg_master:
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
881
  	free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
882
883
  free_irq:
  	iounmap(mpc8xxx_spi->reg_base);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
884
  err_ioremap:
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
885
  	fsl_spi_cpm_free(mpc8xxx_spi);
4c1fba442   Anton Vorontsov   spi_mpc8xxx: Add ...
886
  err_cpm_init:
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
887
  err_probe:
ccf06998f   Kumar Gala   [PATCH] spi: add ...
888
  	spi_master_put(master);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
889
  err:
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
890
  	return ERR_PTR(ret);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
891
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
892
  static void fsl_spi_cs_control(struct spi_device *spi, bool on)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
893
894
  {
  	struct device *dev = spi->dev.parent;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
895
  	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
35b4b3c0c   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
902
  static int of_fsl_spi_get_chipselects(struct device *dev)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
903
  {
61c7a080a   Grant Likely   of: Always use 's...
904
  	struct device_node *np = dev->of_node;
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
905
  	struct fsl_spi_platform_data *pdata = dev->platform_data;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
906
  	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
35b4b3c0c   Anton Vorontsov   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   Roel Kluin   spi: takes size o...
920
  	pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
921
922
  	if (!pinfo->gpios)
  		return -ENOMEM;
021415468   Roel Kluin   spi: takes size o...
923
  	memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
924

021415468   Roel Kluin   spi: takes size o...
925
  	pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
35b4b3c0c   Anton Vorontsov   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   Anton Vorontsov   spi_mpc8xxx: Fix ...
940
  			ret = gpio;
35b4b3c0c   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
965
  	pdata->cs_control = fsl_spi_cs_control;
35b4b3c0c   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
983
  static int of_fsl_spi_free_chipselects(struct device *dev)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
984
985
  {
  	struct fsl_spi_platform_data *pdata = dev->platform_data;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
986
  	struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
35b4b3c0c   Anton Vorontsov   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   Grant Likely   dt/spi: Eliminate...
1001
  static int __devinit of_fsl_spi_probe(struct platform_device *ofdev)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1002
1003
  {
  	struct device *dev = &ofdev->dev;
61c7a080a   Grant Likely   of: Always use 's...
1004
  	struct device_node *np = ofdev->dev.of_node;
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1005
1006
1007
  	struct spi_master *master;
  	struct resource mem;
  	struct resource irq;
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1008
  	int ret = -ENOMEM;
18d306d13   Grant Likely   dt/spi: Eliminate...
1009
  	ret = of_mpc8xxx_spi_probe(ofdev);
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1010
1011
  	if (ret)
  		return ret;
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1012

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1013
  	ret = of_fsl_spi_get_chipselects(dev);
35b4b3c0c   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
1026
  	master = fsl_spi_probe(dev, &mem, irq.start);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1027
1028
1029
1030
  	if (IS_ERR(master)) {
  		ret = PTR_ERR(master);
  		goto err;
  	}
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1031
1032
1033
  	return 0;
  
  err:
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1034
  	of_fsl_spi_free_chipselects(dev);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1035
1036
  	return ret;
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1037
  static int __devexit of_fsl_spi_remove(struct platform_device *ofdev)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1038
1039
  {
  	int ret;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
1040
  	ret = mpc8xxx_spi_remove(&ofdev->dev);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1041
1042
  	if (ret)
  		return ret;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1043
  	of_fsl_spi_free_chipselects(&ofdev->dev);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1044
1045
  	return 0;
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1046
  static const struct of_device_id of_fsl_spi_match[] = {
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1047
  	{ .compatible = "fsl,spi" },
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1048
  	{}
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1049
  };
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1050
  MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1051

18d306d13   Grant Likely   dt/spi: Eliminate...
1052
  static struct platform_driver of_fsl_spi_driver = {
4018294b5   Grant Likely   of: Remove duplic...
1053
  	.driver = {
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1054
  		.name = "fsl_spi",
4018294b5   Grant Likely   of: Remove duplic...
1055
  		.owner = THIS_MODULE,
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1056
  		.of_match_table = of_fsl_spi_match,
4018294b5   Grant Likely   of: Remove duplic...
1057
  	},
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1058
1059
  	.probe		= of_fsl_spi_probe,
  	.remove		= __devexit_p(of_fsl_spi_remove),
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1060
1061
1062
1063
  };
  
  #ifdef CONFIG_MPC832x_RDB
  /*
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1064
   * XXX XXX XXX
35b4b3c0c   Anton Vorontsov   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   Anton Vorontsov   spi_mpc8xxx: s/83...
1070
  static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1071
1072
  {
  	struct resource *mem;
e9a172f07   Uwe Kleine-König   spi/mpc8xxx: don'...
1073
  	int irq;
35b4b3c0c   Anton Vorontsov   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   Uwe Kleine-König   spi/mpc8xxx: don'...
1084
  	if (irq <= 0)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1085
  		return -EINVAL;
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1086
  	master = fsl_spi_probe(&pdev->dev, mem, irq);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1087
1088
1089
1090
  	if (IS_ERR(master))
  		return PTR_ERR(master);
  	return 0;
  }
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
1091
  static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1092
  {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
1093
  	return mpc8xxx_spi_remove(&pdev->dev);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1094
  }
575c5807f   Anton Vorontsov   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   Uwe Kleine-König   spi/mpc8xxx: don'...
1098
  	.remove = __devexit_p(plat_mpc8xxx_spi_remove),
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1099
  	.driver = {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
1100
  		.name = "mpc8xxx_spi",
7e38c3c44   Kay Sievers   spi: fix platform...
1101
  		.owner = THIS_MODULE,
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1102
1103
  	},
  };
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1104
1105
1106
1107
  static bool legacy_driver_failed;
  
  static void __init legacy_driver_register(void)
  {
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
1108
  	legacy_driver_failed = platform_driver_register(&mpc8xxx_spi_driver);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1109
1110
1111
1112
1113
1114
  }
  
  static void __exit legacy_driver_unregister(void)
  {
  	if (legacy_driver_failed)
  		return;
575c5807f   Anton Vorontsov   spi_mpc8xxx: s/83...
1115
  	platform_driver_unregister(&mpc8xxx_spi_driver);
35b4b3c0c   Anton Vorontsov   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   Mingkai Hu   spi/mpc8xxx: refa...
1121
  static int __init fsl_spi_init(void)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1122
  {
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1123
  	legacy_driver_register();
18d306d13   Grant Likely   dt/spi: Eliminate...
1124
  	return platform_driver_register(&of_fsl_spi_driver);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1125
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1126
  module_init(fsl_spi_init);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1127

b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1128
  static void __exit fsl_spi_exit(void)
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1129
  {
18d306d13   Grant Likely   dt/spi: Eliminate...
1130
  	platform_driver_unregister(&of_fsl_spi_driver);
35b4b3c0c   Anton Vorontsov   spi_mpc83xx: add ...
1131
  	legacy_driver_unregister();
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1132
  }
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1133
  module_exit(fsl_spi_exit);
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1134
1135
  
  MODULE_AUTHOR("Kumar Gala");
b36ece832   Mingkai Hu   spi/mpc8xxx: refa...
1136
  MODULE_DESCRIPTION("Simple Freescale SPI Driver");
ccf06998f   Kumar Gala   [PATCH] spi: add ...
1137
  MODULE_LICENSE("GPL");