Blame view

drivers/spi/spi-fsl-espi.c 21.3 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
2
3
4
5
  /*
   * Freescale eSPI controller driver.
   *
   * Copyright 2010 Freescale Semiconductor, Inc.
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
6
   */
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
7
  #include <linux/delay.h>
a31083600   Xiubo Li   spi: fsl: Sort in...
8
  #include <linux/err.h>
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
9
  #include <linux/fsl_devices.h>
a31083600   Xiubo Li   spi: fsl: Sort in...
10
  #include <linux/interrupt.h>
a31083600   Xiubo Li   spi: fsl: Sort in...
11
  #include <linux/module.h>
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
12
13
  #include <linux/mm.h>
  #include <linux/of.h>
5af507300   Rob Herring   drivers: clean-up...
14
15
  #include <linux/of_address.h>
  #include <linux/of_irq.h>
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
16
  #include <linux/of_platform.h>
a31083600   Xiubo Li   spi: fsl: Sort in...
17
18
  #include <linux/platform_device.h>
  #include <linux/spi/spi.h>
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
19
  #include <linux/pm_runtime.h>
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
20
  #include <sysdev/fsl_soc.h>
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
21
  /* eSPI Controller registers */
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
22
23
24
25
26
27
28
29
30
  #define ESPI_SPMODE	0x00	/* eSPI mode register */
  #define ESPI_SPIE	0x04	/* eSPI event register */
  #define ESPI_SPIM	0x08	/* eSPI mask register */
  #define ESPI_SPCOM	0x0c	/* eSPI command register */
  #define ESPI_SPITF	0x10	/* eSPI transmit FIFO access register*/
  #define ESPI_SPIRF	0x14	/* eSPI receive FIFO access register*/
  #define ESPI_SPMODE0	0x20	/* eSPI cs0 mode register */
  
  #define ESPI_SPMODEx(x)	(ESPI_SPMODE0 + (x) * 4)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
31

8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
32
  /* eSPI Controller mode register definitions */
81abc2eca   Heiner Kallweit   spi: fsl-espi: im...
33
34
  #define SPMODE_ENABLE		BIT(31)
  #define SPMODE_LOOP		BIT(30)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
35
36
37
38
  #define SPMODE_TXTHR(x)		((x) << 8)
  #define SPMODE_RXTHR(x)		((x) << 0)
  
  /* eSPI Controller CS mode register definitions */
81abc2eca   Heiner Kallweit   spi: fsl-espi: im...
39
40
41
42
  #define CSMODE_CI_INACTIVEHIGH	BIT(31)
  #define CSMODE_CP_BEGIN_EDGECLK	BIT(30)
  #define CSMODE_REV		BIT(29)
  #define CSMODE_DIV16		BIT(28)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
43
  #define CSMODE_PM(x)		((x) << 24)
81abc2eca   Heiner Kallweit   spi: fsl-espi: im...
44
  #define CSMODE_POL_1		BIT(20)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
45
46
47
48
  #define CSMODE_LEN(x)		((x) << 16)
  #define CSMODE_BEF(x)		((x) << 12)
  #define CSMODE_AFT(x)		((x) << 8)
  #define CSMODE_CG(x)		((x) << 3)
547312659   Heiner Kallweit   spi: fsl-espi: fi...
49
  #define FSL_ESPI_FIFO_SIZE	32
e508cea45   Heiner Kallweit   spi: fsl-espi: ma...
50
  #define FSL_ESPI_RXTHR		15
547312659   Heiner Kallweit   spi: fsl-espi: fi...
51

8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
52
  /* Default mode/csmode for eSPI controller */
e508cea45   Heiner Kallweit   spi: fsl-espi: ma...
53
  #define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(FSL_ESPI_RXTHR))
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
54
55
56
57
  #define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
  		| CSMODE_AFT(0) | CSMODE_CG(1))
  
  /* SPIE register values */
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
58
59
  #define SPIE_RXCNT(reg)     ((reg >> 24) & 0x3F)
  #define SPIE_TXCNT(reg)     ((reg >> 16) & 0x3F)
81abc2eca   Heiner Kallweit   spi: fsl-espi: im...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  #define	SPIE_TXE		BIT(15)	/* TX FIFO empty */
  #define	SPIE_DON		BIT(14)	/* TX done */
  #define	SPIE_RXT		BIT(13)	/* RX FIFO threshold */
  #define	SPIE_RXF		BIT(12)	/* RX FIFO full */
  #define	SPIE_TXT		BIT(11)	/* TX FIFO threshold*/
  #define	SPIE_RNE		BIT(9)	/* RX FIFO not empty */
  #define	SPIE_TNF		BIT(8)	/* TX FIFO not full */
  
  /* SPIM register values */
  #define	SPIM_TXE		BIT(15)	/* TX FIFO empty */
  #define	SPIM_DON		BIT(14)	/* TX done */
  #define	SPIM_RXT		BIT(13)	/* RX FIFO threshold */
  #define	SPIM_RXF		BIT(12)	/* RX FIFO full */
  #define	SPIM_TXT		BIT(11)	/* TX FIFO threshold*/
  #define	SPIM_RNE		BIT(9)	/* RX FIFO not empty */
  #define	SPIM_TNF		BIT(8)	/* TX FIFO not full */
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
76
77
78
  
  /* SPCOM register values */
  #define SPCOM_CS(x)		((x) << 30)
81abc2eca   Heiner Kallweit   spi: fsl-espi: im...
79
80
81
  #define SPCOM_DO		BIT(28) /* Dual output */
  #define SPCOM_TO		BIT(27) /* TX only */
  #define SPCOM_RXSKIP(x)		((x) << 16)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
82
  #define SPCOM_TRANLEN(x)	((x) << 0)
81abc2eca   Heiner Kallweit   spi: fsl-espi: im...
83

5cfa1e4e0   Hou Zhiqiang   spi/fsl-espi: Cor...
84
  #define	SPCOM_TRANLEN_MAX	0x10000	/* Max transaction length */
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
85

