Blame view

drivers/spi/spi-imx.c 23.8 KB
b5f3294f0   Sascha Hauer   spi: add SPI driv...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  /*
   * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
   * Copyright (C) 2008 Juergen Beisert
   *
   * 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.
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the
   * Free Software Foundation
   * 51 Franklin Street, Fifth Floor
   * Boston, MA  02110-1301, USA.
   */
  
  #include <linux/clk.h>
  #include <linux/completion.h>
  #include <linux/delay.h>
  #include <linux/err.h>
  #include <linux/gpio.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/irq.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
33
  #include <linux/slab.h>
b5f3294f0   Sascha Hauer   spi: add SPI driv...
34
35
36
  #include <linux/spi/spi.h>
  #include <linux/spi/spi_bitbang.h>
  #include <linux/types.h>
22a85e4cd   Shawn Guo   spi/imx: add devi...
37
38
39
  #include <linux/of.h>
  #include <linux/of_device.h>
  #include <linux/of_gpio.h>
b5f3294f0   Sascha Hauer   spi: add SPI driv...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  
  #include <mach/spi.h>
  
  #define DRIVER_NAME "spi_imx"
  
  #define MXC_CSPIRXDATA		0x00
  #define MXC_CSPITXDATA		0x04
  #define MXC_CSPICTRL		0x08
  #define MXC_CSPIINT		0x0c
  #define MXC_RESET		0x1c
  
  /* generic defines to abstract from the different register layouts */
  #define MXC_INT_RR	(1 << 0) /* Receive data ready interrupt */
  #define MXC_INT_TE	(1 << 1) /* Transmit FIFO empty interrupt */
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
54
  struct spi_imx_config {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
55
56
57
  	unsigned int speed_hz;
  	unsigned int bpw;
  	unsigned int mode;
3b2aa89eb   Uwe Kleine-König   spi/imx: save the...
58
  	u8 cs;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
59
  };
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
60
  enum spi_imx_devtype {
04ee58549   Shawn Guo   spi/imx: use soc ...
61
62
63
64
65
66
  	IMX1_CSPI,
  	IMX21_CSPI,
  	IMX27_CSPI,
  	IMX31_CSPI,
  	IMX35_CSPI,	/* CSPI on all i.mx except above */
  	IMX51_ECSPI,	/* ECSPI on i.mx51 and later */
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
67
68
69
70
71
72
73
74
75
  };
  
  struct spi_imx_data;
  
  struct spi_imx_devtype_data {
  	void (*intctrl)(struct spi_imx_data *, int);
  	int (*config)(struct spi_imx_data *, struct spi_imx_config *);
  	void (*trigger)(struct spi_imx_data *);
  	int (*rx_available)(struct spi_imx_data *);
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
76
  	void (*reset)(struct spi_imx_data *);
04ee58549   Shawn Guo   spi/imx: use soc ...
77
  	enum spi_imx_devtype devtype;
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
78
  };
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
79
  struct spi_imx_data {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
80
81
82
83
84
85
86
  	struct spi_bitbang bitbang;
  
  	struct completion xfer_done;
  	void *base;
  	int irq;
  	struct clk *clk;
  	unsigned long spi_clk;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
87
88
  
  	unsigned int count;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
89
90
  	void (*tx)(struct spi_imx_data *);
  	void (*rx)(struct spi_imx_data *);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
91
92
93
  	void *rx_buf;
  	const void *tx_buf;
  	unsigned int txfifo; /* number of words pushed in tx FIFO */
edd501bbf   Shawn Guo   spi/imx: do not m...
94
  	struct spi_imx_devtype_data *devtype_data;
c2387cb9e   Shawn Guo   spi/imx: copy gpi...
95
  	int chipselect[0];
b5f3294f0   Sascha Hauer   spi: add SPI driv...
96
  };
04ee58549   Shawn Guo   spi/imx: use soc ...
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  static inline int is_imx27_cspi(struct spi_imx_data *d)
  {
  	return d->devtype_data->devtype == IMX27_CSPI;
  }
  
  static inline int is_imx35_cspi(struct spi_imx_data *d)
  {
  	return d->devtype_data->devtype == IMX35_CSPI;
  }
  
  static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d)
  {
  	return (d->devtype_data->devtype == IMX51_ECSPI) ? 64 : 8;
  }
b5f3294f0   Sascha Hauer   spi: add SPI driv...
111
  #define MXC_SPI_BUF_RX(type)						\
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
112
  static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx)		\
b5f3294f0   Sascha Hauer   spi: add SPI driv...
113
  {									\
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
114
  	unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);	\
b5f3294f0   Sascha Hauer   spi: add SPI driv...
115
  									\
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
116
117
118
  	if (spi_imx->rx_buf) {						\
  		*(type *)spi_imx->rx_buf = val;				\
  		spi_imx->rx_buf += sizeof(type);			\
b5f3294f0   Sascha Hauer   spi: add SPI driv...
119
120
121
122
  	}								\
  }
  
  #define MXC_SPI_BUF_TX(type)						\
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
123
  static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx)		\
