Blame view

drivers/spi/spi-topcliff-pch.c 46.6 KB
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1
2
  /*
   * SPI bus driver for the Topcliff PCH used by Intel SoCs
65308c46b   Grant Likely   spi/topcliff: cle...
3
   *
2b2462832   Tomoya MORINAGA   spi-topcliff-pch:...
4
   * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; version 2 of the License.
   *
   * 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
   */
65308c46b   Grant Likely   spi/topcliff: cle...
19
  #include <linux/delay.h>
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
20
21
22
23
24
25
26
27
  #include <linux/pci.h>
  #include <linux/wait.h>
  #include <linux/spi/spi.h>
  #include <linux/interrupt.h>
  #include <linux/sched.h>
  #include <linux/spi/spidev.h>
  #include <linux/module.h>
  #include <linux/device.h>
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
28
  #include <linux/platform_device.h>
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
29

c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
30
31
  #include <linux/dmaengine.h>
  #include <linux/pch_dma.h>
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
32
33
34
35
36
37
38
39
  /* Register offsets */
  #define PCH_SPCR		0x00	/* SPI control register */
  #define PCH_SPBRR		0x04	/* SPI baud rate register */
  #define PCH_SPSR		0x08	/* SPI status register */
  #define PCH_SPDWR		0x0C	/* SPI write data register */
  #define PCH_SPDRR		0x10	/* SPI read data register */
  #define PCH_SSNXCR		0x18	/* SSN Expand Control Register */
  #define PCH_SRST		0x1C	/* SPI reset register */
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
40
  #define PCH_ADDRESS_SIZE	0x20
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
41
42
43
44
45
46
47
48
49
  
  #define PCH_SPSR_TFD		0x000007C0
  #define PCH_SPSR_RFD		0x0000F800
  
  #define PCH_READABLE(x)		(((x) & PCH_SPSR_RFD)>>11)
  #define PCH_WRITABLE(x)		(((x) & PCH_SPSR_TFD)>>6)
  
  #define PCH_RX_THOLD		7
  #define PCH_RX_THOLD_MAX	15
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
50

f3e03e2eb   Tomoya MORINAGA   spi-topcliff-pch:...
51
  #define PCH_TX_THOLD		2
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
52
53
54
55
56
57
  #define PCH_MAX_BAUDRATE	5000000
  #define PCH_MAX_FIFO_DEPTH	16
  
  #define STATUS_RUNNING		1
  #define STATUS_EXITING		2
  #define PCH_SLEEP_TIME		10
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
58
  #define SSN_LOW			0x02U
8b7aa961a   Tomoya MORINAGA   spi-topcliff-pch:...
59
  #define SSN_HIGH		0x03U
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  #define SSN_NO_CONTROL		0x00U
  #define PCH_MAX_CS		0xFF
  #define PCI_DEVICE_ID_GE_SPI	0x8816
  
  #define SPCR_SPE_BIT		(1 << 0)
  #define SPCR_MSTR_BIT		(1 << 1)
  #define SPCR_LSBF_BIT		(1 << 4)
  #define SPCR_CPHA_BIT		(1 << 5)
  #define SPCR_CPOL_BIT		(1 << 6)
  #define SPCR_TFIE_BIT		(1 << 8)
  #define SPCR_RFIE_BIT		(1 << 9)
  #define SPCR_FIE_BIT		(1 << 10)
  #define SPCR_ORIE_BIT		(1 << 11)
  #define SPCR_MDFIE_BIT		(1 << 12)
  #define SPCR_FICLR_BIT		(1 << 24)
  #define SPSR_TFI_BIT		(1 << 0)
  #define SPSR_RFI_BIT		(1 << 1)
  #define SPSR_FI_BIT		(1 << 2)
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
78
  #define SPSR_ORF_BIT		(1 << 3)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
79
  #define SPBRR_SIZE_BIT		(1 << 10)
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
80
81
  #define PCH_ALL			(SPCR_TFIE_BIT|SPCR_RFIE_BIT|SPCR_FIE_BIT|\
  				SPCR_ORIE_BIT|SPCR_MDFIE_BIT)
65308c46b   Grant Likely   spi/topcliff: cle...
82

e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
83
84
  #define SPCR_RFIC_FIELD		20
  #define SPCR_TFIC_FIELD		16
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
85
86
87
  #define MASK_SPBRR_SPBR_BITS	((1 << 10) - 1)
  #define MASK_RFIC_SPCR_BITS	(0xf << SPCR_RFIC_FIELD)
  #define MASK_TFIC_SPCR_BITS	(0xf << SPCR_TFIC_FIELD)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
88
89
90
  
  #define PCH_CLOCK_HZ		50000000
  #define PCH_MAX_SPBR		1023
2b2462832   Tomoya MORINAGA   spi-topcliff-pch:...
91
  /* Definition for ML7213/ML7223/ML7831 by LAPIS Semiconductor */
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
92
93
  #define PCI_VENDOR_ID_ROHM		0x10DB
  #define PCI_DEVICE_ID_ML7213_SPI	0x802c
2e2de2e31   Tomoya MORINAGA   spi/topcliff-pch:...
94
  #define PCI_DEVICE_ID_ML7223_SPI	0x800F
92b3a5c1b   Tomoya MORINAGA   spi-topcliff-pch:...
95
  #define PCI_DEVICE_ID_ML7831_SPI	0x8816
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
96
97
98
99
  
  /*
   * Set the number of SPI instance max
   * Intel EG20T PCH :		1ch
2b2462832   Tomoya MORINAGA   spi-topcliff-pch:...
100
101
102
   * LAPIS Semiconductor ML7213 IOH :	2ch
   * LAPIS Semiconductor ML7223 IOH :	1ch
   * LAPIS Semiconductor ML7831 IOH :	1ch
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
103
104
  */
  #define PCH_SPI_MAX_DEV			2
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
105

c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  #define PCH_BUF_SIZE		4096
  #define PCH_DMA_TRANS_SIZE	12
  
  static int use_dma = 1;
  
  struct pch_spi_dma_ctrl {
  	struct dma_async_tx_descriptor	*desc_tx;
  	struct dma_async_tx_descriptor	*desc_rx;
  	struct pch_dma_slave		param_tx;
  	struct pch_dma_slave		param_rx;
  	struct dma_chan		*chan_tx;
  	struct dma_chan		*chan_rx;
  	struct scatterlist		*sg_tx_p;
  	struct scatterlist		*sg_rx_p;
  	struct scatterlist		sg_tx;
  	struct scatterlist		sg_rx;
  	int				nent;
  	void				*tx_buf_virt;
  	void				*rx_buf_virt;
  	dma_addr_t			tx_buf_dma;
  	dma_addr_t			rx_buf_dma;
  };
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  /**
   * struct pch_spi_data - Holds the SPI channel specific details
   * @io_remap_addr:		The remapped PCI base address
   * @master:			Pointer to the SPI master structure
   * @work:			Reference to work queue handler
   * @wk:				Workqueue for carrying out execution of the
   *				requests
   * @wait:			Wait queue for waking up upon receiving an
   *				interrupt.
   * @transfer_complete:		Status of SPI Transfer
   * @bcurrent_msg_processing:	Status flag for message processing
   * @lock:			Lock for protecting this structure
   * @queue:			SPI Message queue
   * @status:			Status of the SPI driver
   * @bpw_len:			Length of data to be transferred in bits per
   *				word
   * @transfer_active:		Flag showing active transfer
   * @tx_index:			Transmit data count; for bookkeeping during
   *				transfer
   * @rx_index:			Receive data count; for bookkeeping during
   *				transfer
   * @tx_buff:			Buffer for data to be transmitted
   * @rx_index:			Buffer for Received data
   * @n_curnt_chip:		The chip number that this SPI driver currently
   *				operates on
   * @current_chip:		Reference to the current chip that this SPI
   *				driver currently operates on
   * @current_msg:		The current message that this SPI driver is
   *				handling
   * @cur_trans:			The current transfer that this SPI driver is
   *				handling
   * @board_dat:			Reference to the SPI device data structure
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
160
161
162
   * @plat_dev:			platform_device structure
   * @ch:				SPI channel number
   * @irq_reg_sts:		Status of IRQ registration
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
163
164
165
   */
  struct pch_spi_data {
  	void __iomem *io_remap_addr;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
166
  	unsigned long io_base_addr;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  	struct spi_master *master;
  	struct work_struct work;
  	struct workqueue_struct *wk;
  	wait_queue_head_t wait;
  	u8 transfer_complete;
  	u8 bcurrent_msg_processing;
  	spinlock_t lock;
  	struct list_head queue;
  	u8 status;
  	u32 bpw_len;
  	u8 transfer_active;
  	u32 tx_index;
  	u32 rx_index;
  	u16 *pkt_tx_buff;
  	u16 *pkt_rx_buff;
  	u8 n_curnt_chip;
  	struct spi_device *current_chip;
  	struct spi_message *current_msg;
  	struct spi_transfer *cur_trans;
  	struct pch_spi_board_data *board_dat;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
187
188
  	struct platform_device	*plat_dev;
  	int ch;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
189
190
  	struct pch_spi_dma_ctrl dma;
  	int use_dma;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
191
  	u8 irq_reg_sts;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
192
193
194
195
196
  };
  
  /**
   * struct pch_spi_board_data - Holds the SPI device specific details
   * @pdev:		Pointer to the PCI device
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
197
   * @suspend_sts:	Status of suspend
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
198
   * @num:		The number of SPI device instance
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
199
200
201
   */
  struct pch_spi_board_data {
  	struct pci_dev *pdev;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
202
  	u8 suspend_sts;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
203
204
205
206
207
208
209
  	int num;
  };
  
  struct pch_pd_dev_save {
  	int num;
  	struct platform_device *pd_save[PCH_SPI_MAX_DEV];
  	struct pch_spi_board_data *board_dat;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
210
211
212
  };
  
  static struct pci_device_id pch_spi_pcidev_id[] = {
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
213
214
  	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI),    1, },
  	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, },