e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
86
  #define AUTOSUSPEND_TIMEOUT 2000
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
87
88
89
  struct fsl_espi {
  	struct device *dev;
  	void __iomem *reg_base;
058234328   Heiner Kallweit   spi: fsl-espi: el...
90
91
92
93
  	struct list_head *m_transfers;
  	struct spi_transfer *tx_t;
  	unsigned int tx_pos;
  	bool tx_done;
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
94
95
96
  	struct spi_transfer *rx_t;
  	unsigned int rx_pos;
  	bool rx_done;
058234328   Heiner Kallweit   spi: fsl-espi: el...
97

e1cdee73d   Heiner Kallweit   spi: fsl-espi: de...
98
  	bool swab;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
99
  	unsigned int rxskip;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
100
101
102
103
104
105
  	spinlock_t lock;
  
  	u32 spibrg;             /* SPIBRG input clock */
  
  	struct completion done;
  };
219b5e3b2   Heiner Kallweit   spi: fsl-espi: in...
106
107
108
  struct fsl_espi_cs {
  	u32 hw_mode;
  };
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
109
  static inline u32 fsl_espi_read_reg(struct fsl_espi *espi, int offset)
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
110
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
111
  	return ioread32be(espi->reg_base + offset);
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
112
  }
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
113
114
  static inline u16 fsl_espi_read_reg16(struct fsl_espi *espi, int offset)
  {
7e2ef0033   Heiner Kallweit   spi: fsl-espi: fi...
115
  	return ioread16be(espi->reg_base + offset);
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
116
  }
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
117
  static inline u8 fsl_espi_read_reg8(struct fsl_espi *espi, int offset)
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
118
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
119
  	return ioread8(espi->reg_base + offset);
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
120
  }
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
121
  static inline void fsl_espi_write_reg(struct fsl_espi *espi, int offset,
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
122
123
  				      u32 val)
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
124
  	iowrite32be(val, espi->reg_base + offset);
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
125
  }
058234328   Heiner Kallweit   spi: fsl-espi: el...
126
127
128
  static inline void fsl_espi_write_reg16(struct fsl_espi *espi, int offset,
  					u16 val)
  {
7e2ef0033   Heiner Kallweit   spi: fsl-espi: fi...
129
  	iowrite16be(val, espi->reg_base + offset);
058234328   Heiner Kallweit   spi: fsl-espi: el...
130
  }
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
131
  static inline void fsl_espi_write_reg8(struct fsl_espi *espi, int offset,
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
132
133
  				       u8 val)
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
134
  	iowrite8(val, espi->reg_base + offset);
46afd38b7   Heiner Kallweit   spi: fsl-espi: al...
135
  }
d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
136
137
  static int fsl_espi_check_message(struct spi_message *m)
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
138
  	struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
139
140
141
  	struct spi_transfer *t, *first;
  
  	if (m->frame_length > SPCOM_TRANLEN_MAX) {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
142
143
  		dev_err(espi->dev, "message too long, size is %u bytes
  ",
d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
144
145
146
147
148
149
  			m->frame_length);
  		return -EMSGSIZE;
  	}
  
  	first = list_first_entry(&m->transfers, struct spi_transfer,
  				 transfer_list);
e4be7053b   Heiner Kallweit   spi: fsl-espi: re...
150

d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
151
152
153
  	list_for_each_entry(t, &m->transfers, transfer_list) {
  		if (first->bits_per_word != t->bits_per_word ||
  		    first->speed_hz != t->speed_hz) {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
154
155
  			dev_err(espi->dev, "bits_per_word/speed_hz should be the same for all transfers
  ");
d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
156
157
158
  			return -EINVAL;
  		}
  	}
e4be7053b   Heiner Kallweit   spi: fsl-espi: re...
159
160
161
  	/* ESPI supports MSB-first transfers for word size 8 / 16 only */
  	if (!(m->spi->mode & SPI_LSB_FIRST) && first->bits_per_word != 8 &&
  	    first->bits_per_word != 16) {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
162
  		dev_err(espi->dev,
e4be7053b   Heiner Kallweit   spi: fsl-espi: re...
163
164
165
166
167
  			"MSB-first transfer not supported for wordsize %u
  ",
  			first->bits_per_word);
  		return -EINVAL;
  	}
d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
168
169
  	return 0;
  }
aca75157d   Heiner Kallweit   spi: fsl-espi: ad...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  static unsigned int fsl_espi_check_rxskip_mode(struct spi_message *m)
  {
  	struct spi_transfer *t;
  	unsigned int i = 0, rxskip = 0;
  
  	/*
  	 * prerequisites for ESPI rxskip mode:
  	 * - message has two transfers
  	 * - first transfer is a write and second is a read
  	 *
  	 * In addition the current low-level transfer mechanism requires
  	 * that the rxskip bytes fit into the TX FIFO. Else the transfer
  	 * would hang because after the first FSL_ESPI_FIFO_SIZE bytes
  	 * the TX FIFO isn't re-filled.
  	 */
  	list_for_each_entry(t, &m->transfers, transfer_list) {
  		if (i == 0) {
  			if (!t->tx_buf || t->rx_buf ||
  			    t->len > FSL_ESPI_FIFO_SIZE)
  				return 0;
  			rxskip = t->len;
  		} else if (i == 1) {
  			if (t->tx_buf || !t->rx_buf)
  				return 0;
  		}
  		i++;
  	}
  
  	return i == 2 ? rxskip : 0;
  }
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
200
  static void fsl_espi_fill_tx_fifo(struct fsl_espi *espi, u32 events)