b5f3294f0   Sascha Hauer   spi: add SPI driv...
124
125
126
  {									\
  	type val = 0;							\
  									\
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
127
128
129
  	if (spi_imx->tx_buf) {						\
  		val = *(type *)spi_imx->tx_buf;				\
  		spi_imx->tx_buf += sizeof(type);			\
b5f3294f0   Sascha Hauer   spi: add SPI driv...
130
131
  	}								\
  									\
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
132
  	spi_imx->count -= sizeof(type);					\
b5f3294f0   Sascha Hauer   spi: add SPI driv...
133
  									\
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
134
  	writel(val, spi_imx->base + MXC_CSPITXDATA);			\
b5f3294f0   Sascha Hauer   spi: add SPI driv...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  }
  
  MXC_SPI_BUF_RX(u8)
  MXC_SPI_BUF_TX(u8)
  MXC_SPI_BUF_RX(u16)
  MXC_SPI_BUF_TX(u16)
  MXC_SPI_BUF_RX(u32)
  MXC_SPI_BUF_TX(u32)
  
  /* First entry is reserved, second entry is valid only if SDHC_SPIEN is set
   * (which is currently not the case in this driver)
   */
  static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
  	256, 384, 512, 768, 1024};
  
  /* MX21, MX27 */
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
151
  static unsigned int spi_imx_clkdiv_1(unsigned int fin,
04ee58549   Shawn Guo   spi/imx: use soc ...
152
  		unsigned int fspi, unsigned int max)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
153
  {
04ee58549   Shawn Guo   spi/imx: use soc ...
154
  	int i;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
155
156
157
158
159
160
161
  
  	for (i = 2; i < max; i++)
  		if (fspi * mxc_clkdivs[i] >= fin)
  			return i;
  
  	return max;
  }
0b599603d   Uwe Kleine-König   spi/imx: add supp...
162
  /* MX1, MX31, MX35, MX51 CSPI */
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
163
  static unsigned int spi_imx_clkdiv_2(unsigned int fin,
b5f3294f0   Sascha Hauer   spi: add SPI driv...
164
165
166
167
168
169
170
171
172
173
174
175
  		unsigned int fspi)
  {
  	int i, div = 4;
  
  	for (i = 0; i < 7; i++) {
  		if (fspi * div >= fin)
  			return i;
  		div <<= 1;
  	}
  
  	return 7;
  }
66de757c5   Shawn Guo   spi/imx: do not u...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  #define MX51_ECSPI_CTRL		0x08
  #define MX51_ECSPI_CTRL_ENABLE		(1 <<  0)
  #define MX51_ECSPI_CTRL_XCH		(1 <<  2)
  #define MX51_ECSPI_CTRL_MODE_MASK	(0xf << 4)
  #define MX51_ECSPI_CTRL_POSTDIV_OFFSET	8
  #define MX51_ECSPI_CTRL_PREDIV_OFFSET	12
  #define MX51_ECSPI_CTRL_CS(cs)		((cs) << 18)
  #define MX51_ECSPI_CTRL_BL_OFFSET	20
  
  #define MX51_ECSPI_CONFIG	0x0c
  #define MX51_ECSPI_CONFIG_SCLKPHA(cs)	(1 << ((cs) +  0))
  #define MX51_ECSPI_CONFIG_SCLKPOL(cs)	(1 << ((cs) +  4))
  #define MX51_ECSPI_CONFIG_SBBCTRL(cs)	(1 << ((cs) +  8))
  #define MX51_ECSPI_CONFIG_SSBPOL(cs)	(1 << ((cs) + 12))
  
  #define MX51_ECSPI_INT		0x10
  #define MX51_ECSPI_INT_TEEN		(1 <<  0)
  #define MX51_ECSPI_INT_RREN		(1 <<  3)
  
  #define MX51_ECSPI_STAT		0x18
  #define MX51_ECSPI_STAT_RR		(1 <<  3)
0b599603d   Uwe Kleine-König   spi/imx: add supp...
197
198
  
  /* MX51 eCSPI */
66de757c5   Shawn Guo   spi/imx: do not u...
199
  static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi)
0b599603d   Uwe Kleine-König   spi/imx: add supp...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  {
  	/*
  	 * there are two 4-bit dividers, the pre-divider divides by
  	 * $pre, the post-divider by 2^$post
  	 */
  	unsigned int pre, post;
  
  	if (unlikely(fspi > fin))
  		return 0;
  
  	post = fls(fin) - fls(fspi);
  	if (fin > fspi << post)
  		post++;
  
  	/* now we have: (fin <= fspi << post) with post being minimal */
  
  	post = max(4U, post) - 4;
  	if (unlikely(post > 0xf)) {
  		pr_err("%s: cannot set clock freq: %u (base freq: %u)
  ",
  				__func__, fspi, fin);
  		return 0xff;
  	}
  
  	pre = DIV_ROUND_UP(fin, fspi << post) - 1;
  
  	pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u
  ",
  			__func__, fin, fspi, post, pre);
66de757c5   Shawn Guo   spi/imx: do not u...
229
230
  	return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) |
  		(post << MX51_ECSPI_CTRL_POSTDIV_OFFSET);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
231
  }
66de757c5   Shawn Guo   spi/imx: do not u...
232
  static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
0b599603d   Uwe Kleine-König   spi/imx: add supp...
233
234
235
236
  {
  	unsigned val = 0;
  
  	if (enable & MXC_INT_TE)
66de757c5   Shawn Guo   spi/imx: do not u...
237
  		val |= MX51_ECSPI_INT_TEEN;
0b599603d   Uwe Kleine-König   spi/imx: add supp...
238
239
  
  	if (enable & MXC_INT_RR)
66de757c5   Shawn Guo   spi/imx: do not u...
240
  		val |= MX51_ECSPI_INT_RREN;
0b599603d   Uwe Kleine-König   spi/imx: add supp...
241

66de757c5   Shawn Guo   spi/imx: do not u...
242
  	writel(val, spi_imx->base + MX51_ECSPI_INT);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
243
  }
66de757c5   Shawn Guo   spi/imx: do not u...
244
  static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