2e2de2e31   Tomoya MORINAGA   spi/topcliff-pch:...
215
  	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), 1, },
92b3a5c1b   Tomoya MORINAGA   spi-topcliff-pch:...
216
  	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_SPI), 1, },
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
217
  	{ }
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
218
  };
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
219
220
221
222
223
224
225
226
  /**
   * pch_spi_writereg() - Performs  register writes
   * @master:	Pointer to struct spi_master.
   * @idx:	Register offset.
   * @val:	Value to be written to register.
   */
  static inline void pch_spi_writereg(struct spi_master *master, int idx, u32 val)
  {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
227
  	struct pch_spi_data *data = spi_master_get_devdata(master);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
228
229
230
231
232
233
234
235
236
237
238
  	iowrite32(val, (data->io_remap_addr + idx));
  }
  
  /**
   * pch_spi_readreg() - Performs register reads
   * @master:	Pointer to struct spi_master.
   * @idx:	Register offset.
   */
  static inline u32 pch_spi_readreg(struct spi_master *master, int idx)
  {
  	struct pch_spi_data *data = spi_master_get_devdata(master);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
239
240
  	return ioread32(data->io_remap_addr + idx);
  }
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
241
242
243
244
245
246
247
  static inline void pch_spi_setclr_reg(struct spi_master *master, int idx,
  				      u32 set, u32 clr)
  {
  	u32 tmp = pch_spi_readreg(master, idx);
  	tmp = (tmp & ~clr) | set;
  	pch_spi_writereg(master, idx, tmp);
  }
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  static void pch_spi_set_master_mode(struct spi_master *master)
  {
  	pch_spi_setclr_reg(master, PCH_SPCR, SPCR_MSTR_BIT, 0);
  }
  
  /**
   * pch_spi_clear_fifo() - Clears the Transmit and Receive FIFOs
   * @master:	Pointer to struct spi_master.
   */
  static void pch_spi_clear_fifo(struct spi_master *master)
  {
  	pch_spi_setclr_reg(master, PCH_SPCR, SPCR_FICLR_BIT, 0);
  	pch_spi_setclr_reg(master, PCH_SPCR, 0, SPCR_FICLR_BIT);
  }
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
  				void __iomem *io_remap_addr)
  {
  	u32 n_read, tx_index, rx_index, bpw_len;
  	u16 *pkt_rx_buffer, *pkt_tx_buff;
  	int read_cnt;
  	u32 reg_spcr_val;
  	void __iomem *spsr;
  	void __iomem *spdrr;
  	void __iomem *spdwr;
  
  	spsr = io_remap_addr + PCH_SPSR;
  	iowrite32(reg_spsr_val, spsr);
  
  	if (data->transfer_active) {
  		rx_index = data->rx_index;
  		tx_index = data->tx_index;
  		bpw_len = data->bpw_len;
  		pkt_rx_buffer = data->pkt_rx_buff;
  		pkt_tx_buff = data->pkt_tx_buff;
  
  		spdrr = io_remap_addr + PCH_SPDRR;
  		spdwr = io_remap_addr + PCH_SPDWR;
  
  		n_read = PCH_READABLE(reg_spsr_val);
  
  		for (read_cnt = 0; (read_cnt < n_read); read_cnt++) {
  			pkt_rx_buffer[rx_index++] = ioread32(spdrr);
  			if (tx_index < bpw_len)
  				iowrite32(pkt_tx_buff[tx_index++], spdwr);
  		}
  
  		/* disable RFI if not needed */
  		if ((bpw_len - rx_index) <= PCH_MAX_FIFO_DEPTH) {
  			reg_spcr_val = ioread32(io_remap_addr + PCH_SPCR);
65308c46b   Grant Likely   spi/topcliff: cle...
297
  			reg_spcr_val &= ~SPCR_RFIE_BIT; /* disable RFI */
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
298
299
  
  			/* reset rx threshold */
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
300
  			reg_spcr_val &= ~MASK_RFIC_SPCR_BITS;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
301
  			reg_spcr_val |= (PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
302
303
  
  			iowrite32(reg_spcr_val, (io_remap_addr + PCH_SPCR));
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
304
305
306
307
308
309
310
311
312
313
  		}
  
  		/* update counts */
  		data->tx_index = tx_index;
  		data->rx_index = rx_index;
  
  	}
  
  	/* if transfer complete interrupt */
  	if (reg_spsr_val & SPSR_FI_BIT) {
373b0eb64   Tomoya MORINAGA   spi-topcliff-pch:...
314
315
316
317
318
319
320
321
322
323
  		if ((tx_index == bpw_len) && (rx_index == tx_index)) {
  			/* disable interrupts */
  			pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
  
  			/* transfer is completed;
  			   inform pch_spi_process_messages */
  			data->transfer_complete = true;
  			data->transfer_active = false;
  			wake_up(&data->wait);
  		} else {
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
324
325
  			dev_err(&data->master->dev,
  				"%s : Transfer is not completed", __func__);
373b0eb64   Tomoya MORINAGA   spi-topcliff-pch:...
326
  		}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
327
328
  	}
  }
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
329
330
331
332
333
334
335
336
  /**
   * pch_spi_handler() - Interrupt handler
   * @irq:	The interrupt number.
   * @dev_id:	Pointer to struct pch_spi_board_data.
   */
  static irqreturn_t pch_spi_handler(int irq, void *dev_id)
  {
  	u32 reg_spsr_val;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
337
338
339
  	void __iomem *spsr;
  	void __iomem *io_remap_addr;
  	irqreturn_t ret = IRQ_NONE;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
340
341
  	struct pch_spi_data *data = dev_id;
  	struct pch_spi_board_data *board_dat = data->board_dat;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
342
343
344
345
346
347
348
  
  	if (board_dat->suspend_sts) {
  		dev_dbg(&board_dat->pdev->dev,
  			"%s returning due to suspend
  ", __func__);
  		return IRQ_NONE;
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
349
350
351
352
  	io_remap_addr = data->io_remap_addr;
  	spsr = io_remap_addr + PCH_SPSR;
  
  	reg_spsr_val = ioread32(spsr);
25e803f9c   Tomoya MORINAGA   spi-topcliff-pch:...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  	if (reg_spsr_val & SPSR_ORF_BIT) {
  		dev_err(&board_dat->pdev->dev, "%s Over run error
  ", __func__);
  		if (data->current_msg->complete != 0) {
  			data->transfer_complete = true;
  			data->current_msg->status = -EIO;
  			data->current_msg->complete(data->current_msg->context);
  			data->bcurrent_msg_processing = false;
  			data->current_msg = NULL;
  			data->cur_trans = NULL;
  		}
  	}
  
  	if (data->use_dma)
  		return IRQ_NONE;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
368

e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
369
  	/* Check if the interrupt is for SPI device */
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  	if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) {
  		pch_spi_handler_sub(data, reg_spsr_val, io_remap_addr);
  		ret = IRQ_HANDLED;
  	}
  
  	dev_dbg(&board_dat->pdev->dev, "%s EXIT return value=%d
  ",
  		__func__, ret);
  
  	return ret;
  }
  
  /**
   * pch_spi_set_baud_rate() - Sets SPBR field in SPBRR
   * @master:	Pointer to struct spi_master.
   * @speed_hz:	Baud rate.
   */
  static void pch_spi_set_baud_rate(struct spi_master *master, u32 speed_hz)
  {
65308c46b   Grant Likely   spi/topcliff: cle...
389
  	u32 n_spbr = PCH_CLOCK_HZ / (speed_hz * 2);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
390
391
  
  	/* if baud rate is less than we can support limit it */
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
392
393
  	if (n_spbr > PCH_MAX_SPBR)
  		n_spbr = PCH_MAX_SPBR;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
394
  	pch_spi_setclr_reg(master, PCH_SPBRR, n_spbr, MASK_SPBRR_SPBR_BITS);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  }
  
  /**
   * pch_spi_set_bits_per_word() - Sets SIZE field in SPBRR
   * @master:		Pointer to struct spi_master.
   * @bits_per_word:	Bits per word for SPI transfer.
   */
  static void pch_spi_set_bits_per_word(struct spi_master *master,
  				      u8 bits_per_word)
  {
  	if (bits_per_word == 8)
  		pch_spi_setclr_reg(master, PCH_SPBRR, 0, SPBRR_SIZE_BIT);
  	else
  		pch_spi_setclr_reg(master, PCH_SPBRR, SPBRR_SIZE_BIT, 0);
  }
  
  /**
   * pch_spi_setup_transfer() - Configures the PCH SPI hardware for transfer
   * @spi:	Pointer to struct spi_device.
   */
  static void pch_spi_setup_transfer(struct spi_device *spi)
  {
65308c46b   Grant Likely   spi/topcliff: cle...
417
  	u32 flags = 0;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
418
419
420
421
422
  
  	dev_dbg(&spi->dev, "%s SPBRR content =%x setting baud rate=%d
  ",
  		__func__, pch_spi_readreg(spi->master, PCH_SPBRR),
  		spi->max_speed_hz);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
423
424
425
426
  	pch_spi_set_baud_rate(spi->master, spi->max_speed_hz);
  
  	/* set bits per word */
  	pch_spi_set_bits_per_word(spi->master, spi->bits_per_word);
65308c46b   Grant Likely   spi/topcliff: cle...
427
428
  	if (!(spi->mode & SPI_LSB_FIRST))
  		flags |= SPCR_LSBF_BIT;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
429
  	if (spi->mode & SPI_CPOL)
65308c46b   Grant Likely   spi/topcliff: cle...
430
  		flags |= SPCR_CPOL_BIT;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
431
  	if (spi->mode & SPI_CPHA)
65308c46b   Grant Likely   spi/topcliff: cle...
432
433
434
  		flags |= SPCR_CPHA_BIT;
  	pch_spi_setclr_reg(spi->master, PCH_SPCR, flags,
  			   (SPCR_LSBF_BIT | SPCR_CPOL_BIT | SPCR_CPHA_BIT));
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
435
436
437
438
439
440
  
  	/* Clear the FIFO by toggling  FICLR to 1 and back to 0 */
  	pch_spi_clear_fifo(spi->master);
  }
  
  /**
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
   * pch_spi_reset() - Clears SPI registers
   * @master:	Pointer to struct spi_master.
   */
  static void pch_spi_reset(struct spi_master *master)
  {
  	/* write 1 to reset SPI */
  	pch_spi_writereg(master, PCH_SRST, 0x1);
  
  	/* clear reset */
  	pch_spi_writereg(master, PCH_SRST, 0x0);
  }
  
  static int pch_spi_setup(struct spi_device *pspi)
  {
  	/* check bits per word */
65308c46b   Grant Likely   spi/topcliff: cle...
456
  	if (pspi->bits_per_word == 0) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
457
458
459
460
  		pspi->bits_per_word = 8;
  		dev_dbg(&pspi->dev, "%s 8 bits per word
  ", __func__);
  	}
65308c46b   Grant Likely   spi/topcliff: cle...
461
  	if ((pspi->bits_per_word != 8) && (pspi->bits_per_word != 16)) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
462
463
464
465
466
467
468
469
470
471
472
473
474
  		dev_err(&pspi->dev, "%s Invalid bits per word
  ", __func__);
  		return -EINVAL;
  	}
  
  	/* Check baud rate setting */
  	/* if baud rate of chip is greater than
  	   max we can support,return error */
  	if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
  		pspi->max_speed_hz = PCH_MAX_BAUDRATE;
  
  	dev_dbg(&pspi->dev, "%s MODE = %x
  ", __func__,
65308c46b   Grant Likely   spi/topcliff: cle...
475
  		(pspi->mode) & (SPI_CPOL | SPI_CPHA));
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
476
477
478
479
480
481
482
483
484
485
486
487
488
  
  	return 0;
  }
  
  static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
  {
  
  	struct spi_transfer *transfer;
  	struct pch_spi_data *data = spi_master_get_devdata(pspi->master);
  	int retval;
  	unsigned long flags;
  
  	/* validate spi message and baud rate */
65308c46b   Grant Likely   spi/topcliff: cle...
489
490
491
492
493
494
  	if (unlikely(list_empty(&pmsg->transfers) == 1)) {
  		dev_err(&pspi->dev, "%s list empty
  ", __func__);
  		retval = -EINVAL;
  		goto err_out;
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
495

65308c46b   Grant Likely   spi/topcliff: cle...
496
497
498
499
  	if (unlikely(pspi->max_speed_hz == 0)) {
  		dev_err(&pspi->dev, "%s pch_spi_tranfer maxspeed=%d
  ",
  			__func__, pspi->max_speed_hz);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
500
501
502
503
504
505
506
  		retval = -EINVAL;
  		goto err_out;
  	}
  
  	dev_dbg(&pspi->dev, "%s Transfer List not empty. "
  		"Transfer Speed is set.
  ", __func__);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
507
  	spin_lock_irqsave(&data->lock, flags);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
508
509
  	/* validate Tx/Rx buffers and Transfer length */
  	list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
65308c46b   Grant Likely   spi/topcliff: cle...
510
  		if (!transfer->tx_buf && !transfer->rx_buf) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
511
512
513
514
  			dev_err(&pspi->dev,
  				"%s Tx and Rx buffer NULL
  ", __func__);
  			retval = -EINVAL;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
515
  			goto err_return_spinlock;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
516
  		}
65308c46b   Grant Likely   spi/topcliff: cle...
517
  		if (!transfer->len) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
518
519
520
521
  			dev_err(&pspi->dev, "%s Transfer length invalid
  ",
  				__func__);
  			retval = -EINVAL;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
522
  			goto err_return_spinlock;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
523
524
525
526
527
  		}
  
  		dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length"
  			" valid
  ", __func__);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
528
  		/* if baud rate has been specified validate the same */
65308c46b   Grant Likely   spi/topcliff: cle...
529
530
  		if (transfer->speed_hz > PCH_MAX_BAUDRATE)
  			transfer->speed_hz = PCH_MAX_BAUDRATE;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
531
532
533
534
535
536
537
538
539
  
  		/* if bits per word has been specified validate the same */
  		if (transfer->bits_per_word) {
  			if ((transfer->bits_per_word != 8)
  			    && (transfer->bits_per_word != 16)) {
  				retval = -EINVAL;
  				dev_err(&pspi->dev,
  					"%s Invalid bits per word
  ", __func__);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
540
  				goto err_return_spinlock;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
541
542
543
  			}
  		}
  	}
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
544
  	spin_unlock_irqrestore(&data->lock, flags);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
545

65308c46b   Grant Likely   spi/topcliff: cle...
546
547
  	/* We won't process any messages if we have been asked to terminate */
  	if (data->status == STATUS_EXITING) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
548
549
550
  		dev_err(&pspi->dev, "%s status = STATUS_EXITING.
  ", __func__);
  		retval = -ESHUTDOWN;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
551
  		goto err_out;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
552
553
554
555
  	}
  
  	/* If suspended ,return -EINVAL */
  	if (data->board_dat->suspend_sts) {
65308c46b   Grant Likely   spi/topcliff: cle...
556
557
  		dev_err(&pspi->dev, "%s suspend; returning EINVAL
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
558
  		retval = -EINVAL;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
559
  		goto err_out;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
560
561
562
563
  	}
  
  	/* set status of message */
  	pmsg->actual_length = 0;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
564
565
566
567
  	dev_dbg(&pspi->dev, "%s - pmsg->status =%d
  ", __func__, pmsg->status);
  
  	pmsg->status = -EINPROGRESS;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
568
  	spin_lock_irqsave(&data->lock, flags);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
569
570
  	/* add message to queue */
  	list_add_tail(&pmsg->queue, &data->queue);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
571
  	spin_unlock_irqrestore(&data->lock, flags);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
572
573
574
575
576
  	dev_dbg(&pspi->dev, "%s - Invoked list_add_tail
  ", __func__);
  
  	/* schedule work queue to run */
  	queue_work(data->wk, &data->work);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
577
578
579
580
  	dev_dbg(&pspi->dev, "%s - Invoked queue work
  ", __func__);
  
  	retval = 0;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
581
582
583
584
  err_out:
  	dev_dbg(&pspi->dev, "%s RETURN=%d
  ", __func__, retval);
  	return retval;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
585
586
587
588
589
  err_return_spinlock:
  	dev_dbg(&pspi->dev, "%s RETURN=%d
  ", __func__, retval);
  	spin_unlock_irqrestore(&data->lock, flags);
  	return retval;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
590
591
592
593
594
  }
  
  static inline void pch_spi_select_chip(struct pch_spi_data *data,
  				       struct spi_device *pspi)
  {
65308c46b   Grant Likely   spi/topcliff: cle...
595
596
597
598
  	if (data->current_chip != NULL) {
  		if (pspi->chip_select != data->n_curnt_chip) {
  			dev_dbg(&pspi->dev, "%s : different slave
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
599
600
601
602
603
604
605
606
607
608
609
610
  			data->current_chip = NULL;
  		}
  	}
  
  	data->current_chip = pspi;
  
  	data->n_curnt_chip = data->current_chip->chip_select;
  
  	dev_dbg(&pspi->dev, "%s :Invoking pch_spi_setup_transfer
  ", __func__);
  	pch_spi_setup_transfer(pspi);
  }
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
611
  static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
612
  {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
613
614
615
616
617
618
  	int size;
  	u32 n_writes;
  	int j;
  	struct spi_message *pmsg;
  	const u8 *tx_buf;
  	const u16 *tx_sbuf;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
619
620
  	/* set baud rate if needed */
  	if (data->cur_trans->speed_hz) {
65308c46b   Grant Likely   spi/topcliff: cle...
621
622
623
  		dev_dbg(&data->master->dev, "%s:setting baud rate
  ", __func__);
  		pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
624
625
626
  	}
  
  	/* set bits per word if needed */
65308c46b   Grant Likely   spi/topcliff: cle...
627
628
629
630
  	if (data->cur_trans->bits_per_word &&
  	    (data->current_msg->spi->bits_per_word != data->cur_trans->bits_per_word)) {
  		dev_dbg(&data->master->dev, "%s:set bits per word
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
631
  		pch_spi_set_bits_per_word(data->master,
65308c46b   Grant Likely   spi/topcliff: cle...
632
  					  data->cur_trans->bits_per_word);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
633
634
635
636
637
638
639
640
641
642
  		*bpw = data->cur_trans->bits_per_word;
  	} else {
  		*bpw = data->current_msg->spi->bits_per_word;
  	}
  
  	/* reset Tx/Rx index */
  	data->tx_index = 0;
  	data->rx_index = 0;
  
  	data->bpw_len = data->cur_trans->len / (*bpw / 8);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
643
644
  
  	/* find alloc size */
65308c46b   Grant Likely   spi/topcliff: cle...
645
  	size = data->cur_trans->len * sizeof(*data->pkt_tx_buff);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
646
647
  	/* allocate memory for pkt_tx_buff & pkt_rx_buffer */
  	data->pkt_tx_buff = kzalloc(size, GFP_KERNEL);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
648
649
  	if (data->pkt_tx_buff != NULL) {
  		data->pkt_rx_buff = kzalloc(size, GFP_KERNEL);
65308c46b   Grant Likely   spi/topcliff: cle...
650
  		if (!data->pkt_rx_buff)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
651
  			kfree(data->pkt_tx_buff);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
652
  	}
65308c46b   Grant Likely   spi/topcliff: cle...
653
  	if (!data->pkt_rx_buff) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
654
  		/* flush queue and set status of all transfers to -ENOMEM */
65308c46b   Grant Likely   spi/topcliff: cle...
655
656
  		dev_err(&data->master->dev, "%s :kzalloc failed
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
657
658
659
660
661
662
663
664
665
  		list_for_each_entry(pmsg, data->queue.next, queue) {
  			pmsg->status = -ENOMEM;
  
  			if (pmsg->complete != 0)
  				pmsg->complete(pmsg->context);
  
  			/* delete from queue */
  			list_del_init(&pmsg->queue);
  		}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
666
667
668
669
  		return;
  	}
  
  	/* copy Tx Data */
65308c46b   Grant Likely   spi/topcliff: cle...
670
  	if (data->cur_trans->tx_buf != NULL) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
671
  		if (*bpw == 8) {
65308c46b   Grant Likely   spi/topcliff: cle...
672
673
674
  			tx_buf = data->cur_trans->tx_buf;
  			for (j = 0; j < data->bpw_len; j++)
  				data->pkt_tx_buff[j] = *tx_buf++;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
675
  		} else {
65308c46b   Grant Likely   spi/topcliff: cle...
676
677
678
  			tx_sbuf = data->cur_trans->tx_buf;
  			for (j = 0; j < data->bpw_len; j++)
  				data->pkt_tx_buff[j] = *tx_sbuf++;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
679
680
681
682
  		}
  	}
  
  	/* if len greater than PCH_MAX_FIFO_DEPTH, write 16,else len bytes */
65308c46b   Grant Likely   spi/topcliff: cle...
683
684
  	n_writes = data->bpw_len;
  	if (n_writes > PCH_MAX_FIFO_DEPTH)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
685
  		n_writes = PCH_MAX_FIFO_DEPTH;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
686

65308c46b   Grant Likely   spi/topcliff: cle...
687
688
  	dev_dbg(&data->master->dev, "
  %s:Pulling down SSN low - writing "
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
689
690
691
  		"0x2 to SSNXCR
  ", __func__);
  	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
65308c46b   Grant Likely   spi/topcliff: cle...
692
693
  	for (j = 0; j < n_writes; j++)
  		pch_spi_writereg(data->master, PCH_SPDWR, data->pkt_tx_buff[j]);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
694
695
696
697
698
699
700
701
  
  	/* update tx_index */
  	data->tx_index = j;
  
  	/* reset transfer complete flag */
  	data->transfer_complete = false;
  	data->transfer_active = true;
  }
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
702
  static void pch_spi_nomore_transfer(struct pch_spi_data *data)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
703
  {
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
704
  	struct spi_message *pmsg;
65308c46b   Grant Likely   spi/topcliff: cle...
705
706
  	dev_dbg(&data->master->dev, "%s called
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
707
  	/* Invoke complete callback
65308c46b   Grant Likely   spi/topcliff: cle...
708
  	 * [To the spi core..indicating end of transfer] */
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
709
  	data->current_msg->status = 0;
65308c46b   Grant Likely   spi/topcliff: cle...
710
  	if (data->current_msg->complete != 0) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  		dev_dbg(&data->master->dev,
  			"%s:Invoking callback of SPI core
  ", __func__);
  		data->current_msg->complete(data->current_msg->context);
  	}
  
  	/* update status in global variable */
  	data->bcurrent_msg_processing = false;
  
  	dev_dbg(&data->master->dev,
  		"%s:data->bcurrent_msg_processing = false
  ", __func__);
  
  	data->current_msg = NULL;
  	data->cur_trans = NULL;
65308c46b   Grant Likely   spi/topcliff: cle...
726
727
  	/* check if we have items in list and not suspending
  	 * return 1 if list empty */
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
728
  	if ((list_empty(&data->queue) == 0) &&
65308c46b   Grant Likely   spi/topcliff: cle...
729
730
  	    (!data->board_dat->suspend_sts) &&
  	    (data->status != STATUS_EXITING)) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
731
  		/* We have some more work to do (either there is more tranint
65308c46b   Grant Likely   spi/topcliff: cle...
732
733
734
735
736
  		 * bpw;sfer requests in the current message or there are
  		 *more messages)
  		 */
  		dev_dbg(&data->master->dev, "%s:Invoke queue_work
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
737
  		queue_work(data->wk, &data->work);
65308c46b   Grant Likely   spi/topcliff: cle...
738
739
  	} else if (data->board_dat->suspend_sts ||
  		   data->status == STATUS_EXITING) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
740
741
742
743
744
745
  		dev_dbg(&data->master->dev,
  			"%s suspend/remove initiated, flushing queue
  ",
  			__func__);
  		list_for_each_entry(pmsg, data->queue.next, queue) {
  			pmsg->status = -EIO;
65308c46b   Grant Likely   spi/topcliff: cle...
746
  			if (pmsg->complete)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
747
748
749
750
751
752
753
754
755
756
  				pmsg->complete(pmsg->context);
  
  			/* delete from queue */
  			list_del_init(&pmsg->queue);
  		}
  	}
  }
  
  static void pch_spi_set_ir(struct pch_spi_data *data)
  {
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
757
758
  	/* enable interrupts, set threshold, enable SPI */
  	if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH)
77e58efd1   Justin P. Mattock   spi/topcliff: Typ...
759
  		/* set receive threshold to PCH_RX_THOLD */
65308c46b   Grant Likely   spi/topcliff: cle...
760
  		pch_spi_setclr_reg(data->master, PCH_SPCR,
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
761
762
763
764
765
  				   PCH_RX_THOLD << SPCR_RFIC_FIELD |
  				   SPCR_FIE_BIT | SPCR_RFIE_BIT |
  				   SPCR_ORIE_BIT | SPCR_SPE_BIT,
  				   MASK_RFIC_SPCR_BITS | PCH_ALL);
  	else
77e58efd1   Justin P. Mattock   spi/topcliff: Typ...
766
  		/* set receive threshold to maximum */
65308c46b   Grant Likely   spi/topcliff: cle...
767
  		pch_spi_setclr_reg(data->master, PCH_SPCR,
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
768
769
770
771
  				   PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD |
  				   SPCR_FIE_BIT | SPCR_ORIE_BIT |
  				   SPCR_SPE_BIT,
  				   MASK_RFIC_SPCR_BITS | PCH_ALL);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
772
773
774
775
776
777
778
779
  
  	/* Wait until the transfer completes; go to sleep after
  				 initiating the transfer. */
  	dev_dbg(&data->master->dev,
  		"%s:waiting for transfer to get over
  ", __func__);
  
  	wait_event_interruptible(data->wait, data->transfer_complete);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
780
781
  	/* clear all interrupts */
  	pch_spi_writereg(data->master, PCH_SPSR,
65308c46b   Grant Likely   spi/topcliff: cle...
782
  			 pch_spi_readreg(data->master, PCH_SPSR));
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
783
784
785
786
  	/* Disable interrupts and SPI transfer */
  	pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL | SPCR_SPE_BIT);
  	/* clear FIFO */
  	pch_spi_clear_fifo(data->master);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
787
788
789
790
791
792
793
794
795
  }
  
  static void pch_spi_copy_rx_data(struct pch_spi_data *data, int bpw)
  {
  	int j;
  	u8 *rx_buf;
  	u16 *rx_sbuf;
  
  	/* copy Rx Data */
65308c46b   Grant Likely   spi/topcliff: cle...
796
  	if (!data->cur_trans->rx_buf)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
797
798
799
  		return;
  
  	if (bpw == 8) {
65308c46b   Grant Likely   spi/topcliff: cle...
800
801
802
  		rx_buf = data->cur_trans->rx_buf;
  		for (j = 0; j < data->bpw_len; j++)
  			*rx_buf++ = data->pkt_rx_buff[j] & 0xFF;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
803
  	} else {
65308c46b   Grant Likely   spi/topcliff: cle...
804
805
806
  		rx_sbuf = data->cur_trans->rx_buf;
  		for (j = 0; j < data->bpw_len; j++)
  			*rx_sbuf++ = data->pkt_rx_buff[j];
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
807
808
  	}
  }
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
  static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw)
  {
  	int j;
  	u8 *rx_buf;
  	u16 *rx_sbuf;
  	const u8 *rx_dma_buf;
  	const u16 *rx_dma_sbuf;
  
  	/* copy Rx Data */
  	if (!data->cur_trans->rx_buf)
  		return;
  
  	if (bpw == 8) {
  		rx_buf = data->cur_trans->rx_buf;
  		rx_dma_buf = data->dma.rx_buf_virt;
  		for (j = 0; j < data->bpw_len; j++)
  			*rx_buf++ = *rx_dma_buf++ & 0xFF;
  	} else {
  		rx_sbuf = data->cur_trans->rx_buf;
  		rx_dma_sbuf = data->dma.rx_buf_virt;
  		for (j = 0; j < data->bpw_len; j++)
  			*rx_sbuf++ = *rx_dma_sbuf++;
  	}
  }
25e803f9c   Tomoya MORINAGA   spi-topcliff-pch:...
833
  static int pch_spi_start_transfer(struct pch_spi_data *data)
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
834
835
836
  {
  	struct pch_spi_dma_ctrl *dma;
  	unsigned long flags;
25e803f9c   Tomoya MORINAGA   spi-topcliff-pch:...
837
  	int rtn;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
  
  	dma = &data->dma;
  
  	spin_lock_irqsave(&data->lock, flags);
  
  	/* disable interrupts, SPI set enable */
  	pch_spi_setclr_reg(data->master, PCH_SPCR, SPCR_SPE_BIT, PCH_ALL);
  
  	spin_unlock_irqrestore(&data->lock, flags);
  
  	/* Wait until the transfer completes; go to sleep after
  				 initiating the transfer. */
  	dev_dbg(&data->master->dev,
  		"%s:waiting for transfer to get over
  ", __func__);
25e803f9c   Tomoya MORINAGA   spi-topcliff-pch:...
853
854
855
  	rtn = wait_event_interruptible_timeout(data->wait,
  					       data->transfer_complete,
  					       msecs_to_jiffies(2 * HZ));
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
856
857
858
  
  	dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,
  			    DMA_FROM_DEVICE);
27504be5c   Tomoya MORINAGA   spi-topcliff-pch:...
859
860
861
862
  
  	dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent,
  			    DMA_FROM_DEVICE);
  	memset(data->dma.tx_buf_virt, 0, PAGE_SIZE);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
863
864
865
866
867
868
  	async_tx_ack(dma->desc_rx);
  	async_tx_ack(dma->desc_tx);
  	kfree(dma->sg_tx_p);
  	kfree(dma->sg_rx_p);
  
  	spin_lock_irqsave(&data->lock, flags);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
869
870
871
872
873
874
875
876
877
878
879
880
  
  	/* clear fifo threshold, disable interrupts, disable SPI transfer */
  	pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
  			   MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS | PCH_ALL |
  			   SPCR_SPE_BIT);
  	/* clear all interrupts */
  	pch_spi_writereg(data->master, PCH_SPSR,
  			 pch_spi_readreg(data->master, PCH_SPSR));
  	/* clear FIFO */
  	pch_spi_clear_fifo(data->master);
  
  	spin_unlock_irqrestore(&data->lock, flags);
25e803f9c   Tomoya MORINAGA   spi-topcliff-pch:...
881
882
  
  	return rtn;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  }
  
  static void pch_dma_rx_complete(void *arg)
  {
  	struct pch_spi_data *data = arg;
  
  	/* transfer is completed;inform pch_spi_process_messages_dma */
  	data->transfer_complete = true;
  	wake_up_interruptible(&data->wait);
  }
  
  static bool pch_spi_filter(struct dma_chan *chan, void *slave)
  {
  	struct pch_dma_slave *param = slave;
  
  	if ((chan->chan_id == param->chan_id) &&
  	    (param->dma_dev == chan->device->dev)) {
  		chan->private = param;
  		return true;
  	} else {
  		return false;
  	}
  }
  
  static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
  {
  	dma_cap_mask_t mask;
  	struct dma_chan *chan;
  	struct pci_dev *dma_dev;
  	struct pch_dma_slave *param;
  	struct pch_spi_dma_ctrl *dma;
  	unsigned int width;
  
  	if (bpw == 8)
  		width = PCH_DMA_WIDTH_1_BYTE;
  	else
  		width = PCH_DMA_WIDTH_2_BYTES;
  
  	dma = &data->dma;
  	dma_cap_zero(mask);
  	dma_cap_set(DMA_SLAVE, mask);
  
  	/* Get DMA's dev information */
  	dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(12, 0));
  
  	/* Set Tx DMA */
  	param = &dma->param_tx;
  	param->dma_dev = &dma_dev->dev;
  	param->chan_id = data->master->bus_num * 2; /* Tx = 0, 2 */
  	param->tx_reg = data->io_base_addr + PCH_SPDWR;
  	param->width = width;
  	chan = dma_request_channel(mask, pch_spi_filter, param);
  	if (!chan) {
  		dev_err(&data->master->dev,
  			"ERROR: dma_request_channel FAILS(Tx)
  ");
  		data->use_dma = 0;
  		return;
  	}
  	dma->chan_tx = chan;
  
  	/* Set Rx DMA */
  	param = &dma->param_rx;
  	param->dma_dev = &dma_dev->dev;
  	param->chan_id = data->master->bus_num * 2 + 1; /* Rx = Tx + 1 */
  	param->rx_reg = data->io_base_addr + PCH_SPDRR;
  	param->width = width;
  	chan = dma_request_channel(mask, pch_spi_filter, param);
  	if (!chan) {
  		dev_err(&data->master->dev,
  			"ERROR: dma_request_channel FAILS(Rx)
  ");
  		dma_release_channel(dma->chan_tx);
  		dma->chan_tx = NULL;
  		data->use_dma = 0;
  		return;
  	}
  	dma->chan_rx = chan;
  }
  
  static void pch_spi_release_dma(struct pch_spi_data *data)
  {
  	struct pch_spi_dma_ctrl *dma;
  
  	dma = &data->dma;
  	if (dma->chan_tx) {
  		dma_release_channel(dma->chan_tx);
  		dma->chan_tx = NULL;
  	}
  	if (dma->chan_rx) {
  		dma_release_channel(dma->chan_rx);
  		dma->chan_rx = NULL;
  	}
  	return;
  }
  
  static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
  {
  	const u8 *tx_buf;
  	const u16 *tx_sbuf;
  	u8 *tx_dma_buf;
  	u16 *tx_dma_sbuf;
  	struct scatterlist *sg;
  	struct dma_async_tx_descriptor *desc_tx;
  	struct dma_async_tx_descriptor *desc_rx;
  	int num;
  	int i;
  	int size;
  	int rem;
  	unsigned long flags;
  	struct pch_spi_dma_ctrl *dma;
  
  	dma = &data->dma;
  
  	/* set baud rate if needed */
  	if (data->cur_trans->speed_hz) {
  		dev_dbg(&data->master->dev, "%s:setting baud rate
  ", __func__);
  		spin_lock_irqsave(&data->lock, flags);
  		pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz);
  		spin_unlock_irqrestore(&data->lock, flags);
  	}
  
  	/* set bits per word if needed */
  	if (data->cur_trans->bits_per_word &&
  	    (data->current_msg->spi->bits_per_word !=
  	     data->cur_trans->bits_per_word)) {
  		dev_dbg(&data->master->dev, "%s:set bits per word
  ", __func__);
  		spin_lock_irqsave(&data->lock, flags);
  		pch_spi_set_bits_per_word(data->master,
  					  data->cur_trans->bits_per_word);
  		spin_unlock_irqrestore(&data->lock, flags);
  		*bpw = data->cur_trans->bits_per_word;
  	} else {
  		*bpw = data->current_msg->spi->bits_per_word;
  	}
  	data->bpw_len = data->cur_trans->len / (*bpw / 8);
  
  	/* copy Tx Data */
  	if (data->cur_trans->tx_buf != NULL) {
  		if (*bpw == 8) {
  			tx_buf = data->cur_trans->tx_buf;
  			tx_dma_buf = dma->tx_buf_virt;
  			for (i = 0; i < data->bpw_len; i++)
  				*tx_dma_buf++ = *tx_buf++;
  		} else {
  			tx_sbuf = data->cur_trans->tx_buf;
  			tx_dma_sbuf = dma->tx_buf_virt;
  			for (i = 0; i < data->bpw_len; i++)
  				*tx_dma_sbuf++ = *tx_sbuf++;
  		}
  	}
  	if (data->bpw_len > PCH_DMA_TRANS_SIZE) {
  		num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1;
  		size = PCH_DMA_TRANS_SIZE;
  		rem = data->bpw_len % PCH_DMA_TRANS_SIZE;
  	} else {
  		num = 1;
  		size = data->bpw_len;
  		rem = data->bpw_len;
  	}
  	dev_dbg(&data->master->dev, "%s num=%d size=%d rem=%d
  ",
  		__func__, num, size, rem);
  	spin_lock_irqsave(&data->lock, flags);
  
  	/* set receive fifo threshold and transmit fifo threshold */
  	pch_spi_setclr_reg(data->master, PCH_SPCR,
  			   ((size - 1) << SPCR_RFIC_FIELD) |
f3e03e2eb   Tomoya MORINAGA   spi-topcliff-pch:...
1053
  			   (PCH_TX_THOLD << SPCR_TFIC_FIELD),
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  			   MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS);
  
  	spin_unlock_irqrestore(&data->lock, flags);
  
  	/* RX */
  	dma->sg_rx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
  	sg_init_table(dma->sg_rx_p, num); /* Initialize SG table */
  	/* offset, length setting */
  	sg = dma->sg_rx_p;
  	for (i = 0; i < num; i++, sg++) {
f3e03e2eb   Tomoya MORINAGA   spi-topcliff-pch:...
1064
1065
1066
  		if (i == (num - 2)) {
  			sg->offset = size * i;
  			sg->offset = sg->offset * (*bpw / 8);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1067
1068
1069
  			sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem,
  				    sg->offset);
  			sg_dma_len(sg) = rem;
f3e03e2eb   Tomoya MORINAGA   spi-topcliff-pch:...
1070
1071
1072
1073
1074
1075
  		} else if (i == (num - 1)) {
  			sg->offset = size * (i - 1) + rem;
  			sg->offset = sg->offset * (*bpw / 8);
  			sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
  				    sg->offset);
  			sg_dma_len(sg) = size;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1076
  		} else {
f3e03e2eb   Tomoya MORINAGA   spi-topcliff-pch:...
1077
  			sg->offset = size * i;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  			sg->offset = sg->offset * (*bpw / 8);
  			sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
  				    sg->offset);
  			sg_dma_len(sg) = size;
  		}
  		sg_dma_address(sg) = dma->rx_buf_dma + sg->offset;
  	}
  	sg = dma->sg_rx_p;
  	desc_rx = dma->chan_rx->device->device_prep_slave_sg(dma->chan_rx, sg,
  					num, DMA_FROM_DEVICE,
  					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
  	if (!desc_rx) {
  		dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed
  ",
  			__func__);
  		return;
  	}
  	dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_FROM_DEVICE);
  	desc_rx->callback = pch_dma_rx_complete;
  	desc_rx->callback_param = data;
  	dma->nent = num;
  	dma->desc_rx = desc_rx;
  
  	/* TX */
f3e03e2eb   Tomoya MORINAGA   spi-topcliff-pch:...
1102
1103
1104
1105
1106
1107
1108
1109
1110
  	if (data->bpw_len > PCH_DMA_TRANS_SIZE) {
  		num = data->bpw_len / PCH_DMA_TRANS_SIZE;
  		size = PCH_DMA_TRANS_SIZE;
  		rem = 16;
  	} else {
  		num = 1;
  		size = data->bpw_len;
  		rem = data->bpw_len;
  	}
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  	dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
  	sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */
  	/* offset, length setting */
  	sg = dma->sg_tx_p;
  	for (i = 0; i < num; i++, sg++) {
  		if (i == 0) {
  			sg->offset = 0;
  			sg_set_page(sg, virt_to_page(dma->tx_buf_virt), rem,
  				    sg->offset);
  			sg_dma_len(sg) = rem;
  		} else {
  			sg->offset = rem + size * (i - 1);
  			sg->offset = sg->offset * (*bpw / 8);
  			sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size,
  				    sg->offset);
  			sg_dma_len(sg) = size;
  		}
  		sg_dma_address(sg) = dma->tx_buf_dma + sg->offset;
  	}
  	sg = dma->sg_tx_p;
  	desc_tx = dma->chan_tx->device->device_prep_slave_sg(dma->chan_tx,
  					sg, num, DMA_TO_DEVICE,
  					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
  	if (!desc_tx) {
  		dev_err(&data->master->dev, "%s:device_prep_slave_sg Failed
  ",
  			__func__);
  		return;
  	}
  	dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_TO_DEVICE);
  	desc_tx->callback = NULL;
  	desc_tx->callback_param = data;
  	dma->nent = num;
  	dma->desc_tx = desc_tx;
  
  	dev_dbg(&data->master->dev, "
  %s:Pulling down SSN low - writing "
  		"0x2 to SSNXCR
  ", __func__);
  
  	spin_lock_irqsave(&data->lock, flags);
  	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
  	desc_rx->tx_submit(desc_rx);
  	desc_tx->tx_submit(desc_tx);
  	spin_unlock_irqrestore(&data->lock, flags);
  
  	/* reset transfer complete flag */
  	data->transfer_complete = false;
  }
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1160
1161
1162
1163
  
  static void pch_spi_process_messages(struct work_struct *pwork)
  {
  	struct spi_message *pmsg;
65308c46b   Grant Likely   spi/topcliff: cle...
1164
  	struct pch_spi_data *data;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1165
  	int bpw;
65308c46b   Grant Likely   spi/topcliff: cle...
1166
  	data = container_of(pwork, struct pch_spi_data, work);
8e41b527f   Grant Likely   spi/topcliff: Fix...
1167
1168
  	dev_dbg(&data->master->dev, "%s data initialized
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1169
1170
  
  	spin_lock(&data->lock);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1171
  	/* check if suspend has been initiated;if yes flush queue */
65308c46b   Grant Likely   spi/topcliff: cle...
1172
  	if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) {
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1173
1174
1175
  		dev_dbg(&data->master->dev, "%s suspend/remove initiated,"
  			"flushing queue
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  		list_for_each_entry(pmsg, data->queue.next, queue) {
  			pmsg->status = -EIO;
  
  			if (pmsg->complete != 0) {
  				spin_unlock(&data->lock);
  				pmsg->complete(pmsg->context);
  				spin_lock(&data->lock);
  			}
  
  			/* delete from queue */
  			list_del_init(&pmsg->queue);
  		}
  
  		spin_unlock(&data->lock);
  		return;
  	}
  
  	data->bcurrent_msg_processing = true;
  	dev_dbg(&data->master->dev,
  		"%s Set data->bcurrent_msg_processing= true
  ", __func__);
  
  	/* Get the message from the queue and delete it from there. */
65308c46b   Grant Likely   spi/topcliff: cle...
1199
1200
  	data->current_msg = list_entry(data->queue.next, struct spi_message,
  					queue);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1201
1202
1203
1204
1205
1206
1207
1208
  
  	list_del_init(&data->current_msg->queue);
  
  	data->current_msg->status = 0;
  
  	pch_spi_select_chip(data, data->current_msg->spi);
  
  	spin_unlock(&data->lock);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1209
1210
1211
  	if (data->use_dma)
  		pch_spi_request_dma(data,
  				    data->current_msg->spi->bits_per_word);
8b7aa961a   Tomoya MORINAGA   spi-topcliff-pch:...
1212
  	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1213
1214
1215
1216
1217
  	do {
  		/* If we are already processing a message get the next
  		transfer structure from the message otherwise retrieve
  		the 1st transfer request from the message. */
  		spin_lock(&data->lock);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1218
1219
  		if (data->cur_trans == NULL) {
  			data->cur_trans =
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1220
1221
1222
1223
1224
  				list_entry(data->current_msg->transfers.next,
  					   struct spi_transfer, transfer_list);
  			dev_dbg(&data->master->dev, "%s "
  				":Getting 1st transfer message
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1225
1226
  		} else {
  			data->cur_trans =
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1227
1228
1229
1230
1231
  				list_entry(data->cur_trans->transfer_list.next,
  					   struct spi_transfer, transfer_list);
  			dev_dbg(&data->master->dev, "%s "
  				":Getting next transfer message
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1232
  		}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1233
  		spin_unlock(&data->lock);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1234
1235
  		if (data->use_dma) {
  			pch_spi_handle_dma(data, &bpw);
25e803f9c   Tomoya MORINAGA   spi-topcliff-pch:...
1236
1237
  			if (!pch_spi_start_transfer(data))
  				goto out;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
  			pch_spi_copy_rx_data_for_dma(data, bpw);
  		} else {
  			pch_spi_set_tx(data, &bpw);
  			pch_spi_set_ir(data);
  			pch_spi_copy_rx_data(data, bpw);
  			kfree(data->pkt_rx_buff);
  			data->pkt_rx_buff = NULL;
  			kfree(data->pkt_tx_buff);
  			data->pkt_tx_buff = NULL;
  		}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
  		/* increment message count */
  		data->current_msg->actual_length += data->cur_trans->len;
  
  		dev_dbg(&data->master->dev,
  			"%s:data->current_msg->actual_length=%d
  ",
  			__func__, data->current_msg->actual_length);
  
  		/* check for delay */
  		if (data->cur_trans->delay_usecs) {
  			dev_dbg(&data->master->dev, "%s:"
  				"delay in usec=%d
  ", __func__,
  				data->cur_trans->delay_usecs);
  			udelay(data->cur_trans->delay_usecs);
  		}
  
  		spin_lock(&data->lock);
  
  		/* No more transfer in this message. */
  		if ((data->cur_trans->transfer_list.next) ==
  		    &(data->current_msg->transfers)) {
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1270
  			pch_spi_nomore_transfer(data);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1271
1272
1273
  		}
  
  		spin_unlock(&data->lock);
65308c46b   Grant Likely   spi/topcliff: cle...
1274
  	} while (data->cur_trans != NULL);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1275

25e803f9c   Tomoya MORINAGA   spi-topcliff-pch:...
1276
  out:
8b7aa961a   Tomoya MORINAGA   spi-topcliff-pch:...
1277
  	pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1278
1279
  	if (data->use_dma)
  		pch_spi_release_dma(data);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1280
  }
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1281
1282
  static void pch_spi_free_resources(struct pch_spi_board_data *board_dat,
  				   struct pch_spi_data *data)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1283
1284
1285
1286
1287
  {
  	dev_dbg(&board_dat->pdev->dev, "%s ENTRY
  ", __func__);
  
  	/* free workqueue */
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1288
1289
1290
  	if (data->wk != NULL) {
  		destroy_workqueue(data->wk);
  		data->wk = NULL;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1291
1292
1293
1294
1295
  		dev_dbg(&board_dat->pdev->dev,
  			"%s destroy_workqueue invoked successfully
  ",
  			__func__);
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1296
  }
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1297
1298
  static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
  				 struct pch_spi_data *data)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1299
  {
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1300
  	int retval = 0;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1301
1302
  	dev_dbg(&board_dat->pdev->dev, "%s ENTRY
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1303
  	/* create workqueue */
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1304
1305
  	data->wk = create_singlethread_workqueue(KBUILD_MODNAME);
  	if (!data->wk) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1306
1307
1308
1309
1310
1311
  		dev_err(&board_dat->pdev->dev,
  			"%s create_singlet hread_workqueue failed
  ", __func__);
  		retval = -EBUSY;
  		goto err_return;
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1312
  	/* reset PCH SPI h/w */
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1313
  	pch_spi_reset(data->master);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1314
1315
1316
  	dev_dbg(&board_dat->pdev->dev,
  		"%s pch_spi_reset invoked successfully
  ", __func__);
65308c46b   Grant Likely   spi/topcliff: cle...
1317
1318
  	dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1319
1320
1321
1322
1323
1324
  
  err_return:
  	if (retval != 0) {
  		dev_err(&board_dat->pdev->dev,
  			"%s FAIL:invoking pch_spi_free_resources
  ", __func__);
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1325
  		pch_spi_free_resources(board_dat, data);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1326
1327
1328
1329
1330
1331
1332
  	}
  
  	dev_dbg(&board_dat->pdev->dev, "%s Return=%d
  ", __func__, retval);
  
  	return retval;
  }
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
  static void pch_free_dma_buf(struct pch_spi_board_data *board_dat,
  			     struct pch_spi_data *data)
  {
  	struct pch_spi_dma_ctrl *dma;
  
  	dma = &data->dma;
  	if (dma->tx_buf_dma)
  		dma_free_coherent(&board_dat->pdev->dev, PCH_BUF_SIZE,
  				  dma->tx_buf_virt, dma->tx_buf_dma);
  	if (dma->rx_buf_dma)
  		dma_free_coherent(&board_dat->pdev->dev, PCH_BUF_SIZE,
  				  dma->rx_buf_virt, dma->rx_buf_dma);
  	return;
  }
  
  static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
  			      struct pch_spi_data *data)
  {
  	struct pch_spi_dma_ctrl *dma;
  
  	dma = &data->dma;
  	/* Get Consistent memory for Tx DMA */
  	dma->tx_buf_virt = dma_alloc_coherent(&board_dat->pdev->dev,
  				PCH_BUF_SIZE, &dma->tx_buf_dma, GFP_KERNEL);
  	/* Get Consistent memory for Rx DMA */
  	dma->rx_buf_virt = dma_alloc_coherent(&board_dat->pdev->dev,
  				PCH_BUF_SIZE, &dma->rx_buf_dma, GFP_KERNEL);
  }
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1361
  static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1362
  {
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1363
  	int ret;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1364
  	struct spi_master *master;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1365
1366
  	struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev);
  	struct pch_spi_data *data;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1367

c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1368
1369
  	dev_dbg(&plat_dev->dev, "%s:debug
  ", __func__);
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1370
1371
1372
1373
1374
1375
1376
  	master = spi_alloc_master(&board_dat->pdev->dev,
  				  sizeof(struct pch_spi_data));
  	if (!master) {
  		dev_err(&plat_dev->dev, "spi_alloc_master[%d] failed.
  ",
  			plat_dev->id);
  		return -ENOMEM;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1377
  	}
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1378
1379
  	data = spi_master_get_devdata(master);
  	data->master = master;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1380

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1381
  	platform_set_drvdata(plat_dev, data);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1382

c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1383
1384
1385
  	/* baseaddress + address offset) */
  	data->io_base_addr = pci_resource_start(board_dat->pdev, 1) +
  					 PCH_ADDRESS_SIZE * plat_dev->id;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1386
  	data->io_remap_addr = pci_iomap(board_dat->pdev, 1, 0) +
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1387
  					 PCH_ADDRESS_SIZE * plat_dev->id;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1388
1389
1390
1391
1392
  	if (!data->io_remap_addr) {
  		dev_err(&plat_dev->dev, "%s pci_iomap failed
  ", __func__);
  		ret = -ENOMEM;
  		goto err_pci_iomap;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1393
  	}
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1394
1395
1396
  	dev_dbg(&plat_dev->dev, "[ch%d] remap_addr=%p
  ",
  		plat_dev->id, data->io_remap_addr);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1397
1398
1399
1400
1401
1402
  
  	/* initialize members of SPI master */
  	master->bus_num = -1;
  	master->num_chipselect = PCH_MAX_CS;
  	master->setup = pch_spi_setup;
  	master->transfer = pch_spi_transfer;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1403

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1404
1405
1406
1407
1408
  	data->board_dat = board_dat;
  	data->plat_dev = plat_dev;
  	data->n_curnt_chip = 255;
  	data->status = STATUS_RUNNING;
  	data->ch = plat_dev->id;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1409
  	data->use_dma = use_dma;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1410

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1411
1412
1413
1414
  	INIT_LIST_HEAD(&data->queue);
  	spin_lock_init(&data->lock);
  	INIT_WORK(&data->work, pch_spi_process_messages);
  	init_waitqueue_head(&data->wait);
65308c46b   Grant Likely   spi/topcliff: cle...
1415

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1416
1417
1418
1419
  	ret = pch_spi_get_resources(board_dat, data);
  	if (ret) {
  		dev_err(&plat_dev->dev, "%s fail(retval=%d)
  ", __func__, ret);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1420
1421
  		goto err_spi_get_resources;
  	}
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1422
1423
1424
1425
1426
1427
1428
1429
1430
  	ret = request_irq(board_dat->pdev->irq, pch_spi_handler,
  			  IRQF_SHARED, KBUILD_MODNAME, data);
  	if (ret) {
  		dev_err(&plat_dev->dev,
  			"%s request_irq failed
  ", __func__);
  		goto err_request_irq;
  	}
  	data->irq_reg_sts = true;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1431

e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1432
  	pch_spi_set_master_mode(master);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1433

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1434
1435
1436
  	ret = spi_register_master(master);
  	if (ret != 0) {
  		dev_err(&plat_dev->dev,
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1437
1438
  			"%s spi_register_master FAILED
  ", __func__);
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1439
  		goto err_spi_register_master;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1440
  	}
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1441
1442
1443
1444
1445
  	if (use_dma) {
  		dev_info(&plat_dev->dev, "Use DMA for data transfers
  ");
  		pch_alloc_dma_buf(board_dat, data);
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1446
  	return 0;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1447
1448
1449
1450
  err_spi_register_master:
  	free_irq(board_dat->pdev->irq, board_dat);
  err_request_irq:
  	pch_spi_free_resources(board_dat, data);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1451
  err_spi_get_resources:
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1452
1453
  	pci_iounmap(board_dat->pdev, data->io_remap_addr);
  err_pci_iomap:
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1454
  	spi_master_put(master);
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1455
1456
  
  	return ret;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1457
  }
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1458
  static int __devexit pch_spi_pd_remove(struct platform_device *plat_dev)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1459
  {
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1460
1461
  	struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev);
  	struct pch_spi_data *data = platform_get_drvdata(plat_dev);
65308c46b   Grant Likely   spi/topcliff: cle...
1462
  	int count;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1463
  	unsigned long flags;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1464

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1465
1466
1467
  	dev_dbg(&plat_dev->dev, "%s:[ch%d] irq=%d
  ",
  		__func__, plat_dev->id, board_dat->pdev->irq);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1468
1469
1470
  
  	if (use_dma)
  		pch_free_dma_buf(board_dat, data);
65308c46b   Grant Likely   spi/topcliff: cle...
1471
1472
1473
  	/* check for any pending messages; no action is taken if the queue
  	 * is still full; but at least we tried.  Unload anyway */
  	count = 500;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1474
  	spin_lock_irqsave(&data->lock, flags);
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1475
1476
  	data->status = STATUS_EXITING;
  	while ((list_empty(&data->queue) == 0) && --count) {
65308c46b   Grant Likely   spi/topcliff: cle...
1477
1478
1479
  		dev_dbg(&board_dat->pdev->dev, "%s :queue not empty
  ",
  			__func__);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1480
  		spin_unlock_irqrestore(&data->lock, flags);
65308c46b   Grant Likely   spi/topcliff: cle...
1481
  		msleep(PCH_SLEEP_TIME);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1482
  		spin_lock_irqsave(&data->lock, flags);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1483
  	}
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1484
  	spin_unlock_irqrestore(&data->lock, flags);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1485

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1486
1487
1488
1489
1490
1491
1492
1493
  	pch_spi_free_resources(board_dat, data);
  	/* disable interrupts & free IRQ */
  	if (data->irq_reg_sts) {
  		/* disable interrupts */
  		pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
  		data->irq_reg_sts = false;
  		free_irq(board_dat->pdev->irq, data);
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1494

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1495
1496
1497
1498
  	pci_iounmap(board_dat->pdev, data->io_remap_addr);
  	spi_unregister_master(data->master);
  	spi_master_put(data->master);
  	platform_set_drvdata(plat_dev, NULL);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1499

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1500
  	return 0;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1501
  }
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1502
  #ifdef CONFIG_PM
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1503
1504
  static int pch_spi_pd_suspend(struct platform_device *pd_dev,
  			      pm_message_t state)
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1505
1506
  {
  	u8 count;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1507
1508
  	struct pch_spi_board_data *board_dat = dev_get_platdata(&pd_dev->dev);
  	struct pch_spi_data *data = platform_get_drvdata(pd_dev);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1509

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1510
1511
  	dev_dbg(&pd_dev->dev, "%s ENTRY
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1512
1513
  
  	if (!board_dat) {
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1514
  		dev_err(&pd_dev->dev,
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1515
1516
1517
1518
  			"%s pci_get_drvdata returned NULL
  ", __func__);
  		return -EFAULT;
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1519
1520
1521
  	/* check if the current message is processed:
  	   Only after thats done the transfer will be suspended */
  	count = 255;
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1522
1523
  	while ((--count) > 0) {
  		if (!(data->bcurrent_msg_processing))
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1524
  			break;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1525
1526
1527
1528
  		msleep(PCH_SLEEP_TIME);
  	}
  
  	/* Free IRQ */
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1529
  	if (data->irq_reg_sts) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1530
  		/* disable all interrupts */
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1531
1532
1533
  		pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
  		pch_spi_reset(data->master);
  		free_irq(board_dat->pdev->irq, data);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1534

f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1535
1536
  		data->irq_reg_sts = false;
  		dev_dbg(&pd_dev->dev,
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1537
1538
1539
  			"%s free_irq invoked successfully.
  ", __func__);
  	}
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
  	return 0;
  }
  
  static int pch_spi_pd_resume(struct platform_device *pd_dev)
  {
  	struct pch_spi_board_data *board_dat = dev_get_platdata(&pd_dev->dev);
  	struct pch_spi_data *data = platform_get_drvdata(pd_dev);
  	int retval;
  
  	if (!board_dat) {
  		dev_err(&pd_dev->dev,
  			"%s pci_get_drvdata returned NULL
  ", __func__);
  		return -EFAULT;
  	}
  
  	if (!data->irq_reg_sts) {
  		/* register IRQ */
  		retval = request_irq(board_dat->pdev->irq, pch_spi_handler,
  				     IRQF_SHARED, KBUILD_MODNAME, data);
  		if (retval < 0) {
  			dev_err(&pd_dev->dev,
  				"%s request_irq failed
  ", __func__);
  			return retval;
  		}
  
  		/* reset PCH SPI h/w */
  		pch_spi_reset(data->master);
  		pch_spi_set_master_mode(data->master);
  		data->irq_reg_sts = true;
  	}
  	return 0;
  }
  #else
  #define pch_spi_pd_suspend NULL
  #define pch_spi_pd_resume NULL
  #endif
  
  static struct platform_driver pch_spi_pd_driver = {
  	.driver = {
  		.name = "pch-spi",
  		.owner = THIS_MODULE,
  	},
  	.probe = pch_spi_pd_probe,
  	.remove = __devexit_p(pch_spi_pd_remove),
  	.suspend = pch_spi_pd_suspend,
  	.resume = pch_spi_pd_resume
  };
  
  static int __devinit pch_spi_probe(struct pci_dev *pdev,
  				   const struct pci_device_id *id)
  {
  	struct pch_spi_board_data *board_dat;
  	struct platform_device *pd_dev = NULL;
  	int retval;
  	int i;
  	struct pch_pd_dev_save *pd_dev_save;
  
  	pd_dev_save = kzalloc(sizeof(struct pch_pd_dev_save), GFP_KERNEL);
  	if (!pd_dev_save) {
  		dev_err(&pdev->dev, "%s Can't allocate pd_dev_sav
  ", __func__);
  		return -ENOMEM;
  	}
  
  	board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL);
  	if (!board_dat) {
  		dev_err(&pdev->dev, "%s Can't allocate board_dat
  ", __func__);
  		retval = -ENOMEM;
  		goto err_no_mem;
  	}
  
  	retval = pci_request_regions(pdev, KBUILD_MODNAME);
  	if (retval) {
  		dev_err(&pdev->dev, "%s request_region failed
  ", __func__);
  		goto pci_request_regions;
  	}
  
  	board_dat->pdev = pdev;
  	board_dat->num = id->driver_data;
  	pd_dev_save->num = id->driver_data;
  	pd_dev_save->board_dat = board_dat;
  
  	retval = pci_enable_device(pdev);
  	if (retval) {
  		dev_err(&pdev->dev, "%s pci_enable_device failed
  ", __func__);
  		goto pci_enable_device;
  	}
  
  	for (i = 0; i < board_dat->num; i++) {
  		pd_dev = platform_device_alloc("pch-spi", i);
  		if (!pd_dev) {
  			dev_err(&pdev->dev, "platform_device_alloc failed
  ");
  			goto err_platform_device;
  		}
  		pd_dev_save->pd_save[i] = pd_dev;
  		pd_dev->dev.parent = &pdev->dev;
  
  		retval = platform_device_add_data(pd_dev, board_dat,
  						  sizeof(*board_dat));
  		if (retval) {
  			dev_err(&pdev->dev,
  				"platform_device_add_data failed
  ");
  			platform_device_put(pd_dev);
  			goto err_platform_device;
  		}
  
  		retval = platform_device_add(pd_dev);
  		if (retval) {
  			dev_err(&pdev->dev, "platform_device_add failed
  ");
  			platform_device_put(pd_dev);
  			goto err_platform_device;
  		}
  	}
  
  	pci_set_drvdata(pdev, pd_dev_save);
  
  	return 0;
  
  err_platform_device:
  	pci_disable_device(pdev);
  pci_enable_device:
  	pci_release_regions(pdev);
  pci_request_regions:
  	kfree(board_dat);
  err_no_mem:
  	kfree(pd_dev_save);
  
  	return retval;
  }
  
  static void __devexit pch_spi_remove(struct pci_dev *pdev)
  {
  	int i;
  	struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev);
  
  	dev_dbg(&pdev->dev, "%s ENTRY:pdev=%p
  ", __func__, pdev);
  
  	for (i = 0; i < pd_dev_save->num; i++)
  		platform_device_unregister(pd_dev_save->pd_save[i]);
  
  	pci_disable_device(pdev);
  	pci_release_regions(pdev);
  	kfree(pd_dev_save->board_dat);
  	kfree(pd_dev_save);
  }
  
  #ifdef CONFIG_PM
  static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state)
  {
  	int retval;
  	struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev);
  
  	dev_dbg(&pdev->dev, "%s ENTRY
  ", __func__);
  
  	pd_dev_save->board_dat->suspend_sts = true;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1705
1706
  	/* save config space */
  	retval = pci_save_state(pdev);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1707
  	if (retval == 0) {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1708
  		pci_enable_wake(pdev, PCI_D3hot, 0);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1709
  		pci_disable_device(pdev);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1710
  		pci_set_power_state(pdev, PCI_D3hot);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1711
1712
1713
1714
  	} else {
  		dev_err(&pdev->dev, "%s pci_save_state failed
  ", __func__);
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1715
1716
1717
1718
1719
1720
  	return retval;
  }
  
  static int pch_spi_resume(struct pci_dev *pdev)
  {
  	int retval;
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1721
  	struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1722
1723
  	dev_dbg(&pdev->dev, "%s ENTRY
  ", __func__);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1724
  	pci_set_power_state(pdev, PCI_D0);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1725
1726
1727
1728
1729
1730
1731
1732
  	pci_restore_state(pdev);
  
  	retval = pci_enable_device(pdev);
  	if (retval < 0) {
  		dev_err(&pdev->dev,
  			"%s pci_enable_device failed
  ", __func__);
  	} else {
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1733
  		pci_enable_wake(pdev, PCI_D3hot, 0);
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1734
1735
  		/* set suspend status to false */
  		pd_dev_save->board_dat->suspend_sts = false;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1736
  	}
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
  	return retval;
  }
  #else
  #define pch_spi_suspend NULL
  #define pch_spi_resume NULL
  
  #endif
  
  static struct pci_driver pch_spi_pcidev = {
  	.name = "pch_spi",
  	.id_table = pch_spi_pcidev_id,
  	.probe = pch_spi_probe,
  	.remove = pch_spi_remove,
  	.suspend = pch_spi_suspend,
  	.resume = pch_spi_resume,
  };
  
  static int __init pch_spi_init(void)
  {
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
  	int ret;
  	ret = platform_driver_register(&pch_spi_pd_driver);
  	if (ret)
  		return ret;
  
  	ret = pci_register_driver(&pch_spi_pcidev);
  	if (ret)
  		return ret;
  
  	return 0;
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1766
1767
  }
  module_init(pch_spi_init);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1768
1769
1770
  static void __exit pch_spi_exit(void)
  {
  	pci_unregister_driver(&pch_spi_pcidev);
f016aeb65   Tomoya MORINAGA   spi/topcliff_pch:...
1771
  	platform_driver_unregister(&pch_spi_pd_driver);
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1772
1773
  }
  module_exit(pch_spi_exit);
c37f3c274   Tomoya MORINAGA   spi/topcliff_pch:...
1774
1775
1776
  module_param(use_dma, int, 0644);
  MODULE_PARM_DESC(use_dma,
  		 "to use DMA for data transfers pass 1 else 0; default 1");
e8b17b5b3   Masayuki Ohtake   spi/topcliff: Add...
1777
  MODULE_LICENSE("GPL");
2b2462832   Tomoya MORINAGA   spi-topcliff-pch:...
1778
  MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor ML7xxx IOH SPI Driver");