547312659   Heiner Kallweit   spi: fsl-espi: fi...
201
202
  {
  	u32 tx_fifo_avail;
058234328   Heiner Kallweit   spi: fsl-espi: el...
203
204
  	unsigned int tx_left;
  	const void *tx_buf;
547312659   Heiner Kallweit   spi: fsl-espi: fi...
205
206
207
  
  	/* if events is zero transfer has not started and tx fifo is empty */
  	tx_fifo_avail = events ? SPIE_TXCNT(events) :  FSL_ESPI_FIFO_SIZE;
058234328   Heiner Kallweit   spi: fsl-espi: el...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  start:
  	tx_left = espi->tx_t->len - espi->tx_pos;
  	tx_buf = espi->tx_t->tx_buf;
  	while (tx_fifo_avail >= min(4U, tx_left) && tx_left) {
  		if (tx_left >= 4) {
  			if (!tx_buf)
  				fsl_espi_write_reg(espi, ESPI_SPITF, 0);
  			else if (espi->swab)
  				fsl_espi_write_reg(espi, ESPI_SPITF,
  					swahb32p(tx_buf + espi->tx_pos));
  			else
  				fsl_espi_write_reg(espi, ESPI_SPITF,
  					*(u32 *)(tx_buf + espi->tx_pos));
  			espi->tx_pos += 4;
  			tx_left -= 4;
547312659   Heiner Kallweit   spi: fsl-espi: fi...
223
  			tx_fifo_avail -= 4;
058234328   Heiner Kallweit   spi: fsl-espi: el...
224
225
226
227
228
229
  		} else if (tx_left >= 2 && tx_buf && espi->swab) {
  			fsl_espi_write_reg16(espi, ESPI_SPITF,
  					swab16p(tx_buf + espi->tx_pos));
  			espi->tx_pos += 2;
  			tx_left -= 2;
  			tx_fifo_avail -= 2;
547312659   Heiner Kallweit   spi: fsl-espi: fi...
230
  		} else {
058234328   Heiner Kallweit   spi: fsl-espi: el...
231
232
233
234
235
236
237
  			if (!tx_buf)
  				fsl_espi_write_reg8(espi, ESPI_SPITF, 0);
  			else
  				fsl_espi_write_reg8(espi, ESPI_SPITF,
  					*(u8 *)(tx_buf + espi->tx_pos));
  			espi->tx_pos += 1;
  			tx_left -= 1;
547312659   Heiner Kallweit   spi: fsl-espi: fi...
238
239
  			tx_fifo_avail -= 1;
  		}
058234328   Heiner Kallweit   spi: fsl-espi: el...
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  	}
  
  	if (!tx_left) {
  		/* Last transfer finished, in rxskip mode only one is needed */
  		if (list_is_last(&espi->tx_t->transfer_list,
  		    espi->m_transfers) || espi->rxskip) {
  			espi->tx_done = true;
  			return;
  		}
  		espi->tx_t = list_next_entry(espi->tx_t, transfer_list);
  		espi->tx_pos = 0;
  		/* continue with next transfer if tx fifo is not full */
  		if (tx_fifo_avail)
  			goto start;
  	}
547312659   Heiner Kallweit   spi: fsl-espi: fi...
255
  }
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
256
  static void fsl_espi_read_rx_fifo(struct fsl_espi *espi, u32 events)
f05689a66   Heiner Kallweit   spi: fsl-espi: fi...
257
258
  {
  	u32 rx_fifo_avail = SPIE_RXCNT(events);
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
259
260
  	unsigned int rx_left;
  	void *rx_buf;
f05689a66   Heiner Kallweit   spi: fsl-espi: fi...
261

dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
262
263
264
265
266
267
268
269
270
271
272
273
274
  start:
  	rx_left = espi->rx_t->len - espi->rx_pos;
  	rx_buf = espi->rx_t->rx_buf;
  	while (rx_fifo_avail >= min(4U, rx_left) && rx_left) {
  		if (rx_left >= 4) {
  			u32 val = fsl_espi_read_reg(espi, ESPI_SPIRF);
  
  			if (rx_buf && espi->swab)
  				*(u32 *)(rx_buf + espi->rx_pos) = swahb32(val);
  			else if (rx_buf)
  				*(u32 *)(rx_buf + espi->rx_pos) = val;
  			espi->rx_pos += 4;
  			rx_left -= 4;
f05689a66   Heiner Kallweit   spi: fsl-espi: fi...
275
  			rx_fifo_avail -= 4;
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
276
277
278
279
280
281
282
  		} else if (rx_left >= 2 && rx_buf && espi->swab) {
  			u16 val = fsl_espi_read_reg16(espi, ESPI_SPIRF);
  
  			*(u16 *)(rx_buf + espi->rx_pos) = swab16(val);
  			espi->rx_pos += 2;
  			rx_left -= 2;
  			rx_fifo_avail -= 2;
f05689a66   Heiner Kallweit   spi: fsl-espi: fi...
283
  		} else {
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
284
285
286
287
288
289
  			u8 val = fsl_espi_read_reg8(espi, ESPI_SPIRF);
  
  			if (rx_buf)
  				*(u8 *)(rx_buf + espi->rx_pos) = val;
  			espi->rx_pos += 1;
  			rx_left -= 1;
f05689a66   Heiner Kallweit   spi: fsl-espi: fi...
290
291
  			rx_fifo_avail -= 1;
  		}
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  	}
  
  	if (!rx_left) {
  		if (list_is_last(&espi->rx_t->transfer_list,
  		    espi->m_transfers)) {
  			espi->rx_done = true;
  			return;
  		}
  		espi->rx_t = list_next_entry(espi->rx_t, transfer_list);
  		espi->rx_pos = 0;
  		/* continue with next transfer if rx fifo is not empty */
  		if (rx_fifo_avail)
  			goto start;
  	}
f05689a66   Heiner Kallweit   spi: fsl-espi: fi...
306
  }
ea616ee22   Heiner Kallweit   spi: fsl-espi: ch...
307
  static void fsl_espi_setup_transfer(struct spi_device *spi,
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
308
309
  					struct spi_transfer *t)
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
310
  	struct fsl_espi *espi = spi_master_get_devdata(spi->master);
d198ebfb7   Heiner Kallweit   spi: fsl-espi: si...
311
  	int bits_per_word = t ? t->bits_per_word : spi->bits_per_word;