0b599603d   Uwe Kleine-König   spi/imx: add supp...
245
246
  {
  	u32 reg;
66de757c5   Shawn Guo   spi/imx: do not u...
247
248
249
  	reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
  	reg |= MX51_ECSPI_CTRL_XCH;
  	writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
250
  }
66de757c5   Shawn Guo   spi/imx: do not u...
251
  static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
0b599603d   Uwe Kleine-König   spi/imx: add supp...
252
253
  		struct spi_imx_config *config)
  {
66de757c5   Shawn Guo   spi/imx: do not u...
254
  	u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
0b599603d   Uwe Kleine-König   spi/imx: add supp...
255

f020c39e5   Sascha Hauer   spi/imx: select m...
256
257
258
259
260
261
262
  	/*
  	 * The hardware seems to have a race condition when changing modes. The
  	 * current assumption is that the selection of the channel arrives
  	 * earlier in the hardware than the mode bits when they are written at
  	 * the same time.
  	 * So set master mode for all channels as we do not support slave mode.
  	 */
66de757c5   Shawn Guo   spi/imx: do not u...
263
  	ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
0b599603d   Uwe Kleine-König   spi/imx: add supp...
264
265
  
  	/* set clock speed */
66de757c5   Shawn Guo   spi/imx: do not u...
266
  	ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
267
268
  
  	/* set chip select to use */
66de757c5   Shawn Guo   spi/imx: do not u...
269
  	ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
270

66de757c5   Shawn Guo   spi/imx: do not u...
271
  	ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
0b599603d   Uwe Kleine-König   spi/imx: add supp...
272

66de757c5   Shawn Guo   spi/imx: do not u...
273
  	cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
274
275
  
  	if (config->mode & SPI_CPHA)
66de757c5   Shawn Guo   spi/imx: do not u...
276
  		cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
277
278
  
  	if (config->mode & SPI_CPOL)
66de757c5   Shawn Guo   spi/imx: do not u...
279
  		cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
280
281
  
  	if (config->mode & SPI_CS_HIGH)
66de757c5   Shawn Guo   spi/imx: do not u...
282
  		cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
283

66de757c5   Shawn Guo   spi/imx: do not u...
284
285
  	writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
  	writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
0b599603d   Uwe Kleine-König   spi/imx: add supp...
286
287
288
  
  	return 0;
  }
66de757c5   Shawn Guo   spi/imx: do not u...
289
  static int __maybe_unused mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
0b599603d   Uwe Kleine-König   spi/imx: add supp...
290
  {
66de757c5   Shawn Guo   spi/imx: do not u...
291
  	return readl(spi_imx->base + MX51_ECSPI_STAT) & MX51_ECSPI_STAT_RR;
0b599603d   Uwe Kleine-König   spi/imx: add supp...
292
  }
66de757c5   Shawn Guo   spi/imx: do not u...
293
  static void __maybe_unused mx51_ecspi_reset(struct spi_imx_data *spi_imx)
0b599603d   Uwe Kleine-König   spi/imx: add supp...
294
295
  {
  	/* drain receive buffer */
66de757c5   Shawn Guo   spi/imx: do not u...
296
  	while (mx51_ecspi_rx_available(spi_imx))
0b599603d   Uwe Kleine-König   spi/imx: add supp...
297
298
  		readl(spi_imx->base + MXC_CSPIRXDATA);
  }
b5f3294f0   Sascha Hauer   spi: add SPI driv...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  #define MX31_INTREG_TEEN	(1 << 0)
  #define MX31_INTREG_RREN	(1 << 3)
  
  #define MX31_CSPICTRL_ENABLE	(1 << 0)
  #define MX31_CSPICTRL_MASTER	(1 << 1)
  #define MX31_CSPICTRL_XCH	(1 << 2)
  #define MX31_CSPICTRL_POL	(1 << 4)
  #define MX31_CSPICTRL_PHA	(1 << 5)
  #define MX31_CSPICTRL_SSCTL	(1 << 6)
  #define MX31_CSPICTRL_SSPOL	(1 << 7)
  #define MX31_CSPICTRL_BC_SHIFT	8
  #define MX35_CSPICTRL_BL_SHIFT	20
  #define MX31_CSPICTRL_CS_SHIFT	24
  #define MX35_CSPICTRL_CS_SHIFT	12
  #define MX31_CSPICTRL_DR_SHIFT	16
  
  #define MX31_CSPISTATUS		0x14
  #define MX31_STATUS_RR		(1 << 3)
  
  /* These functions also work for the i.MX35, but be aware that
   * the i.MX35 has a slightly different register layout for bits
   * we do not use here.
   */
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
322
  static void __maybe_unused mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
323
324
325
326
327
328
329
  {
  	unsigned int val = 0;
  
  	if (enable & MXC_INT_TE)
  		val |= MX31_INTREG_TEEN;
  	if (enable & MXC_INT_RR)
  		val |= MX31_INTREG_RREN;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
330
  	writel(val, spi_imx->base + MXC_CSPIINT);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
331
  }
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
332
  static void __maybe_unused mx31_trigger(struct spi_imx_data *spi_imx)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
333
334
  {
  	unsigned int reg;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
335
  	reg = readl(spi_imx->base + MXC_CSPICTRL);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
336
  	reg |= MX31_CSPICTRL_XCH;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
337
  	writel(reg, spi_imx->base + MXC_CSPICTRL);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
338
  }