73aaf1584   Paulo Zaneti   spi: fsl-espi: fi...
312
  	u32 pm, hz = t ? t->speed_hz : spi->max_speed_hz;
219b5e3b2   Heiner Kallweit   spi: fsl-espi: in...
313
  	struct fsl_espi_cs *cs = spi_get_ctldata(spi);
8f3086d2a   Heiner Kallweit   spi: fsl-espi: do...
314
  	u32 hw_mode_old = cs->hw_mode;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
315

8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
316
317
  	/* mask out bits we are going to set */
  	cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF));
a755af52f   Heiner Kallweit   spi: fsl-espi: si...
318
  	cs->hw_mode |= CSMODE_LEN(bits_per_word - 1);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
319

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
320
  	pm = DIV_ROUND_UP(espi->spibrg, hz * 4) - 1;
73aaf1584   Paulo Zaneti   spi: fsl-espi: fi...
321
322
  
  	if (pm > 15) {
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
323
  		cs->hw_mode |= CSMODE_DIV16;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
324
  		pm = DIV_ROUND_UP(espi->spibrg, hz * 16 * 4) - 1;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
325
  	}
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
326
327
  
  	cs->hw_mode |= CSMODE_PM(pm);
8f3086d2a   Heiner Kallweit   spi: fsl-espi: do...
328
329
  	/* don't write the mode register if the mode doesn't change */
  	if (cs->hw_mode != hw_mode_old)
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
330
  		fsl_espi_write_reg(espi, ESPI_SPMODEx(spi->chip_select),
8f3086d2a   Heiner Kallweit   spi: fsl-espi: do...
331
  				   cs->hw_mode);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
332
  }
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
333
334
  static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
335
  	struct fsl_espi *espi = spi_master_get_devdata(spi->master);
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
336
  	unsigned int rx_len = t->len;
aca75157d   Heiner Kallweit   spi: fsl-espi: ad...
337
  	u32 mask, spcom;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
338
  	int ret;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
339
  	reinit_completion(&espi->done);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
340
341
  
  	/* Set SPCOM[CS] and SPCOM[TRANLEN] field */
aca75157d   Heiner Kallweit   spi: fsl-espi: ad...
342
343
344
345
  	spcom = SPCOM_CS(spi->chip_select);
  	spcom |= SPCOM_TRANLEN(t->len - 1);
  
  	/* configure RXSKIP mode */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
346
347
  	if (espi->rxskip) {
  		spcom |= SPCOM_RXSKIP(espi->rxskip);
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
348
  		rx_len = t->len - espi->rxskip;
8263cb33c   Heiner Kallweit   spi: fsl-espi: ad...
349
350
  		if (t->rx_nbits == SPI_NBITS_DUAL)
  			spcom |= SPCOM_DO;
aca75157d   Heiner Kallweit   spi: fsl-espi: ad...
351
  	}
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
352
  	fsl_espi_write_reg(espi, ESPI_SPCOM, spcom);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
353

e508cea45   Heiner Kallweit   spi: fsl-espi: ma...
354
355
  	/* enable interrupts */
  	mask = SPIM_DON;
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
356
  	if (rx_len > FSL_ESPI_FIFO_SIZE)
e508cea45   Heiner Kallweit   spi: fsl-espi: ma...
357
  		mask |= SPIM_RXT;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
358
  	fsl_espi_write_reg(espi, ESPI_SPIM, mask);
5bcc6a2f0   Heiner Kallweit   spi: fsl-espi: me...
359

547312659   Heiner Kallweit   spi: fsl-espi: fi...
360
  	/* Prevent filling the fifo from getting interrupted */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
361
362
363
  	spin_lock_irq(&espi->lock);
  	fsl_espi_fill_tx_fifo(espi, 0);
  	spin_unlock_irq(&espi->lock);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
364

aa70e567c   Nobuteru Hayashi   spi/fsl-espi: Don...
365
  	/* Won't hang up forever, SPI bus sometimes got lost interrupts... */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
366
  	ret = wait_for_completion_timeout(&espi->done, 2 * HZ);
aa70e567c   Nobuteru Hayashi   spi/fsl-espi: Don...
367
  	if (ret == 0)
058234328   Heiner Kallweit   spi: fsl-espi: el...
368
369
  		dev_err(espi->dev, "Transfer timed out!
  ");
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
370
371
  
  	/* disable rx ints */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
372
  	fsl_espi_write_reg(espi, ESPI_SPIM, 0);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
373

db1b049fa   Heiner Kallweit   spi: fsl-espi: ex...
374
  	return ret == 0 ? -ETIMEDOUT : 0;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
375
  }
38d003f1a   Heiner Kallweit   spi: fsl-espi: me...
376
  static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
377
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
378
  	struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
379
  	struct spi_device *spi = m->spi;
38d003f1a   Heiner Kallweit   spi: fsl-espi: me...
380
  	int ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
381

e1cdee73d   Heiner Kallweit   spi: fsl-espi: de...
382
383
  	/* In case of LSB-first and bits_per_word > 8 byte-swap all words */
  	espi->swab = spi->mode & SPI_LSB_FIRST && trans->bits_per_word > 8;
058234328   Heiner Kallweit   spi: fsl-espi: el...
384
385
386
387
388
  	espi->m_transfers = &m->transfers;
  	espi->tx_t = list_first_entry(&m->transfers, struct spi_transfer,
  				      transfer_list);
  	espi->tx_pos = 0;
  	espi->tx_done = false;
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
389
390
391
392
  	espi->rx_t = list_first_entry(&m->transfers, struct spi_transfer,
  				      transfer_list);
  	espi->rx_pos = 0;
  	espi->rx_done = false;