2a64a90a2   Shawn Guo   spi/imx: merge ty...
339
  static int __maybe_unused mx31_config(struct spi_imx_data *spi_imx,
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
340
341
342
  		struct spi_imx_config *config)
  {
  	unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
3b2aa89eb   Uwe Kleine-König   spi/imx: save the...
343
  	int cs = spi_imx->chipselect[config->cs];
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
344
345
346
  
  	reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
  		MX31_CSPICTRL_DR_SHIFT;
04ee58549   Shawn Guo   spi/imx: use soc ...
347
  	if (is_imx35_cspi(spi_imx)) {
2a64a90a2   Shawn Guo   spi/imx: merge ty...
348
349
350
351
352
  		reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
  		reg |= MX31_CSPICTRL_SSCTL;
  	} else {
  		reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
  	}
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
353
354
355
356
357
358
359
  
  	if (config->mode & SPI_CPHA)
  		reg |= MX31_CSPICTRL_PHA;
  	if (config->mode & SPI_CPOL)
  		reg |= MX31_CSPICTRL_POL;
  	if (config->mode & SPI_CS_HIGH)
  		reg |= MX31_CSPICTRL_SSPOL;
3b2aa89eb   Uwe Kleine-König   spi/imx: save the...
360
  	if (cs < 0)
2a64a90a2   Shawn Guo   spi/imx: merge ty...
361
  		reg |= (cs + 32) <<
04ee58549   Shawn Guo   spi/imx: use soc ...
362
363
  			(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT :
  						  MX31_CSPICTRL_CS_SHIFT);
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
364
365
366
367
368
  
  	writel(reg, spi_imx->base + MXC_CSPICTRL);
  
  	return 0;
  }
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
369
  static int __maybe_unused mx31_rx_available(struct spi_imx_data *spi_imx)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
370
  {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
371
  	return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
372
  }
2a64a90a2   Shawn Guo   spi/imx: merge ty...
373
  static void __maybe_unused mx31_reset(struct spi_imx_data *spi_imx)
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
374
375
  {
  	/* drain receive buffer */
2a64a90a2   Shawn Guo   spi/imx: merge ty...
376
  	while (readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR)
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
377
378
  		readl(spi_imx->base + MXC_CSPIRXDATA);
  }
3451fb156   Shawn Guo   spi/imx: use mx21...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  #define MX21_INTREG_RR		(1 << 4)
  #define MX21_INTREG_TEEN	(1 << 9)
  #define MX21_INTREG_RREN	(1 << 13)
  
  #define MX21_CSPICTRL_POL	(1 << 5)
  #define MX21_CSPICTRL_PHA	(1 << 6)
  #define MX21_CSPICTRL_SSPOL	(1 << 8)
  #define MX21_CSPICTRL_XCH	(1 << 9)
  #define MX21_CSPICTRL_ENABLE	(1 << 10)
  #define MX21_CSPICTRL_MASTER	(1 << 11)
  #define MX21_CSPICTRL_DR_SHIFT	14
  #define MX21_CSPICTRL_CS_SHIFT	19
  
  static void __maybe_unused mx21_intctrl(struct spi_imx_data *spi_imx, int enable)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
393
394
395
396
  {
  	unsigned int val = 0;
  
  	if (enable & MXC_INT_TE)
3451fb156   Shawn Guo   spi/imx: use mx21...
397
  		val |= MX21_INTREG_TEEN;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
398
  	if (enable & MXC_INT_RR)
3451fb156   Shawn Guo   spi/imx: use mx21...
399
  		val |= MX21_INTREG_RREN;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
400

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
401
  	writel(val, spi_imx->base + MXC_CSPIINT);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
402
  }
3451fb156   Shawn Guo   spi/imx: use mx21...
403
  static void __maybe_unused mx21_trigger(struct spi_imx_data *spi_imx)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
404
405
  {
  	unsigned int reg;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
406
  	reg = readl(spi_imx->base + MXC_CSPICTRL);
3451fb156   Shawn Guo   spi/imx: use mx21...
407
  	reg |= MX21_CSPICTRL_XCH;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
408
  	writel(reg, spi_imx->base + MXC_CSPICTRL);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
409
  }
3451fb156   Shawn Guo   spi/imx: use mx21...
410
  static int __maybe_unused mx21_config(struct spi_imx_data *spi_imx,
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
411
  		struct spi_imx_config *config)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
412
  {
3451fb156   Shawn Guo   spi/imx: use mx21...
413
  	unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER;
3b2aa89eb   Uwe Kleine-König   spi/imx: save the...
414
  	int cs = spi_imx->chipselect[config->cs];
04ee58549   Shawn Guo   spi/imx: use soc ...
415
  	unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
416

04ee58549   Shawn Guo   spi/imx: use soc ...
417
  	reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz, max) <<
3451fb156   Shawn Guo   spi/imx: use mx21...
418
  		MX21_CSPICTRL_DR_SHIFT;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
419
420
421
  	reg |= config->bpw - 1;
  
  	if (config->mode & SPI_CPHA)
3451fb156   Shawn Guo   spi/imx: use mx21...
422
  		reg |= MX21_CSPICTRL_PHA;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
423
  	if (config->mode & SPI_CPOL)
3451fb156   Shawn Guo   spi/imx: use mx21...
424
  		reg |= MX21_CSPICTRL_POL;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
425
  	if (config->mode & SPI_CS_HIGH)
3451fb156   Shawn Guo   spi/imx: use mx21...
426
  		reg |= MX21_CSPICTRL_SSPOL;
3b2aa89eb   Uwe Kleine-König   spi/imx: save the...
427
  	if (cs < 0)
3451fb156   Shawn Guo   spi/imx: use mx21...
428
  		reg |= (cs + 32) << MX21_CSPICTRL_CS_SHIFT;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
429

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
430
  	writel(reg, spi_imx->base + MXC_CSPICTRL);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
431
432
433
  
  	return 0;
  }
3451fb156   Shawn Guo   spi/imx: use mx21...
434
  static int __maybe_unused mx21_rx_available(struct spi_imx_data *spi_imx)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
435
  {
3451fb156   Shawn Guo   spi/imx: use mx21...
436
  	return readl(spi_imx->base + MXC_CSPIINT) & MX21_INTREG_RR;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
437
  }
3451fb156   Shawn Guo   spi/imx: use mx21...
438
  static void __maybe_unused mx21_reset(struct spi_imx_data *spi_imx)
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
439
440
441
  {
  	writel(1, spi_imx->base + MXC_RESET);
  }
b5f3294f0   Sascha Hauer   spi: add SPI driv...
442
443
444
445
446
447
448
449
450
451
  #define MX1_INTREG_RR		(1 << 3)
  #define MX1_INTREG_TEEN		(1 << 8)
  #define MX1_INTREG_RREN		(1 << 11)
  
  #define MX1_CSPICTRL_POL	(1 << 4)
  #define MX1_CSPICTRL_PHA	(1 << 5)
  #define MX1_CSPICTRL_XCH	(1 << 8)
  #define MX1_CSPICTRL_ENABLE	(1 << 9)
  #define MX1_CSPICTRL_MASTER	(1 << 10)
  #define MX1_CSPICTRL_DR_SHIFT	13
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
452
  static void __maybe_unused mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
453
454
455
456
457
458
459
  {
  	unsigned int val = 0;
  
  	if (enable & MXC_INT_TE)
  		val |= MX1_INTREG_TEEN;
  	if (enable & MXC_INT_RR)
  		val |= MX1_INTREG_RREN;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
460
  	writel(val, spi_imx->base + MXC_CSPIINT);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
461
  }
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
462
  static void __maybe_unused mx1_trigger(struct spi_imx_data *spi_imx)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
463
464
  {
  	unsigned int reg;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
465
  	reg = readl(spi_imx->base + MXC_CSPICTRL);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
466
  	reg |= MX1_CSPICTRL_XCH;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
467
  	writel(reg, spi_imx->base + MXC_CSPICTRL);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
468
  }
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
469
  static int __maybe_unused mx1_config(struct spi_imx_data *spi_imx,
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
470
  		struct spi_imx_config *config)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
471
472
  {
  	unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
473
  	reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
b5f3294f0   Sascha Hauer   spi: add SPI driv...
474
475
476
477
478
479
480
  		MX1_CSPICTRL_DR_SHIFT;
  	reg |= config->bpw - 1;
  
  	if (config->mode & SPI_CPHA)
  		reg |= MX1_CSPICTRL_PHA;
  	if (config->mode & SPI_CPOL)
  		reg |= MX1_CSPICTRL_POL;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
481
  	writel(reg, spi_imx->base + MXC_CSPICTRL);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
482
483
484
  
  	return 0;
  }
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
485
  static int __maybe_unused mx1_rx_available(struct spi_imx_data *spi_imx)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
486
  {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
487
  	return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
488
  }
1723e66b0   Uwe Kleine-König   spi/imx: get rid ...
489
490
491
492
  static void __maybe_unused mx1_reset(struct spi_imx_data *spi_imx)
  {
  	writel(1, spi_imx->base + MXC_RESET);
  }
04ee58549   Shawn Guo   spi/imx: use soc ...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
  static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
  	.intctrl = mx1_intctrl,
  	.config = mx1_config,
  	.trigger = mx1_trigger,
  	.rx_available = mx1_rx_available,
  	.reset = mx1_reset,
  	.devtype = IMX1_CSPI,
  };
  
  static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
  	.intctrl = mx21_intctrl,
  	.config = mx21_config,
  	.trigger = mx21_trigger,
  	.rx_available = mx21_rx_available,
  	.reset = mx21_reset,
  	.devtype = IMX21_CSPI,
  };
  
  static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
  	/* i.mx27 cspi shares the functions with i.mx21 one */
  	.intctrl = mx21_intctrl,
  	.config = mx21_config,
  	.trigger = mx21_trigger,
  	.rx_available = mx21_rx_available,
  	.reset = mx21_reset,
  	.devtype = IMX27_CSPI,
  };
  
  static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
  	.intctrl = mx31_intctrl,
  	.config = mx31_config,
  	.trigger = mx31_trigger,
  	.rx_available = mx31_rx_available,
  	.reset = mx31_reset,
  	.devtype = IMX31_CSPI,
  };
  
  static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
  	/* i.mx35 and later cspi shares the functions with i.mx31 one */
  	.intctrl = mx31_intctrl,
  	.config = mx31_config,
  	.trigger = mx31_trigger,
  	.rx_available = mx31_rx_available,
  	.reset = mx31_reset,
  	.devtype = IMX35_CSPI,
  };
  
  static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
  	.intctrl = mx51_ecspi_intctrl,
  	.config = mx51_ecspi_config,
  	.trigger = mx51_ecspi_trigger,
  	.rx_available = mx51_ecspi_rx_available,
  	.reset = mx51_ecspi_reset,
  	.devtype = IMX51_ECSPI,
  };
  
  static struct platform_device_id spi_imx_devtype[] = {
  	{
  		.name = "imx1-cspi",
  		.driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data,
  	}, {
  		.name = "imx21-cspi",
  		.driver_data = (kernel_ulong_t) &imx21_cspi_devtype_data,
  	}, {
  		.name = "imx27-cspi",
  		.driver_data = (kernel_ulong_t) &imx27_cspi_devtype_data,
  	}, {
  		.name = "imx31-cspi",
  		.driver_data = (kernel_ulong_t) &imx31_cspi_devtype_data,
  	}, {
  		.name = "imx35-cspi",
  		.driver_data = (kernel_ulong_t) &imx35_cspi_devtype_data,
  	}, {
  		.name = "imx51-ecspi",
  		.driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data,
  	}, {
  		/* sentinel */
  	}
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
571
  };