058234328   Heiner Kallweit   spi: fsl-espi: el...
393

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
394
395
396
397
  	espi->rxskip = fsl_espi_check_rxskip_mode(m);
  	if (trans->rx_nbits == SPI_NBITS_DUAL && !espi->rxskip) {
  		dev_err(espi->dev, "Dual output mode requires RXSKIP mode!
  ");
8263cb33c   Heiner Kallweit   spi: fsl-espi: ad...
398
399
  		return -EINVAL;
  	}
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
400
401
402
  	/* In RXSKIP mode skip first transfer for reads */
  	if (espi->rxskip)
  		espi->rx_t = list_next_entry(espi->rx_t, transfer_list);
faceef390   Heiner Kallweit   spi: fsl-espi: el...
403
  	fsl_espi_setup_transfer(spi, trans);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
404

06af115d6   Heiner Kallweit   spi: fsl-espi: im...
405
  	ret = fsl_espi_bufs(spi, trans);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
406

e74dc5c76   Alexandru Ardelean   spi: use new `spi...
407
  	spi_transfer_delay_exec(trans);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
408

e33a3ade9   Heiner Kallweit   spi: fsl-espi: re...
409
  	return ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
410
  }
c592becbe   Heiner Kallweit   spi: fsl-(e)spi: ...
411
412
  static int fsl_espi_do_one_msg(struct spi_master *master,
  			       struct spi_message *m)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
413
  {
8263cb33c   Heiner Kallweit   spi: fsl-espi: ad...
414
  	unsigned int delay_usecs = 0, rx_nbits = 0;
3984d39b0   Alexandru Ardelean   spi: spi-fsl-espi...
415
  	unsigned int delay_nsecs = 0, delay_nsecs1 = 0;
faceef390   Heiner Kallweit   spi: fsl-espi: el...
416
  	struct spi_transfer *t, trans = {};
e33a3ade9   Heiner Kallweit   spi: fsl-espi: re...
417
  	int ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
418

d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
419
420
421
  	ret = fsl_espi_check_message(m);
  	if (ret)
  		goto out;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
422
  	list_for_each_entry(t, &m->transfers, transfer_list) {
3984d39b0   Alexandru Ardelean   spi: spi-fsl-espi...
423
424
425
426
427
428
429
430
431
432
  		if (t->delay_usecs) {
  			if (t->delay_usecs > delay_usecs) {
  				delay_usecs = t->delay_usecs;
  				delay_nsecs = delay_usecs * 1000;
  			}
  		} else {
  			delay_nsecs1 = spi_delay_to_ns(&t->delay, t);
  			if (delay_nsecs1 > delay_nsecs)
  				delay_nsecs = delay_nsecs1;
  		}
8263cb33c   Heiner Kallweit   spi: fsl-espi: ad...
433
434
  		if (t->rx_nbits > rx_nbits)
  			rx_nbits = t->rx_nbits;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
435
  	}
96361fafb   Heiner Kallweit   spi: fsl-espi: ce...
436
437
  	t = list_first_entry(&m->transfers, struct spi_transfer,
  			     transfer_list);
06af115d6   Heiner Kallweit   spi: fsl-espi: im...
438
  	trans.len = m->frame_length;
96361fafb   Heiner Kallweit   spi: fsl-espi: ce...
439
440
  	trans.speed_hz = t->speed_hz;
  	trans.bits_per_word = t->bits_per_word;
3984d39b0   Alexandru Ardelean   spi: spi-fsl-espi...
441
442
  	trans.delay.value = delay_nsecs;
  	trans.delay.unit = SPI_DELAY_UNIT_NSECS;
8263cb33c   Heiner Kallweit   spi: fsl-espi: ad...
443
  	trans.rx_nbits = rx_nbits;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
444

06af115d6   Heiner Kallweit   spi: fsl-espi: im...
445
446
  	if (trans.len)
  		ret = fsl_espi_trans(m, &trans);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
447

faceef390   Heiner Kallweit   spi: fsl-espi: el...
448
  	m->actual_length = ret ? 0 : trans.len;
d3152cf1c   Heiner Kallweit   spi: fsl-espi: fa...
449
  out:
0319d4991   Heiner Kallweit   spi: fsl-espi: fi...
450
451
  	if (m->status == -EINPROGRESS)
  		m->status = ret;
c592becbe   Heiner Kallweit   spi: fsl-(e)spi: ...
452
  	spi_finalize_current_message(master);
0319d4991   Heiner Kallweit   spi: fsl-espi: fi...
453
454
  
  	return ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
455
456
457
458
  }
  
  static int fsl_espi_setup(struct spi_device *spi)
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
459
  	struct fsl_espi *espi;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
460
  	u32 loop_mode;
219b5e3b2   Heiner Kallweit   spi: fsl-espi: in...
461
  	struct fsl_espi_cs *cs = spi_get_ctldata(spi);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
462

8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
463
  	if (!cs) {
d9f267481   Axel Lin   spi: fsl: Don't u...
464
  		cs = kzalloc(sizeof(*cs), GFP_KERNEL);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
465
466
  		if (!cs)
  			return -ENOMEM;
d9f267481   Axel Lin   spi: fsl: Don't u...
467
  		spi_set_ctldata(spi, cs);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
468
  	}
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
469
  	espi = spi_master_get_devdata(spi->master);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
470

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
471
  	pm_runtime_get_sync(espi->dev);
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
472

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
473
  	cs->hw_mode = fsl_espi_read_reg(espi, ESPI_SPMODEx(spi->chip_select));
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
474
475
476
477
478
479
480
481
482
483
484
485
  	/* mask out bits we are going to set */
  	cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH
  			 | CSMODE_REV);
  
  	if (spi->mode & SPI_CPHA)
  		cs->hw_mode |= CSMODE_CP_BEGIN_EDGECLK;
  	if (spi->mode & SPI_CPOL)
  		cs->hw_mode |= CSMODE_CI_INACTIVEHIGH;
  	if (!(spi->mode & SPI_LSB_FIRST))
  		cs->hw_mode |= CSMODE_REV;
  
  	/* Handle the loop mode */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
486
  	loop_mode = fsl_espi_read_reg(espi, ESPI_SPMODE);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
487
488
489
  	loop_mode &= ~SPMODE_LOOP;
  	if (spi->mode & SPI_LOOP)
  		loop_mode |= SPMODE_LOOP;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
490
  	fsl_espi_write_reg(espi, ESPI_SPMODE, loop_mode);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
491

ea616ee22   Heiner Kallweit   spi: fsl-espi: ch...
492
  	fsl_espi_setup_transfer(spi, NULL);
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
493

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
494
495
  	pm_runtime_mark_last_busy(espi->dev);
  	pm_runtime_put_autosuspend(espi->dev);
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
496

8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
497
498
  	return 0;
  }
d9f267481   Axel Lin   spi: fsl: Don't u...
499
500
  static void fsl_espi_cleanup(struct spi_device *spi)
  {
219b5e3b2   Heiner Kallweit   spi: fsl-espi: in...
501
  	struct fsl_espi_cs *cs = spi_get_ctldata(spi);
d9f267481   Axel Lin   spi: fsl: Don't u...
502
503
504
505
  
  	kfree(cs);
  	spi_set_ctldata(spi, NULL);
  }
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
506
  static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
507
  {
dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
508
  	if (!espi->rx_done)
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
509
  		fsl_espi_read_rx_fifo(espi, events);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
510

058234328   Heiner Kallweit   spi: fsl-espi: el...
511
  	if (!espi->tx_done)
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
512
  		fsl_espi_fill_tx_fifo(espi, events);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
513

dcb425f3b   Heiner Kallweit   spi: fsl-espi: el...
514
  	if (!espi->tx_done || !espi->rx_done)
db1b049fa   Heiner Kallweit   spi: fsl-espi: ex...
515
516
517
  		return;
  
  	/* we're done, but check for errors before returning */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
518
  	events = fsl_espi_read_reg(espi, ESPI_SPIE);
db1b049fa   Heiner Kallweit   spi: fsl-espi: ex...
519
520
  
  	if (!(events & SPIE_DON))
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
521
  		dev_err(espi->dev,
db1b049fa   Heiner Kallweit   spi: fsl-espi: ex...
522
523
  			"Transfer done but SPIE_DON isn't set!
  ");
516ddd790   Tiago Brusamarello   spi: spi-fsl-espi...
524
  	if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE) {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
525
526
  		dev_err(espi->dev, "Transfer done but rx/tx fifo's aren't empty!
  ");
516ddd790   Tiago Brusamarello   spi: spi-fsl-espi...
527
528
529
530
  		dev_err(espi->dev, "SPIE_RXCNT = %d, SPIE_TXCNT = %d
  ",
  			SPIE_RXCNT(events), SPIE_TXCNT(events));
  	}
db1b049fa   Heiner Kallweit   spi: fsl-espi: ex...
531

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
532
  	complete(&espi->done);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
533
534
535
536
  }
  
  static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
  {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
537
  	struct fsl_espi *espi = context_data;
b867eef4c   Chris Packham   spi: fsl-espi: On...
538
  	u32 events, mask;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
539

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
540
  	spin_lock(&espi->lock);
547312659   Heiner Kallweit   spi: fsl-espi: fi...
541

8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
542
  	/* Get interrupt events(tx/rx) */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
543
  	events = fsl_espi_read_reg(espi, ESPI_SPIE);
b867eef4c   Chris Packham   spi: fsl-espi: On...
544
545
  	mask = fsl_espi_read_reg(espi, ESPI_SPIM);
  	if (!(events & mask)) {
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
546
  		spin_unlock(&espi->lock);
35f5d71e3   Heiner Kallweit   spi: fsl-espi: im...
547
  		return IRQ_NONE;
547312659   Heiner Kallweit   spi: fsl-espi: fi...
548
  	}
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
549

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
550
551
  	dev_vdbg(espi->dev, "%s: events %x
  ", __func__, events);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
552

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
553
  	fsl_espi_cpu_irq(espi, events);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
554

35f5d71e3   Heiner Kallweit   spi: fsl-espi: im...
555
  	/* Clear the events */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
556
  	fsl_espi_write_reg(espi, ESPI_SPIE, events);
35f5d71e3   Heiner Kallweit   spi: fsl-espi: im...
557

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
558
  	spin_unlock(&espi->lock);
547312659   Heiner Kallweit   spi: fsl-espi: fi...
559

35f5d71e3   Heiner Kallweit   spi: fsl-espi: im...
560
  	return IRQ_HANDLED;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
561
  }
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
562
563
  #ifdef CONFIG_PM
  static int fsl_espi_runtime_suspend(struct device *dev)
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
564
  {
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
565
  	struct spi_master *master = dev_get_drvdata(dev);
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
566
  	struct fsl_espi *espi = spi_master_get_devdata(master);
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
567
  	u32 regval;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
568
  	regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
569
  	regval &= ~SPMODE_ENABLE;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
570
  	fsl_espi_write_reg(espi, ESPI_SPMODE, regval);
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
571
572
573
  
  	return 0;
  }
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
574
  static int fsl_espi_runtime_resume(struct device *dev)
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
575
  {
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
576
  	struct spi_master *master = dev_get_drvdata(dev);
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
577
  	struct fsl_espi *espi = spi_master_get_devdata(master);
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
578
  	u32 regval;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
579
  	regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
580
  	regval |= SPMODE_ENABLE;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
581
  	fsl_espi_write_reg(espi, ESPI_SPMODE, regval);
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
582
583
584
  
  	return 0;
  }
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
585
  #endif
75506d0e0   Heiner Kallweit   spi: fsl-espi: ad...
586

02a595d5d   Heiner Kallweit   spi: fsl-espi: el...
587
  static size_t fsl_espi_max_message_size(struct spi_device *spi)
b541eef12   Michal Suchanek   spi: fsl-espi: ex...
588
589
590
  {
  	return SPCOM_TRANLEN_MAX;
  }
456c742be   Heiner Kallweit   spi: fsl-espi: fa...
591
592
593
  static void fsl_espi_init_regs(struct device *dev, bool initial)
  {
  	struct spi_master *master = dev_get_drvdata(dev);
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
594
  	struct fsl_espi *espi = spi_master_get_devdata(master);
456c742be   Heiner Kallweit   spi: fsl-espi: fa...
595
596
597
598
599
  	struct device_node *nc;
  	u32 csmode, cs, prop;
  	int ret;
  
  	/* SPI controller initializations */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
600
601
602
603
  	fsl_espi_write_reg(espi, ESPI_SPMODE, 0);
  	fsl_espi_write_reg(espi, ESPI_SPIM, 0);
  	fsl_espi_write_reg(espi, ESPI_SPCOM, 0);
  	fsl_espi_write_reg(espi, ESPI_SPIE, 0xffffffff);
456c742be   Heiner Kallweit   spi: fsl-espi: fa...
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  
  	/* Init eSPI CS mode register */
  	for_each_available_child_of_node(master->dev.of_node, nc) {
  		/* get chip select */
  		ret = of_property_read_u32(nc, "reg", &cs);
  		if (ret || cs >= master->num_chipselect)
  			continue;
  
  		csmode = CSMODE_INIT_VAL;
  
  		/* check if CSBEF is set in device tree */
  		ret = of_property_read_u32(nc, "fsl,csbef", &prop);
  		if (!ret) {
  			csmode &= ~(CSMODE_BEF(0xf));
  			csmode |= CSMODE_BEF(prop);
  		}
  
  		/* check if CSAFT is set in device tree */
  		ret = of_property_read_u32(nc, "fsl,csaft", &prop);
  		if (!ret) {
  			csmode &= ~(CSMODE_AFT(0xf));
  			csmode |= CSMODE_AFT(prop);
  		}
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
627
  		fsl_espi_write_reg(espi, ESPI_SPMODEx(cs), csmode);
456c742be   Heiner Kallweit   spi: fsl-espi: fa...
628
629
630
631
632
633
634
  
  		if (initial)
  			dev_info(dev, "cs=%u, init_csmode=0x%x
  ", cs, csmode);
  	}
  
  	/* Enable SPI interface */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
635
  	fsl_espi_write_reg(espi, ESPI_SPMODE, SPMODE_INIT_VAL | SPMODE_ENABLE);
456c742be   Heiner Kallweit   spi: fsl-espi: fa...
636
  }
604042af7   Heiner Kallweit   spi: fsl-espi: im...
637
  static int fsl_espi_probe(struct device *dev, struct resource *mem,
7454346b0   Heiner Kallweit   spi: fsl-espi: re...
638
  			  unsigned int irq, unsigned int num_cs)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
639
  {
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
640
  	struct spi_master *master;
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
641
  	struct fsl_espi *espi;
b497eb024   Heiner Kallweit   spi: fsl-espi: re...
642
  	int ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
643

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
644
  	master = spi_alloc_master(dev, sizeof(struct fsl_espi));
604042af7   Heiner Kallweit   spi: fsl-espi: im...
645
646
  	if (!master)
  		return -ENOMEM;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
647
648
  
  	dev_set_drvdata(dev, master);
7cb555772   Heiner Kallweit   spi: fsl-espi: mi...
649
650
651
  	master->mode_bits = SPI_RX_DUAL | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
  			    SPI_LSB_FIRST | SPI_LOOP;
  	master->dev.of_node = dev->of_node;
24778be20   Stephen Warren   spi: convert driv...
652
  	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
653
  	master->setup = fsl_espi_setup;
d9f267481   Axel Lin   spi: fsl: Don't u...
654
  	master->cleanup = fsl_espi_cleanup;
c592becbe   Heiner Kallweit   spi: fsl-(e)spi: ...
655
  	master->transfer_one_message = fsl_espi_do_one_msg;
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
656
  	master->auto_runtime_pm = true;
02a595d5d   Heiner Kallweit   spi: fsl-espi: el...
657
  	master->max_message_size = fsl_espi_max_message_size;
7454346b0   Heiner Kallweit   spi: fsl-espi: re...
658
  	master->num_chipselect = num_cs;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
659

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
660
661
  	espi = spi_master_get_devdata(master);
  	spin_lock_init(&espi->lock);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
662

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
663
664
665
  	espi->dev = dev;
  	espi->spibrg = fsl_get_sys_freq();
  	if (espi->spibrg == -1) {
7cb555772   Heiner Kallweit   spi: fsl-espi: mi...
666
667
668
669
670
  		dev_err(dev, "Can't get sys frequency!
  ");
  		ret = -EINVAL;
  		goto err_probe;
  	}
f254e65ce   Heiner Kallweit   spi: fsl-espi: se...
671
672
673
  	/* determined by clock divider fields DIV16/PM in register SPMODEx */
  	master->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16);
  	master->max_speed_hz = DIV_ROUND_UP(espi->spibrg, 4);
7cb555772   Heiner Kallweit   spi: fsl-espi: mi...
674

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
675
  	init_completion(&espi->done);
7cb555772   Heiner Kallweit   spi: fsl-espi: mi...
676

35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
677
678
679
  	espi->reg_base = devm_ioremap_resource(dev, mem);
  	if (IS_ERR(espi->reg_base)) {
  		ret = PTR_ERR(espi->reg_base);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
680
681
  		goto err_probe;
  	}
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
682
  	/* Register for SPI Interrupt */
35ab046b5   Heiner Kallweit   spi: fsl-espi: in...
683
  	ret = devm_request_irq(dev, irq, fsl_espi_irq, 0, "fsl_espi", espi);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
684
  	if (ret)
4178b6b1b   Heiner Kallweit   spi: fsl-(e)spi: ...
685
  		goto err_probe;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
686

456c742be   Heiner Kallweit   spi: fsl-espi: fa...
687
  	fsl_espi_init_regs(dev, true);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
688

e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
689
690
691
692
693
  	pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT);
  	pm_runtime_use_autosuspend(dev);
  	pm_runtime_set_active(dev);
  	pm_runtime_enable(dev);
  	pm_runtime_get_sync(dev);
4178b6b1b   Heiner Kallweit   spi: fsl-(e)spi: ...
694
  	ret = devm_spi_register_master(dev, master);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
695
  	if (ret < 0)
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
696
  		goto err_pm;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
697

b0e37c515   Chris Packham   spi: spi-fsl-espi...
698
699
  	dev_info(dev, "irq = %u
  ", irq);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
700

e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
701
702
  	pm_runtime_mark_last_busy(dev);
  	pm_runtime_put_autosuspend(dev);
604042af7   Heiner Kallweit   spi: fsl-espi: im...
703
  	return 0;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
704

e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
705
706
707
708
  err_pm:
  	pm_runtime_put_noidle(dev);
  	pm_runtime_disable(dev);
  	pm_runtime_set_suspended(dev);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
709
710
  err_probe:
  	spi_master_put(master);
604042af7   Heiner Kallweit   spi: fsl-espi: im...
711
  	return ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
712
713
714
715
716
  }
  
  static int of_fsl_espi_get_chipselects(struct device *dev)
  {
  	struct device_node *np = dev->of_node;
b497eb024   Heiner Kallweit   spi: fsl-espi: re...
717
718
  	u32 num_cs;
  	int ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
719

b497eb024   Heiner Kallweit   spi: fsl-espi: re...
720
721
  	ret = of_property_read_u32(np, "fsl,espi-num-chipselects", &num_cs);
  	if (ret) {
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
722
723
  		dev_err(dev, "No 'fsl,espi-num-chipselects' property
  ");
7454346b0   Heiner Kallweit   spi: fsl-espi: re...
724
  		return 0;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
725
  	}
7454346b0   Heiner Kallweit   spi: fsl-espi: re...
726
  	return num_cs;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
727
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
728
  static int of_fsl_espi_probe(struct platform_device *ofdev)
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
729
730
731
  {
  	struct device *dev = &ofdev->dev;
  	struct device_node *np = ofdev->dev.of_node;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
732
  	struct resource mem;
7454346b0   Heiner Kallweit   spi: fsl-espi: re...
733
  	unsigned int irq, num_cs;
acf692190   Heiner Kallweit   spi: fsl-espi: si...
734
  	int ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
735

e3ce4f44f   Heiner Kallweit   spi: fsl-espi: re...
736
737
738
739
740
  	if (of_property_read_bool(np, "mode")) {
  		dev_err(dev, "mode property is not supported on ESPI!
  ");
  		return -EINVAL;
  	}
7454346b0   Heiner Kallweit   spi: fsl-espi: re...
741
742
743
  	num_cs = of_fsl_espi_get_chipselects(dev);
  	if (!num_cs)
  		return -EINVAL;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
744
745
746
  
  	ret = of_address_to_resource(np, 0, &mem);
  	if (ret)
acf692190   Heiner Kallweit   spi: fsl-espi: si...
747
  		return ret;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
748

f7578496a   Thierry Reding   of/irq: Use irq_o...
749
  	irq = irq_of_parse_and_map(np, 0);
acf692190   Heiner Kallweit   spi: fsl-espi: si...
750
751
  	if (!irq)
  		return -EINVAL;
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
752

7454346b0   Heiner Kallweit   spi: fsl-espi: re...
753
  	return fsl_espi_probe(dev, &mem, irq, num_cs);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
754
  }
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
755
756
757
758
759
760
  static int of_fsl_espi_remove(struct platform_device *dev)
  {
  	pm_runtime_disable(&dev->dev);
  
  	return 0;
  }
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
761
762
763
764
  #ifdef CONFIG_PM_SLEEP
  static int of_fsl_espi_suspend(struct device *dev)
  {
  	struct spi_master *master = dev_get_drvdata(dev);
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
765
  	int ret;
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
766
  	ret = spi_master_suspend(master);
7c5d8a249   Geert Uytterhoeven   spi: Do not print...
767
  	if (ret)
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
768
  		return ret;
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
769

a9a813ddc   Heiner Kallweit   spi: fsl-espi: si...
770
  	return pm_runtime_force_suspend(dev);
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
771
772
773
774
  }
  
  static int of_fsl_espi_resume(struct device *dev)
  {
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
775
  	struct spi_master *master = dev_get_drvdata(dev);
456c742be   Heiner Kallweit   spi: fsl-espi: fa...
776
  	int ret;
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
777

456c742be   Heiner Kallweit   spi: fsl-espi: fa...
778
  	fsl_espi_init_regs(dev, false);
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
779

e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
780
781
782
  	ret = pm_runtime_force_resume(dev);
  	if (ret < 0)
  		return ret;
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
783
784
785
786
787
  	return spi_master_resume(master);
  }
  #endif /* CONFIG_PM_SLEEP */
  
  static const struct dev_pm_ops espi_pm = {
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
788
789
  	SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend,
  			   fsl_espi_runtime_resume, NULL)
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
790
791
  	SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume)
  };
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
792
793
794
795
796
  static const struct of_device_id of_fsl_espi_match[] = {
  	{ .compatible = "fsl,mpc8536-espi" },
  	{}
  };
  MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
18d306d13   Grant Likely   dt/spi: Eliminate...
797
  static struct platform_driver fsl_espi_driver = {
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
798
799
  	.driver = {
  		.name = "fsl_espi",
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
800
  		.of_match_table = of_fsl_espi_match,
714bb654e   Hou Zhiqiang   spi/fsl-espi: Add...
801
  		.pm = &espi_pm,
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
802
803
  	},
  	.probe		= of_fsl_espi_probe,
e9abb4db8   Heiner Kallweit   spi: fsl-espi: ad...
804
  	.remove		= of_fsl_espi_remove,
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
805
  };
940ab8896   Grant Likely   drivercore: Add h...
806
  module_platform_driver(fsl_espi_driver);
8b60d6c25   Mingkai Hu   spi/fsl_spi: add ...
807
808
809
810
  
  MODULE_AUTHOR("Mingkai Hu");
  MODULE_DESCRIPTION("Enhanced Freescale SPI Driver");
  MODULE_LICENSE("GPL");