22a85e4cd   Shawn Guo   spi/imx: add devi...
572
573
574
575
576
577
578
579
580
  static const struct of_device_id spi_imx_dt_ids[] = {
  	{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
  	{ .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, },
  	{ .compatible = "fsl,imx27-cspi", .data = &imx27_cspi_devtype_data, },
  	{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
  	{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
  	{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
  	{ /* sentinel */ }
  };
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
581
  static void spi_imx_chipselect(struct spi_device *spi, int is_active)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
582
  {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
583
  	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
584
  	int gpio = spi_imx->chipselect[spi->chip_select];
e6a0a8bfe   Uwe Kleine-König   spi-imx: strip do...
585
586
  	int active = is_active != BITBANG_CS_INACTIVE;
  	int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
587

e6a0a8bfe   Uwe Kleine-König   spi-imx: strip do...
588
  	if (gpio < 0)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
589
  		return;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
590

e6a0a8bfe   Uwe Kleine-König   spi-imx: strip do...
591
  	gpio_set_value(gpio, dev_is_lowactive ^ active);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
592
  }
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
593
  static void spi_imx_push(struct spi_imx_data *spi_imx)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
594
  {
04ee58549   Shawn Guo   spi/imx: use soc ...
595
  	while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
596
  		if (!spi_imx->count)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
597
  			break;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
598
599
  		spi_imx->tx(spi_imx);
  		spi_imx->txfifo++;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
600
  	}
edd501bbf   Shawn Guo   spi/imx: do not m...
601
  	spi_imx->devtype_data->trigger(spi_imx);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
602
  }
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
603
  static irqreturn_t spi_imx_isr(int irq, void *dev_id)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
604
  {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
605
  	struct spi_imx_data *spi_imx = dev_id;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
606

edd501bbf   Shawn Guo   spi/imx: do not m...
607
  	while (spi_imx->devtype_data->rx_available(spi_imx)) {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
608
609
  		spi_imx->rx(spi_imx);
  		spi_imx->txfifo--;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
610
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
611
612
  	if (spi_imx->count) {
  		spi_imx_push(spi_imx);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
613
614
  		return IRQ_HANDLED;
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
615
  	if (spi_imx->txfifo) {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
616
617
618
  		/* No data left to push, but still waiting for rx data,
  		 * enable receive data available interrupt.
  		 */
edd501bbf   Shawn Guo   spi/imx: do not m...
619
  		spi_imx->devtype_data->intctrl(
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
620
  				spi_imx, MXC_INT_RR);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
621
622
  		return IRQ_HANDLED;
  	}
edd501bbf   Shawn Guo   spi/imx: do not m...
623
  	spi_imx->devtype_data->intctrl(spi_imx, 0);
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
624
  	complete(&spi_imx->xfer_done);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
625
626
627
  
  	return IRQ_HANDLED;
  }
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
628
  static int spi_imx_setupxfer(struct spi_device *spi,
b5f3294f0   Sascha Hauer   spi: add SPI driv...
629
630
  				 struct spi_transfer *t)
  {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
631
632
  	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
  	struct spi_imx_config config;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
633
634
635
636
  
  	config.bpw = t ? t->bits_per_word : spi->bits_per_word;
  	config.speed_hz  = t ? t->speed_hz : spi->max_speed_hz;
  	config.mode = spi->mode;
3b2aa89eb   Uwe Kleine-König   spi/imx: save the...
637
  	config.cs = spi->chip_select;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
638

462d26b5d   Sascha Hauer   spi-imx: update s...
639
640
641
642
643
644
  	if (!config.speed_hz)
  		config.speed_hz = spi->max_speed_hz;
  	if (!config.bpw)
  		config.bpw = spi->bits_per_word;
  	if (!config.speed_hz)
  		config.speed_hz = spi->max_speed_hz;
e6a0a8bfe   Uwe Kleine-König   spi-imx: strip do...
645
646
647
648
649
650
651
652
653
654
655
656
  	/* Initialize the functions for transfer */
  	if (config.bpw <= 8) {
  		spi_imx->rx = spi_imx_buf_rx_u8;
  		spi_imx->tx = spi_imx_buf_tx_u8;
  	} else if (config.bpw <= 16) {
  		spi_imx->rx = spi_imx_buf_rx_u16;
  		spi_imx->tx = spi_imx_buf_tx_u16;
  	} else if (config.bpw <= 32) {
  		spi_imx->rx = spi_imx_buf_rx_u32;
  		spi_imx->tx = spi_imx_buf_tx_u32;
  	} else
  		BUG();
edd501bbf   Shawn Guo   spi/imx: do not m...
657
  	spi_imx->devtype_data->config(spi_imx, &config);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
658
659
660
  
  	return 0;
  }
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
661
  static int spi_imx_transfer(struct spi_device *spi,
b5f3294f0   Sascha Hauer   spi: add SPI driv...
662
663
  				struct spi_transfer *transfer)
  {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
664
  	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
665

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
666
667
668
669
  	spi_imx->tx_buf = transfer->tx_buf;
  	spi_imx->rx_buf = transfer->rx_buf;
  	spi_imx->count = transfer->len;
  	spi_imx->txfifo = 0;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
670

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
671
  	init_completion(&spi_imx->xfer_done);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
672

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
673
  	spi_imx_push(spi_imx);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
674

edd501bbf   Shawn Guo   spi/imx: do not m...
675
  	spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
676

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
677
  	wait_for_completion(&spi_imx->xfer_done);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
678
679
680
  
  	return transfer->len;
  }
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
681
  static int spi_imx_setup(struct spi_device *spi)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
682
  {
6c23e5d43   Sascha Hauer   spi-imx: fix init...
683
684
  	struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
  	int gpio = spi_imx->chipselect[spi->chip_select];
f4d4ecfe7   Alberto Panizzo   spi/spi_imx: add ...
685
686
  	dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz
  ", __func__,
b5f3294f0   Sascha Hauer   spi: add SPI driv...
687
  		 spi->mode, spi->bits_per_word, spi->max_speed_hz);
6c23e5d43   Sascha Hauer   spi-imx: fix init...
688
689
  	if (gpio >= 0)
  		gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
690
  	spi_imx_chipselect(spi, BITBANG_CS_INACTIVE);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
691
692
693
  
  	return 0;
  }
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
694
  static void spi_imx_cleanup(struct spi_device *spi)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
695
696
  {
  }
965346e3b   Grant Likely   spi: fix probe/re...
697
  static int __devinit spi_imx_probe(struct platform_device *pdev)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
698
  {
22a85e4cd   Shawn Guo   spi/imx: add devi...
699
700
701
702
703
  	struct device_node *np = pdev->dev.of_node;
  	const struct of_device_id *of_id =
  			of_match_device(spi_imx_dt_ids, &pdev->dev);
  	struct spi_imx_master *mxc_platform_info =
  			dev_get_platdata(&pdev->dev);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
704
  	struct spi_master *master;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
705
  	struct spi_imx_data *spi_imx;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
706
  	struct resource *res;
c2387cb9e   Shawn Guo   spi/imx: copy gpi...
707
  	int i, ret, num_cs;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
708

22a85e4cd   Shawn Guo   spi/imx: add devi...
709
  	if (!np && !mxc_platform_info) {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
710
711
712
713
  		dev_err(&pdev->dev, "can't get the platform data
  ");
  		return -EINVAL;
  	}
22a85e4cd   Shawn Guo   spi/imx: add devi...
714
715
716
  	ret = of_property_read_u32(np, "fsl,spi-num-chipselects", &num_cs);
  	if (ret < 0)
  		num_cs = mxc_platform_info->num_chipselect;
c2387cb9e   Shawn Guo   spi/imx: copy gpi...
717
718
  	master = spi_alloc_master(&pdev->dev,
  			sizeof(struct spi_imx_data) + sizeof(int) * num_cs);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
719
720
721
722
723
724
  	if (!master)
  		return -ENOMEM;
  
  	platform_set_drvdata(pdev, master);
  
  	master->bus_num = pdev->id;
c2387cb9e   Shawn Guo   spi/imx: copy gpi...
725
  	master->num_chipselect = num_cs;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
726

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
727
728
  	spi_imx = spi_master_get_devdata(master);
  	spi_imx->bitbang.master = spi_master_get(master);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
729
730
  
  	for (i = 0; i < master->num_chipselect; i++) {
22a85e4cd   Shawn Guo   spi/imx: add devi...
731
732
733
  		int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
  		if (cs_gpio < 0)
  			cs_gpio = mxc_platform_info->chipselect[i];
4cc122ac9   Fabio Estevam   spi/imx: Fix spi-...
734
735
  
  		spi_imx->chipselect[i] = cs_gpio;
22a85e4cd   Shawn Guo   spi/imx: add devi...
736
  		if (cs_gpio < 0)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
737
  			continue;
4cc122ac9   Fabio Estevam   spi/imx: Fix spi-...
738

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
739
  		ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
740
  		if (ret) {
bbd050af0   John Ogness   spi/i.MX: fix bro...
741
742
  			while (i > 0) {
  				i--;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
743
  				if (spi_imx->chipselect[i] >= 0)
bbd050af0   John Ogness   spi/i.MX: fix bro...
744
745
746
747
  					gpio_free(spi_imx->chipselect[i]);
  			}
  			dev_err(&pdev->dev, "can't get cs gpios
  ");
b5f3294f0   Sascha Hauer   spi: add SPI driv...
748
749
  			goto out_master_put;
  		}
b5f3294f0   Sascha Hauer   spi: add SPI driv...
750
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
751
752
753
754
755
  	spi_imx->bitbang.chipselect = spi_imx_chipselect;
  	spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
  	spi_imx->bitbang.txrx_bufs = spi_imx_transfer;
  	spi_imx->bitbang.master->setup = spi_imx_setup;
  	spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
3910f2cff   Sascha Hauer   spi-imx: setup mo...
756
  	spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
b5f3294f0   Sascha Hauer   spi: add SPI driv...
757

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
758
  	init_completion(&spi_imx->xfer_done);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
759

22a85e4cd   Shawn Guo   spi/imx: add devi...
760
  	spi_imx->devtype_data = of_id ? of_id->data :
04ee58549   Shawn Guo   spi/imx: use soc ...
761
  		(struct spi_imx_devtype_data *) pdev->id_entry->driver_data;
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
762

b5f3294f0   Sascha Hauer   spi: add SPI driv...
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res) {
  		dev_err(&pdev->dev, "can't get platform resource
  ");
  		ret = -ENOMEM;
  		goto out_gpio_free;
  	}
  
  	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
  		dev_err(&pdev->dev, "request_mem_region failed
  ");
  		ret = -EBUSY;
  		goto out_gpio_free;
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
777
778
  	spi_imx->base = ioremap(res->start, resource_size(res));
  	if (!spi_imx->base) {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
779
780
781
  		ret = -EINVAL;
  		goto out_release_mem;
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
782
  	spi_imx->irq = platform_get_irq(pdev, 0);
735759389   Richard Genoud   spi/imx: correct ...
783
  	if (spi_imx->irq < 0) {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
784
785
786
  		ret = -EINVAL;
  		goto out_iounmap;
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
787
  	ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
788
  	if (ret) {
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
789
790
  		dev_err(&pdev->dev, "can't get irq%d: %d
  ", spi_imx->irq, ret);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
791
792
  		goto out_iounmap;
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
793
794
  	spi_imx->clk = clk_get(&pdev->dev, NULL);
  	if (IS_ERR(spi_imx->clk)) {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
795
796
  		dev_err(&pdev->dev, "unable to get clock
  ");
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
797
  		ret = PTR_ERR(spi_imx->clk);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
798
799
  		goto out_free_irq;
  	}
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
800
801
  	clk_enable(spi_imx->clk);
  	spi_imx->spi_clk = clk_get_rate(spi_imx->clk);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
802

edd501bbf   Shawn Guo   spi/imx: do not m...
803
  	spi_imx->devtype_data->reset(spi_imx);
ce1807b2e   Daniel Mack   spi/i.mx: drain M...
804

edd501bbf   Shawn Guo   spi/imx: do not m...
805
  	spi_imx->devtype_data->intctrl(spi_imx, 0);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
806

22a85e4cd   Shawn Guo   spi/imx: add devi...
807
  	master->dev.of_node = pdev->dev.of_node;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
808
  	ret = spi_bitbang_start(&spi_imx->bitbang);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
809
810
811
812
813
814
815
816
817
818
819
820
  	if (ret) {
  		dev_err(&pdev->dev, "bitbang start failed with %d
  ", ret);
  		goto out_clk_put;
  	}
  
  	dev_info(&pdev->dev, "probed
  ");
  
  	return ret;
  
  out_clk_put:
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
821
822
  	clk_disable(spi_imx->clk);
  	clk_put(spi_imx->clk);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
823
  out_free_irq:
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
824
  	free_irq(spi_imx->irq, spi_imx);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
825
  out_iounmap:
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
826
  	iounmap(spi_imx->base);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
827
828
829
830
  out_release_mem:
  	release_mem_region(res->start, resource_size(res));
  out_gpio_free:
  	for (i = 0; i < master->num_chipselect; i++)
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
831
832
  		if (spi_imx->chipselect[i] >= 0)
  			gpio_free(spi_imx->chipselect[i]);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
833
834
835
836
837
838
  out_master_put:
  	spi_master_put(master);
  	kfree(master);
  	platform_set_drvdata(pdev, NULL);
  	return ret;
  }
965346e3b   Grant Likely   spi: fix probe/re...
839
  static int __devexit spi_imx_remove(struct platform_device *pdev)
b5f3294f0   Sascha Hauer   spi: add SPI driv...
840
841
842
  {
  	struct spi_master *master = platform_get_drvdata(pdev);
  	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
843
  	struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
844
  	int i;
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
845
  	spi_bitbang_stop(&spi_imx->bitbang);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
846

6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
847
848
849
850
851
  	writel(0, spi_imx->base + MXC_CSPICTRL);
  	clk_disable(spi_imx->clk);
  	clk_put(spi_imx->clk);
  	free_irq(spi_imx->irq, spi_imx);
  	iounmap(spi_imx->base);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
852
853
  
  	for (i = 0; i < master->num_chipselect; i++)
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
854
855
  		if (spi_imx->chipselect[i] >= 0)
  			gpio_free(spi_imx->chipselect[i]);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
856
857
858
859
860
861
862
863
864
  
  	spi_master_put(master);
  
  	release_mem_region(res->start, resource_size(res));
  
  	platform_set_drvdata(pdev, NULL);
  
  	return 0;
  }
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
865
  static struct platform_driver spi_imx_driver = {
b5f3294f0   Sascha Hauer   spi: add SPI driv...
866
867
868
  	.driver = {
  		   .name = DRIVER_NAME,
  		   .owner = THIS_MODULE,
22a85e4cd   Shawn Guo   spi/imx: add devi...
869
  		   .of_match_table = spi_imx_dt_ids,
b5f3294f0   Sascha Hauer   spi: add SPI driv...
870
  		   },
f4ba6315c   Uwe Kleine-König   spi/imx: convert ...
871
  	.id_table = spi_imx_devtype,
6cdeb0021   Uwe Kleine-König   spi-imx: rename s...
872
  	.probe = spi_imx_probe,
965346e3b   Grant Likely   spi: fix probe/re...
873
  	.remove = __devexit_p(spi_imx_remove),
b5f3294f0   Sascha Hauer   spi: add SPI driv...
874
  };
940ab8896   Grant Likely   drivercore: Add h...
875
  module_platform_driver(spi_imx_driver);
b5f3294f0   Sascha Hauer   spi: add SPI driv...
876
877
878
879
  
  MODULE_DESCRIPTION("SPI Master Controller driver");
  MODULE_AUTHOR("Sascha Hauer, Pengutronix");
  MODULE_LICENSE("GPL");