Commit | Line | Data |
---|---|---|
e8b17b5b MO |
1 | /* |
2 | * SPI bus driver for the Topcliff PCH used by Intel SoCs | |
65308c46 | 3 | * |
e8b17b5b MO |
4 | * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; version 2 of the License. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | |
18 | */ | |
19 | ||
65308c46 | 20 | #include <linux/delay.h> |
e8b17b5b MO |
21 | #include <linux/pci.h> |
22 | #include <linux/wait.h> | |
23 | #include <linux/spi/spi.h> | |
24 | #include <linux/interrupt.h> | |
25 | #include <linux/sched.h> | |
26 | #include <linux/spi/spidev.h> | |
27 | #include <linux/module.h> | |
28 | #include <linux/device.h> | |
29 | ||
30 | /* Register offsets */ | |
31 | #define PCH_SPCR 0x00 /* SPI control register */ | |
32 | #define PCH_SPBRR 0x04 /* SPI baud rate register */ | |
33 | #define PCH_SPSR 0x08 /* SPI status register */ | |
34 | #define PCH_SPDWR 0x0C /* SPI write data register */ | |
35 | #define PCH_SPDRR 0x10 /* SPI read data register */ | |
36 | #define PCH_SSNXCR 0x18 /* SSN Expand Control Register */ | |
37 | #define PCH_SRST 0x1C /* SPI reset register */ | |
38 | ||
39 | #define PCH_SPSR_TFD 0x000007C0 | |
40 | #define PCH_SPSR_RFD 0x0000F800 | |
41 | ||
42 | #define PCH_READABLE(x) (((x) & PCH_SPSR_RFD)>>11) | |
43 | #define PCH_WRITABLE(x) (((x) & PCH_SPSR_TFD)>>6) | |
44 | ||
45 | #define PCH_RX_THOLD 7 | |
46 | #define PCH_RX_THOLD_MAX 15 | |
e8b17b5b | 47 | |
e8b17b5b MO |
48 | #define PCH_MAX_BAUDRATE 5000000 |
49 | #define PCH_MAX_FIFO_DEPTH 16 | |
50 | ||
51 | #define STATUS_RUNNING 1 | |
52 | #define STATUS_EXITING 2 | |
53 | #define PCH_SLEEP_TIME 10 | |
54 | ||
55 | #define PCH_ADDRESS_SIZE 0x20 | |
56 | ||
57 | #define SSN_LOW 0x02U | |
58 | #define SSN_NO_CONTROL 0x00U | |
59 | #define PCH_MAX_CS 0xFF | |
60 | #define PCI_DEVICE_ID_GE_SPI 0x8816 | |
61 | ||
62 | #define SPCR_SPE_BIT (1 << 0) | |
63 | #define SPCR_MSTR_BIT (1 << 1) | |
64 | #define SPCR_LSBF_BIT (1 << 4) | |
65 | #define SPCR_CPHA_BIT (1 << 5) | |
66 | #define SPCR_CPOL_BIT (1 << 6) | |
67 | #define SPCR_TFIE_BIT (1 << 8) | |
68 | #define SPCR_RFIE_BIT (1 << 9) | |
69 | #define SPCR_FIE_BIT (1 << 10) | |
70 | #define SPCR_ORIE_BIT (1 << 11) | |
71 | #define SPCR_MDFIE_BIT (1 << 12) | |
72 | #define SPCR_FICLR_BIT (1 << 24) | |
73 | #define SPSR_TFI_BIT (1 << 0) | |
74 | #define SPSR_RFI_BIT (1 << 1) | |
75 | #define SPSR_FI_BIT (1 << 2) | |
76 | #define SPBRR_SIZE_BIT (1 << 10) | |
77 | ||
65308c46 GL |
78 | #define PCH_ALL (SPCR_TFIE_BIT|SPCR_RFIE_BIT|SPCR_FIE_BIT|SPCR_ORIE_BIT|SPCR_MDFIE_BIT) |
79 | ||
e8b17b5b MO |
80 | #define SPCR_RFIC_FIELD 20 |
81 | #define SPCR_TFIC_FIELD 16 | |
82 | ||
83 | #define SPSR_INT_BITS 0x1F | |
84 | #define MASK_SPBRR_SPBR_BITS (~((1 << 10) - 1)) | |
85 | #define MASK_RFIC_SPCR_BITS (~(0xf << 20)) | |
86 | #define MASK_TFIC_SPCR_BITS (~(0xf000f << 12)) | |
87 | ||
88 | #define PCH_CLOCK_HZ 50000000 | |
89 | #define PCH_MAX_SPBR 1023 | |
90 | ||
91 | ||
92 | /** | |
93 | * struct pch_spi_data - Holds the SPI channel specific details | |
94 | * @io_remap_addr: The remapped PCI base address | |
95 | * @master: Pointer to the SPI master structure | |
96 | * @work: Reference to work queue handler | |
97 | * @wk: Workqueue for carrying out execution of the | |
98 | * requests | |
99 | * @wait: Wait queue for waking up upon receiving an | |
100 | * interrupt. | |
101 | * @transfer_complete: Status of SPI Transfer | |
102 | * @bcurrent_msg_processing: Status flag for message processing | |
103 | * @lock: Lock for protecting this structure | |
104 | * @queue: SPI Message queue | |
105 | * @status: Status of the SPI driver | |
106 | * @bpw_len: Length of data to be transferred in bits per | |
107 | * word | |
108 | * @transfer_active: Flag showing active transfer | |
109 | * @tx_index: Transmit data count; for bookkeeping during | |
110 | * transfer | |
111 | * @rx_index: Receive data count; for bookkeeping during | |
112 | * transfer | |
113 | * @tx_buff: Buffer for data to be transmitted | |
114 | * @rx_index: Buffer for Received data | |
115 | * @n_curnt_chip: The chip number that this SPI driver currently | |
116 | * operates on | |
117 | * @current_chip: Reference to the current chip that this SPI | |
118 | * driver currently operates on | |
119 | * @current_msg: The current message that this SPI driver is | |
120 | * handling | |
121 | * @cur_trans: The current transfer that this SPI driver is | |
122 | * handling | |
123 | * @board_dat: Reference to the SPI device data structure | |
124 | */ | |
125 | struct pch_spi_data { | |
126 | void __iomem *io_remap_addr; | |
127 | struct spi_master *master; | |
128 | struct work_struct work; | |
129 | struct workqueue_struct *wk; | |
130 | wait_queue_head_t wait; | |
131 | u8 transfer_complete; | |
132 | u8 bcurrent_msg_processing; | |
133 | spinlock_t lock; | |
134 | struct list_head queue; | |
135 | u8 status; | |
136 | u32 bpw_len; | |
137 | u8 transfer_active; | |
138 | u32 tx_index; | |
139 | u32 rx_index; | |
140 | u16 *pkt_tx_buff; | |
141 | u16 *pkt_rx_buff; | |
142 | u8 n_curnt_chip; | |
143 | struct spi_device *current_chip; | |
144 | struct spi_message *current_msg; | |
145 | struct spi_transfer *cur_trans; | |
146 | struct pch_spi_board_data *board_dat; | |
147 | }; | |
148 | ||
149 | /** | |
150 | * struct pch_spi_board_data - Holds the SPI device specific details | |
151 | * @pdev: Pointer to the PCI device | |
152 | * @irq_reg_sts: Status of IRQ registration | |
153 | * @pci_req_sts: Status of pci_request_regions | |
154 | * @suspend_sts: Status of suspend | |
155 | * @data: Pointer to SPI channel data structure | |
156 | */ | |
157 | struct pch_spi_board_data { | |
158 | struct pci_dev *pdev; | |
159 | u8 irq_reg_sts; | |
160 | u8 pci_req_sts; | |
161 | u8 suspend_sts; | |
162 | struct pch_spi_data *data; | |
163 | }; | |
164 | ||
165 | static struct pci_device_id pch_spi_pcidev_id[] = { | |
166 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_GE_SPI)}, | |
167 | {0,} | |
168 | }; | |
169 | ||
e8b17b5b MO |
170 | /** |
171 | * pch_spi_writereg() - Performs register writes | |
172 | * @master: Pointer to struct spi_master. | |
173 | * @idx: Register offset. | |
174 | * @val: Value to be written to register. | |
175 | */ | |
176 | static inline void pch_spi_writereg(struct spi_master *master, int idx, u32 val) | |
177 | { | |
e8b17b5b | 178 | struct pch_spi_data *data = spi_master_get_devdata(master); |
e8b17b5b MO |
179 | iowrite32(val, (data->io_remap_addr + idx)); |
180 | } | |
181 | ||
182 | /** | |
183 | * pch_spi_readreg() - Performs register reads | |
184 | * @master: Pointer to struct spi_master. | |
185 | * @idx: Register offset. | |
186 | */ | |
187 | static inline u32 pch_spi_readreg(struct spi_master *master, int idx) | |
188 | { | |
189 | struct pch_spi_data *data = spi_master_get_devdata(master); | |
e8b17b5b MO |
190 | return ioread32(data->io_remap_addr + idx); |
191 | } | |
192 | ||
e8b17b5b MO |
193 | static inline void pch_spi_setclr_reg(struct spi_master *master, int idx, |
194 | u32 set, u32 clr) | |
195 | { | |
196 | u32 tmp = pch_spi_readreg(master, idx); | |
197 | tmp = (tmp & ~clr) | set; | |
198 | pch_spi_writereg(master, idx, tmp); | |
199 | } | |
200 | ||
e8b17b5b MO |
201 | static void pch_spi_set_master_mode(struct spi_master *master) |
202 | { | |
203 | pch_spi_setclr_reg(master, PCH_SPCR, SPCR_MSTR_BIT, 0); | |
204 | } | |
205 | ||
206 | /** | |
207 | * pch_spi_clear_fifo() - Clears the Transmit and Receive FIFOs | |
208 | * @master: Pointer to struct spi_master. | |
209 | */ | |
210 | static void pch_spi_clear_fifo(struct spi_master *master) | |
211 | { | |
212 | pch_spi_setclr_reg(master, PCH_SPCR, SPCR_FICLR_BIT, 0); | |
213 | pch_spi_setclr_reg(master, PCH_SPCR, 0, SPCR_FICLR_BIT); | |
214 | } | |
215 | ||
e8b17b5b MO |
216 | static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, |
217 | void __iomem *io_remap_addr) | |
218 | { | |
219 | u32 n_read, tx_index, rx_index, bpw_len; | |
220 | u16 *pkt_rx_buffer, *pkt_tx_buff; | |
221 | int read_cnt; | |
222 | u32 reg_spcr_val; | |
223 | void __iomem *spsr; | |
224 | void __iomem *spdrr; | |
225 | void __iomem *spdwr; | |
226 | ||
227 | spsr = io_remap_addr + PCH_SPSR; | |
228 | iowrite32(reg_spsr_val, spsr); | |
229 | ||
230 | if (data->transfer_active) { | |
231 | rx_index = data->rx_index; | |
232 | tx_index = data->tx_index; | |
233 | bpw_len = data->bpw_len; | |
234 | pkt_rx_buffer = data->pkt_rx_buff; | |
235 | pkt_tx_buff = data->pkt_tx_buff; | |
236 | ||
237 | spdrr = io_remap_addr + PCH_SPDRR; | |
238 | spdwr = io_remap_addr + PCH_SPDWR; | |
239 | ||
240 | n_read = PCH_READABLE(reg_spsr_val); | |
241 | ||
242 | for (read_cnt = 0; (read_cnt < n_read); read_cnt++) { | |
243 | pkt_rx_buffer[rx_index++] = ioread32(spdrr); | |
244 | if (tx_index < bpw_len) | |
245 | iowrite32(pkt_tx_buff[tx_index++], spdwr); | |
246 | } | |
247 | ||
248 | /* disable RFI if not needed */ | |
249 | if ((bpw_len - rx_index) <= PCH_MAX_FIFO_DEPTH) { | |
250 | reg_spcr_val = ioread32(io_remap_addr + PCH_SPCR); | |
65308c46 | 251 | reg_spcr_val &= ~SPCR_RFIE_BIT; /* disable RFI */ |
e8b17b5b MO |
252 | |
253 | /* reset rx threshold */ | |
254 | reg_spcr_val &= MASK_RFIC_SPCR_BITS; | |
255 | reg_spcr_val |= (PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD); | |
256 | iowrite32(((reg_spcr_val) &= (~(SPCR_RFIE_BIT))), | |
257 | (io_remap_addr + PCH_SPCR)); | |
258 | } | |
259 | ||
260 | /* update counts */ | |
261 | data->tx_index = tx_index; | |
262 | data->rx_index = rx_index; | |
263 | ||
264 | } | |
265 | ||
266 | /* if transfer complete interrupt */ | |
267 | if (reg_spsr_val & SPSR_FI_BIT) { | |
268 | /* disable FI & RFI interrupts */ | |
65308c46 | 269 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, |
9d32af66 | 270 | SPCR_FIE_BIT | SPCR_RFIE_BIT); |
e8b17b5b MO |
271 | |
272 | /* transfer is completed;inform pch_spi_process_messages */ | |
273 | data->transfer_complete = true; | |
274 | wake_up(&data->wait); | |
275 | } | |
276 | } | |
277 | ||
e8b17b5b MO |
278 | /** |
279 | * pch_spi_handler() - Interrupt handler | |
280 | * @irq: The interrupt number. | |
281 | * @dev_id: Pointer to struct pch_spi_board_data. | |
282 | */ | |
283 | static irqreturn_t pch_spi_handler(int irq, void *dev_id) | |
284 | { | |
285 | u32 reg_spsr_val; | |
286 | struct pch_spi_data *data; | |
287 | void __iomem *spsr; | |
288 | void __iomem *io_remap_addr; | |
289 | irqreturn_t ret = IRQ_NONE; | |
e8b17b5b MO |
290 | struct pch_spi_board_data *board_dat = dev_id; |
291 | ||
292 | if (board_dat->suspend_sts) { | |
293 | dev_dbg(&board_dat->pdev->dev, | |
294 | "%s returning due to suspend\n", __func__); | |
295 | return IRQ_NONE; | |
296 | } | |
297 | ||
298 | data = board_dat->data; | |
299 | io_remap_addr = data->io_remap_addr; | |
300 | spsr = io_remap_addr + PCH_SPSR; | |
301 | ||
302 | reg_spsr_val = ioread32(spsr); | |
303 | ||
304 | /* Check if the interrupt is for SPI device */ | |
e8b17b5b MO |
305 | if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { |
306 | pch_spi_handler_sub(data, reg_spsr_val, io_remap_addr); | |
307 | ret = IRQ_HANDLED; | |
308 | } | |
309 | ||
310 | dev_dbg(&board_dat->pdev->dev, "%s EXIT return value=%d\n", | |
311 | __func__, ret); | |
312 | ||
313 | return ret; | |
314 | } | |
315 | ||
316 | /** | |
317 | * pch_spi_set_baud_rate() - Sets SPBR field in SPBRR | |
318 | * @master: Pointer to struct spi_master. | |
319 | * @speed_hz: Baud rate. | |
320 | */ | |
321 | static void pch_spi_set_baud_rate(struct spi_master *master, u32 speed_hz) | |
322 | { | |
65308c46 | 323 | u32 n_spbr = PCH_CLOCK_HZ / (speed_hz * 2); |
e8b17b5b MO |
324 | |
325 | /* if baud rate is less than we can support limit it */ | |
e8b17b5b MO |
326 | if (n_spbr > PCH_MAX_SPBR) |
327 | n_spbr = PCH_MAX_SPBR; | |
328 | ||
329 | pch_spi_setclr_reg(master, PCH_SPBRR, n_spbr, ~MASK_SPBRR_SPBR_BITS); | |
330 | } | |
331 | ||
332 | /** | |
333 | * pch_spi_set_bits_per_word() - Sets SIZE field in SPBRR | |
334 | * @master: Pointer to struct spi_master. | |
335 | * @bits_per_word: Bits per word for SPI transfer. | |
336 | */ | |
337 | static void pch_spi_set_bits_per_word(struct spi_master *master, | |
338 | u8 bits_per_word) | |
339 | { | |
340 | if (bits_per_word == 8) | |
341 | pch_spi_setclr_reg(master, PCH_SPBRR, 0, SPBRR_SIZE_BIT); | |
342 | else | |
343 | pch_spi_setclr_reg(master, PCH_SPBRR, SPBRR_SIZE_BIT, 0); | |
344 | } | |
345 | ||
346 | /** | |
347 | * pch_spi_setup_transfer() - Configures the PCH SPI hardware for transfer | |
348 | * @spi: Pointer to struct spi_device. | |
349 | */ | |
350 | static void pch_spi_setup_transfer(struct spi_device *spi) | |
351 | { | |
65308c46 | 352 | u32 flags = 0; |
e8b17b5b MO |
353 | |
354 | dev_dbg(&spi->dev, "%s SPBRR content =%x setting baud rate=%d\n", | |
355 | __func__, pch_spi_readreg(spi->master, PCH_SPBRR), | |
356 | spi->max_speed_hz); | |
e8b17b5b MO |
357 | pch_spi_set_baud_rate(spi->master, spi->max_speed_hz); |
358 | ||
359 | /* set bits per word */ | |
360 | pch_spi_set_bits_per_word(spi->master, spi->bits_per_word); | |
361 | ||
65308c46 GL |
362 | if (!(spi->mode & SPI_LSB_FIRST)) |
363 | flags |= SPCR_LSBF_BIT; | |
e8b17b5b | 364 | if (spi->mode & SPI_CPOL) |
65308c46 | 365 | flags |= SPCR_CPOL_BIT; |
e8b17b5b | 366 | if (spi->mode & SPI_CPHA) |
65308c46 GL |
367 | flags |= SPCR_CPHA_BIT; |
368 | pch_spi_setclr_reg(spi->master, PCH_SPCR, flags, | |
369 | (SPCR_LSBF_BIT | SPCR_CPOL_BIT | SPCR_CPHA_BIT)); | |
e8b17b5b MO |
370 | |
371 | /* Clear the FIFO by toggling FICLR to 1 and back to 0 */ | |
372 | pch_spi_clear_fifo(spi->master); | |
373 | } | |
374 | ||
e8b17b5b MO |
375 | /** |
376 | * pch_spi_reset() - Clears SPI registers | |
377 | * @master: Pointer to struct spi_master. | |
378 | */ | |
379 | static void pch_spi_reset(struct spi_master *master) | |
380 | { | |
381 | /* write 1 to reset SPI */ | |
382 | pch_spi_writereg(master, PCH_SRST, 0x1); | |
383 | ||
384 | /* clear reset */ | |
385 | pch_spi_writereg(master, PCH_SRST, 0x0); | |
386 | } | |
387 | ||
388 | static int pch_spi_setup(struct spi_device *pspi) | |
389 | { | |
390 | /* check bits per word */ | |
65308c46 | 391 | if (pspi->bits_per_word == 0) { |
e8b17b5b MO |
392 | pspi->bits_per_word = 8; |
393 | dev_dbg(&pspi->dev, "%s 8 bits per word\n", __func__); | |
394 | } | |
395 | ||
65308c46 | 396 | if ((pspi->bits_per_word != 8) && (pspi->bits_per_word != 16)) { |
e8b17b5b MO |
397 | dev_err(&pspi->dev, "%s Invalid bits per word\n", __func__); |
398 | return -EINVAL; | |
399 | } | |
400 | ||
401 | /* Check baud rate setting */ | |
402 | /* if baud rate of chip is greater than | |
403 | max we can support,return error */ | |
404 | if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE) | |
405 | pspi->max_speed_hz = PCH_MAX_BAUDRATE; | |
406 | ||
407 | dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__, | |
65308c46 | 408 | (pspi->mode) & (SPI_CPOL | SPI_CPHA)); |
e8b17b5b MO |
409 | |
410 | return 0; | |
411 | } | |
412 | ||
413 | static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) | |
414 | { | |
415 | ||
416 | struct spi_transfer *transfer; | |
417 | struct pch_spi_data *data = spi_master_get_devdata(pspi->master); | |
418 | int retval; | |
419 | unsigned long flags; | |
420 | ||
421 | /* validate spi message and baud rate */ | |
65308c46 GL |
422 | if (unlikely(list_empty(&pmsg->transfers) == 1)) { |
423 | dev_err(&pspi->dev, "%s list empty\n", __func__); | |
424 | retval = -EINVAL; | |
425 | goto err_out; | |
426 | } | |
e8b17b5b | 427 | |
65308c46 GL |
428 | if (unlikely(pspi->max_speed_hz == 0)) { |
429 | dev_err(&pspi->dev, "%s pch_spi_tranfer maxspeed=%d\n", | |
430 | __func__, pspi->max_speed_hz); | |
e8b17b5b MO |
431 | retval = -EINVAL; |
432 | goto err_out; | |
433 | } | |
434 | ||
435 | dev_dbg(&pspi->dev, "%s Transfer List not empty. " | |
436 | "Transfer Speed is set.\n", __func__); | |
437 | ||
e8b17b5b MO |
438 | /* validate Tx/Rx buffers and Transfer length */ |
439 | list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { | |
65308c46 | 440 | if (!transfer->tx_buf && !transfer->rx_buf) { |
e8b17b5b MO |
441 | dev_err(&pspi->dev, |
442 | "%s Tx and Rx buffer NULL\n", __func__); | |
443 | retval = -EINVAL; | |
65308c46 | 444 | goto err_out; |
e8b17b5b MO |
445 | } |
446 | ||
65308c46 | 447 | if (!transfer->len) { |
e8b17b5b MO |
448 | dev_err(&pspi->dev, "%s Transfer length invalid\n", |
449 | __func__); | |
450 | retval = -EINVAL; | |
65308c46 | 451 | goto err_out; |
e8b17b5b MO |
452 | } |
453 | ||
454 | dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length" | |
455 | " valid\n", __func__); | |
456 | ||
457 | /* if baud rate hs been specified validate the same */ | |
65308c46 GL |
458 | if (transfer->speed_hz > PCH_MAX_BAUDRATE) |
459 | transfer->speed_hz = PCH_MAX_BAUDRATE; | |
e8b17b5b MO |
460 | |
461 | /* if bits per word has been specified validate the same */ | |
462 | if (transfer->bits_per_word) { | |
463 | if ((transfer->bits_per_word != 8) | |
464 | && (transfer->bits_per_word != 16)) { | |
465 | retval = -EINVAL; | |
466 | dev_err(&pspi->dev, | |
467 | "%s Invalid bits per word\n", __func__); | |
65308c46 | 468 | goto err_out; |
e8b17b5b MO |
469 | } |
470 | } | |
471 | } | |
472 | ||
65308c46 | 473 | spin_lock_irqsave(&data->lock, flags); |
e8b17b5b | 474 | |
65308c46 GL |
475 | /* We won't process any messages if we have been asked to terminate */ |
476 | if (data->status == STATUS_EXITING) { | |
e8b17b5b MO |
477 | dev_err(&pspi->dev, "%s status = STATUS_EXITING.\n", __func__); |
478 | retval = -ESHUTDOWN; | |
479 | goto err_return_spinlock; | |
480 | } | |
481 | ||
482 | /* If suspended ,return -EINVAL */ | |
483 | if (data->board_dat->suspend_sts) { | |
65308c46 | 484 | dev_err(&pspi->dev, "%s suspend; returning EINVAL\n", __func__); |
e8b17b5b MO |
485 | retval = -EINVAL; |
486 | goto err_return_spinlock; | |
487 | } | |
488 | ||
489 | /* set status of message */ | |
490 | pmsg->actual_length = 0; | |
e8b17b5b MO |
491 | dev_dbg(&pspi->dev, "%s - pmsg->status =%d\n", __func__, pmsg->status); |
492 | ||
493 | pmsg->status = -EINPROGRESS; | |
494 | ||
495 | /* add message to queue */ | |
496 | list_add_tail(&pmsg->queue, &data->queue); | |
e8b17b5b MO |
497 | dev_dbg(&pspi->dev, "%s - Invoked list_add_tail\n", __func__); |
498 | ||
499 | /* schedule work queue to run */ | |
500 | queue_work(data->wk, &data->work); | |
e8b17b5b MO |
501 | dev_dbg(&pspi->dev, "%s - Invoked queue work\n", __func__); |
502 | ||
503 | retval = 0; | |
504 | ||
505 | err_return_spinlock: | |
506 | spin_unlock_irqrestore(&data->lock, flags); | |
507 | err_out: | |
508 | dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval); | |
509 | return retval; | |
510 | } | |
511 | ||
512 | static inline void pch_spi_select_chip(struct pch_spi_data *data, | |
513 | struct spi_device *pspi) | |
514 | { | |
65308c46 GL |
515 | if (data->current_chip != NULL) { |
516 | if (pspi->chip_select != data->n_curnt_chip) { | |
517 | dev_dbg(&pspi->dev, "%s : different slave\n", __func__); | |
e8b17b5b MO |
518 | data->current_chip = NULL; |
519 | } | |
520 | } | |
521 | ||
522 | data->current_chip = pspi; | |
523 | ||
524 | data->n_curnt_chip = data->current_chip->chip_select; | |
525 | ||
526 | dev_dbg(&pspi->dev, "%s :Invoking pch_spi_setup_transfer\n", __func__); | |
527 | pch_spi_setup_transfer(pspi); | |
528 | } | |
529 | ||
530 | static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw, | |
65308c46 | 531 | struct spi_message **ppmsg) |
e8b17b5b | 532 | { |
e8b17b5b MO |
533 | int size; |
534 | u32 n_writes; | |
535 | int j; | |
536 | struct spi_message *pmsg; | |
537 | const u8 *tx_buf; | |
538 | const u16 *tx_sbuf; | |
539 | ||
540 | pmsg = *ppmsg; | |
541 | ||
542 | /* set baud rate if needed */ | |
543 | if (data->cur_trans->speed_hz) { | |
65308c46 GL |
544 | dev_dbg(&data->master->dev, "%s:setting baud rate\n", __func__); |
545 | pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz); | |
e8b17b5b MO |
546 | } |
547 | ||
548 | /* set bits per word if needed */ | |
65308c46 GL |
549 | if (data->cur_trans->bits_per_word && |
550 | (data->current_msg->spi->bits_per_word != data->cur_trans->bits_per_word)) { | |
551 | dev_dbg(&data->master->dev, "%s:set bits per word\n", __func__); | |
e8b17b5b | 552 | pch_spi_set_bits_per_word(data->master, |
65308c46 | 553 | data->cur_trans->bits_per_word); |
e8b17b5b MO |
554 | *bpw = data->cur_trans->bits_per_word; |
555 | } else { | |
556 | *bpw = data->current_msg->spi->bits_per_word; | |
557 | } | |
558 | ||
559 | /* reset Tx/Rx index */ | |
560 | data->tx_index = 0; | |
561 | data->rx_index = 0; | |
562 | ||
563 | data->bpw_len = data->cur_trans->len / (*bpw / 8); | |
e8b17b5b MO |
564 | |
565 | /* find alloc size */ | |
65308c46 GL |
566 | size = data->cur_trans->len * sizeof(*data->pkt_tx_buff); |
567 | ||
e8b17b5b MO |
568 | /* allocate memory for pkt_tx_buff & pkt_rx_buffer */ |
569 | data->pkt_tx_buff = kzalloc(size, GFP_KERNEL); | |
e8b17b5b MO |
570 | if (data->pkt_tx_buff != NULL) { |
571 | data->pkt_rx_buff = kzalloc(size, GFP_KERNEL); | |
65308c46 | 572 | if (!data->pkt_rx_buff) |
e8b17b5b | 573 | kfree(data->pkt_tx_buff); |
e8b17b5b MO |
574 | } |
575 | ||
65308c46 | 576 | if (!data->pkt_rx_buff) { |
e8b17b5b | 577 | /* flush queue and set status of all transfers to -ENOMEM */ |
65308c46 | 578 | dev_err(&data->master->dev, "%s :kzalloc failed\n", __func__); |
e8b17b5b MO |
579 | list_for_each_entry(pmsg, data->queue.next, queue) { |
580 | pmsg->status = -ENOMEM; | |
581 | ||
582 | if (pmsg->complete != 0) | |
583 | pmsg->complete(pmsg->context); | |
584 | ||
585 | /* delete from queue */ | |
586 | list_del_init(&pmsg->queue); | |
587 | } | |
e8b17b5b MO |
588 | return; |
589 | } | |
590 | ||
591 | /* copy Tx Data */ | |
65308c46 | 592 | if (data->cur_trans->tx_buf != NULL) { |
e8b17b5b | 593 | if (*bpw == 8) { |
65308c46 GL |
594 | tx_buf = data->cur_trans->tx_buf; |
595 | for (j = 0; j < data->bpw_len; j++) | |
596 | data->pkt_tx_buff[j] = *tx_buf++; | |
e8b17b5b | 597 | } else { |
65308c46 GL |
598 | tx_sbuf = data->cur_trans->tx_buf; |
599 | for (j = 0; j < data->bpw_len; j++) | |
600 | data->pkt_tx_buff[j] = *tx_sbuf++; | |
e8b17b5b MO |
601 | } |
602 | } | |
603 | ||
604 | /* if len greater than PCH_MAX_FIFO_DEPTH, write 16,else len bytes */ | |
65308c46 GL |
605 | n_writes = data->bpw_len; |
606 | if (n_writes > PCH_MAX_FIFO_DEPTH) | |
e8b17b5b | 607 | n_writes = PCH_MAX_FIFO_DEPTH; |
e8b17b5b | 608 | |
65308c46 | 609 | dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " |
e8b17b5b MO |
610 | "0x2 to SSNXCR\n", __func__); |
611 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); | |
612 | ||
65308c46 GL |
613 | for (j = 0; j < n_writes; j++) |
614 | pch_spi_writereg(data->master, PCH_SPDWR, data->pkt_tx_buff[j]); | |
e8b17b5b MO |
615 | |
616 | /* update tx_index */ | |
617 | data->tx_index = j; | |
618 | ||
619 | /* reset transfer complete flag */ | |
620 | data->transfer_complete = false; | |
621 | data->transfer_active = true; | |
622 | } | |
623 | ||
624 | ||
625 | static void pch_spi_nomore_transfer(struct pch_spi_data *data, | |
626 | struct spi_message *pmsg) | |
627 | { | |
65308c46 | 628 | dev_dbg(&data->master->dev, "%s called\n", __func__); |
e8b17b5b | 629 | /* Invoke complete callback |
65308c46 | 630 | * [To the spi core..indicating end of transfer] */ |
e8b17b5b MO |
631 | data->current_msg->status = 0; |
632 | ||
65308c46 | 633 | if (data->current_msg->complete != 0) { |
e8b17b5b MO |
634 | dev_dbg(&data->master->dev, |
635 | "%s:Invoking callback of SPI core\n", __func__); | |
636 | data->current_msg->complete(data->current_msg->context); | |
637 | } | |
638 | ||
639 | /* update status in global variable */ | |
640 | data->bcurrent_msg_processing = false; | |
641 | ||
642 | dev_dbg(&data->master->dev, | |
643 | "%s:data->bcurrent_msg_processing = false\n", __func__); | |
644 | ||
645 | data->current_msg = NULL; | |
646 | data->cur_trans = NULL; | |
647 | ||
65308c46 GL |
648 | /* check if we have items in list and not suspending |
649 | * return 1 if list empty */ | |
e8b17b5b | 650 | if ((list_empty(&data->queue) == 0) && |
65308c46 GL |
651 | (!data->board_dat->suspend_sts) && |
652 | (data->status != STATUS_EXITING)) { | |
e8b17b5b | 653 | /* We have some more work to do (either there is more tranint |
65308c46 GL |
654 | * bpw;sfer requests in the current message or there are |
655 | *more messages) | |
656 | */ | |
657 | dev_dbg(&data->master->dev, "%s:Invoke queue_work\n", __func__); | |
e8b17b5b | 658 | queue_work(data->wk, &data->work); |
65308c46 GL |
659 | } else if (data->board_dat->suspend_sts || |
660 | data->status == STATUS_EXITING) { | |
e8b17b5b MO |
661 | dev_dbg(&data->master->dev, |
662 | "%s suspend/remove initiated, flushing queue\n", | |
663 | __func__); | |
664 | list_for_each_entry(pmsg, data->queue.next, queue) { | |
665 | pmsg->status = -EIO; | |
666 | ||
65308c46 | 667 | if (pmsg->complete) |
e8b17b5b MO |
668 | pmsg->complete(pmsg->context); |
669 | ||
670 | /* delete from queue */ | |
671 | list_del_init(&pmsg->queue); | |
672 | } | |
673 | } | |
674 | } | |
675 | ||
676 | static void pch_spi_set_ir(struct pch_spi_data *data) | |
677 | { | |
e8b17b5b MO |
678 | /* enable interrupts */ |
679 | if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) { | |
77e58efd | 680 | /* set receive threshold to PCH_RX_THOLD */ |
65308c46 | 681 | pch_spi_setclr_reg(data->master, PCH_SPCR, |
9d32af66 TM |
682 | PCH_RX_THOLD << SPCR_RFIC_FIELD, |
683 | ~MASK_RFIC_SPCR_BITS); | |
e8b17b5b | 684 | /* enable FI and RFI interrupts */ |
65308c46 | 685 | pch_spi_setclr_reg(data->master, PCH_SPCR, |
9d32af66 | 686 | SPCR_RFIE_BIT | SPCR_FIE_BIT, 0); |
e8b17b5b | 687 | } else { |
77e58efd | 688 | /* set receive threshold to maximum */ |
65308c46 GL |
689 | pch_spi_setclr_reg(data->master, PCH_SPCR, |
690 | PCH_RX_THOLD_MAX << SPCR_TFIC_FIELD, | |
691 | ~MASK_TFIC_SPCR_BITS); | |
e8b17b5b | 692 | /* enable FI interrupt */ |
65308c46 | 693 | pch_spi_setclr_reg(data->master, PCH_SPCR, SPCR_FIE_BIT, 0); |
e8b17b5b MO |
694 | } |
695 | ||
696 | dev_dbg(&data->master->dev, | |
697 | "%s:invoking pch_spi_set_enable to enable SPI\n", __func__); | |
698 | ||
699 | /* SPI set enable */ | |
65308c46 | 700 | pch_spi_setclr_reg(data->current_chip->master, PCH_SPCR, SPCR_SPE_BIT, 0); |
e8b17b5b MO |
701 | |
702 | /* Wait until the transfer completes; go to sleep after | |
703 | initiating the transfer. */ | |
704 | dev_dbg(&data->master->dev, | |
705 | "%s:waiting for transfer to get over\n", __func__); | |
706 | ||
707 | wait_event_interruptible(data->wait, data->transfer_complete); | |
708 | ||
709 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | |
710 | dev_dbg(&data->master->dev, | |
711 | "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); | |
712 | ||
713 | data->transfer_active = false; | |
714 | dev_dbg(&data->master->dev, | |
715 | "%s set data->transfer_active = false\n", __func__); | |
716 | ||
717 | /* clear all interrupts */ | |
718 | pch_spi_writereg(data->master, PCH_SPSR, | |
65308c46 | 719 | pch_spi_readreg(data->master, PCH_SPSR)); |
e8b17b5b | 720 | /* disable interrupts */ |
65308c46 | 721 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); |
e8b17b5b MO |
722 | } |
723 | ||
724 | static void pch_spi_copy_rx_data(struct pch_spi_data *data, int bpw) | |
725 | { | |
726 | int j; | |
727 | u8 *rx_buf; | |
728 | u16 *rx_sbuf; | |
729 | ||
730 | /* copy Rx Data */ | |
65308c46 | 731 | if (!data->cur_trans->rx_buf) |
e8b17b5b MO |
732 | return; |
733 | ||
734 | if (bpw == 8) { | |
65308c46 GL |
735 | rx_buf = data->cur_trans->rx_buf; |
736 | for (j = 0; j < data->bpw_len; j++) | |
737 | *rx_buf++ = data->pkt_rx_buff[j] & 0xFF; | |
e8b17b5b | 738 | } else { |
65308c46 GL |
739 | rx_sbuf = data->cur_trans->rx_buf; |
740 | for (j = 0; j < data->bpw_len; j++) | |
741 | *rx_sbuf++ = data->pkt_rx_buff[j]; | |
e8b17b5b MO |
742 | } |
743 | } | |
744 | ||
745 | ||
746 | static void pch_spi_process_messages(struct work_struct *pwork) | |
747 | { | |
748 | struct spi_message *pmsg; | |
65308c46 | 749 | struct pch_spi_data *data; |
e8b17b5b MO |
750 | int bpw; |
751 | ||
65308c46 | 752 | data = container_of(pwork, struct pch_spi_data, work); |
8e41b527 | 753 | dev_dbg(&data->master->dev, "%s data initialized\n", __func__); |
e8b17b5b MO |
754 | |
755 | spin_lock(&data->lock); | |
756 | ||
757 | /* check if suspend has been initiated;if yes flush queue */ | |
65308c46 | 758 | if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) { |
e8b17b5b MO |
759 | dev_dbg(&data->master->dev, |
760 | "%s suspend/remove initiated,flushing queue\n", | |
761 | __func__); | |
65308c46 | 762 | |
e8b17b5b MO |
763 | list_for_each_entry(pmsg, data->queue.next, queue) { |
764 | pmsg->status = -EIO; | |
765 | ||
766 | if (pmsg->complete != 0) { | |
767 | spin_unlock(&data->lock); | |
768 | pmsg->complete(pmsg->context); | |
769 | spin_lock(&data->lock); | |
770 | } | |
771 | ||
772 | /* delete from queue */ | |
773 | list_del_init(&pmsg->queue); | |
774 | } | |
775 | ||
776 | spin_unlock(&data->lock); | |
777 | return; | |
778 | } | |
779 | ||
780 | data->bcurrent_msg_processing = true; | |
781 | dev_dbg(&data->master->dev, | |
782 | "%s Set data->bcurrent_msg_processing= true\n", __func__); | |
783 | ||
784 | /* Get the message from the queue and delete it from there. */ | |
65308c46 GL |
785 | data->current_msg = list_entry(data->queue.next, struct spi_message, |
786 | queue); | |
e8b17b5b MO |
787 | |
788 | list_del_init(&data->current_msg->queue); | |
789 | ||
790 | data->current_msg->status = 0; | |
791 | ||
792 | pch_spi_select_chip(data, data->current_msg->spi); | |
793 | ||
794 | spin_unlock(&data->lock); | |
795 | ||
796 | do { | |
797 | /* If we are already processing a message get the next | |
798 | transfer structure from the message otherwise retrieve | |
799 | the 1st transfer request from the message. */ | |
800 | spin_lock(&data->lock); | |
801 | ||
802 | if (data->cur_trans == NULL) { | |
803 | data->cur_trans = | |
804 | list_entry(data->current_msg->transfers. | |
805 | next, struct spi_transfer, | |
806 | transfer_list); | |
807 | dev_dbg(&data->master->dev, | |
808 | "%s :Getting 1st transfer message\n", __func__); | |
809 | } else { | |
810 | data->cur_trans = | |
811 | list_entry(data->cur_trans->transfer_list.next, | |
812 | struct spi_transfer, | |
813 | transfer_list); | |
814 | dev_dbg(&data->master->dev, | |
815 | "%s :Getting next transfer message\n", | |
816 | __func__); | |
817 | } | |
818 | ||
819 | spin_unlock(&data->lock); | |
820 | ||
821 | pch_spi_set_tx(data, &bpw, &pmsg); | |
822 | ||
823 | /* Control interrupt*/ | |
824 | pch_spi_set_ir(data); | |
825 | ||
826 | /* Disable SPI transfer */ | |
827 | pch_spi_setclr_reg(data->current_chip->master, PCH_SPCR, 0, | |
828 | SPCR_SPE_BIT); | |
829 | ||
830 | /* clear FIFO */ | |
831 | pch_spi_clear_fifo(data->master); | |
832 | ||
833 | /* copy Rx Data */ | |
834 | pch_spi_copy_rx_data(data, bpw); | |
835 | ||
836 | /* free memory */ | |
837 | kfree(data->pkt_rx_buff); | |
838 | data->pkt_rx_buff = NULL; | |
839 | ||
840 | kfree(data->pkt_tx_buff); | |
841 | data->pkt_tx_buff = NULL; | |
842 | ||
843 | /* increment message count */ | |
844 | data->current_msg->actual_length += data->cur_trans->len; | |
845 | ||
846 | dev_dbg(&data->master->dev, | |
847 | "%s:data->current_msg->actual_length=%d\n", | |
848 | __func__, data->current_msg->actual_length); | |
849 | ||
850 | /* check for delay */ | |
851 | if (data->cur_trans->delay_usecs) { | |
852 | dev_dbg(&data->master->dev, "%s:" | |
853 | "delay in usec=%d\n", __func__, | |
854 | data->cur_trans->delay_usecs); | |
855 | udelay(data->cur_trans->delay_usecs); | |
856 | } | |
857 | ||
858 | spin_lock(&data->lock); | |
859 | ||
860 | /* No more transfer in this message. */ | |
861 | if ((data->cur_trans->transfer_list.next) == | |
862 | &(data->current_msg->transfers)) { | |
863 | pch_spi_nomore_transfer(data, pmsg); | |
864 | } | |
865 | ||
866 | spin_unlock(&data->lock); | |
867 | ||
65308c46 | 868 | } while (data->cur_trans != NULL); |
e8b17b5b MO |
869 | } |
870 | ||
871 | static void pch_spi_free_resources(struct pch_spi_board_data *board_dat) | |
872 | { | |
873 | dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); | |
874 | ||
875 | /* free workqueue */ | |
876 | if (board_dat->data->wk != NULL) { | |
877 | destroy_workqueue(board_dat->data->wk); | |
878 | board_dat->data->wk = NULL; | |
879 | dev_dbg(&board_dat->pdev->dev, | |
880 | "%s destroy_workqueue invoked successfully\n", | |
881 | __func__); | |
882 | } | |
883 | ||
884 | /* disable interrupts & free IRQ */ | |
885 | if (board_dat->irq_reg_sts) { | |
886 | /* disable interrupts */ | |
65308c46 GL |
887 | pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0, |
888 | PCH_ALL); | |
e8b17b5b MO |
889 | |
890 | /* free IRQ */ | |
65308c46 | 891 | free_irq(board_dat->pdev->irq, board_dat); |
e8b17b5b MO |
892 | |
893 | dev_dbg(&board_dat->pdev->dev, | |
894 | "%s free_irq invoked successfully\n", __func__); | |
895 | ||
896 | board_dat->irq_reg_sts = false; | |
897 | } | |
898 | ||
899 | /* unmap PCI base address */ | |
65308c46 | 900 | if (board_dat->data->io_remap_addr != 0) { |
e8b17b5b MO |
901 | pci_iounmap(board_dat->pdev, board_dat->data->io_remap_addr); |
902 | ||
903 | board_dat->data->io_remap_addr = 0; | |
904 | ||
905 | dev_dbg(&board_dat->pdev->dev, | |
906 | "%s pci_iounmap invoked successfully\n", __func__); | |
907 | } | |
908 | ||
909 | /* release PCI region */ | |
910 | if (board_dat->pci_req_sts) { | |
911 | pci_release_regions(board_dat->pdev); | |
912 | dev_dbg(&board_dat->pdev->dev, | |
913 | "%s pci_release_regions invoked successfully\n", | |
914 | __func__); | |
915 | board_dat->pci_req_sts = false; | |
916 | } | |
917 | } | |
918 | ||
919 | static int pch_spi_get_resources(struct pch_spi_board_data *board_dat) | |
920 | { | |
921 | void __iomem *io_remap_addr; | |
922 | int retval; | |
923 | dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); | |
924 | ||
e8b17b5b MO |
925 | /* create workqueue */ |
926 | board_dat->data->wk = create_singlethread_workqueue(KBUILD_MODNAME); | |
65308c46 | 927 | if (!board_dat->data->wk) { |
e8b17b5b MO |
928 | dev_err(&board_dat->pdev->dev, |
929 | "%s create_singlet hread_workqueue failed\n", __func__); | |
930 | retval = -EBUSY; | |
931 | goto err_return; | |
932 | } | |
933 | ||
934 | dev_dbg(&board_dat->pdev->dev, | |
935 | "%s create_singlethread_workqueue success\n", __func__); | |
936 | ||
937 | retval = pci_request_regions(board_dat->pdev, KBUILD_MODNAME); | |
938 | if (retval != 0) { | |
939 | dev_err(&board_dat->pdev->dev, | |
940 | "%s request_region failed\n", __func__); | |
941 | goto err_return; | |
942 | } | |
943 | ||
944 | board_dat->pci_req_sts = true; | |
945 | ||
946 | io_remap_addr = pci_iomap(board_dat->pdev, 1, 0); | |
e8b17b5b MO |
947 | if (io_remap_addr == 0) { |
948 | dev_err(&board_dat->pdev->dev, | |
949 | "%s pci_iomap failed\n", __func__); | |
950 | retval = -ENOMEM; | |
951 | goto err_return; | |
952 | } | |
953 | ||
954 | /* calculate base address for all channels */ | |
955 | board_dat->data->io_remap_addr = io_remap_addr; | |
956 | ||
957 | /* reset PCH SPI h/w */ | |
958 | pch_spi_reset(board_dat->data->master); | |
959 | dev_dbg(&board_dat->pdev->dev, | |
960 | "%s pch_spi_reset invoked successfully\n", __func__); | |
961 | ||
962 | /* register IRQ */ | |
963 | retval = request_irq(board_dat->pdev->irq, pch_spi_handler, | |
65308c46 | 964 | IRQF_SHARED, KBUILD_MODNAME, board_dat); |
e8b17b5b MO |
965 | if (retval != 0) { |
966 | dev_err(&board_dat->pdev->dev, | |
967 | "%s request_irq failed\n", __func__); | |
968 | goto err_return; | |
969 | } | |
970 | ||
971 | dev_dbg(&board_dat->pdev->dev, "%s request_irq returned=%d\n", | |
972 | __func__, retval); | |
973 | ||
974 | board_dat->irq_reg_sts = true; | |
65308c46 | 975 | dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__); |
e8b17b5b MO |
976 | |
977 | err_return: | |
978 | if (retval != 0) { | |
979 | dev_err(&board_dat->pdev->dev, | |
980 | "%s FAIL:invoking pch_spi_free_resources\n", __func__); | |
981 | pch_spi_free_resources(board_dat); | |
982 | } | |
983 | ||
984 | dev_dbg(&board_dat->pdev->dev, "%s Return=%d\n", __func__, retval); | |
985 | ||
986 | return retval; | |
987 | } | |
988 | ||
e8b17b5b MO |
989 | static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
990 | { | |
991 | ||
992 | struct spi_master *master; | |
993 | ||
994 | struct pch_spi_board_data *board_dat; | |
995 | int retval; | |
996 | ||
997 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | |
998 | ||
999 | /* allocate memory for private data */ | |
1000 | board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); | |
1001 | if (board_dat == NULL) { | |
1002 | dev_err(&pdev->dev, | |
1003 | " %s memory allocation for private data failed\n", | |
1004 | __func__); | |
1005 | retval = -ENOMEM; | |
1006 | goto err_kmalloc; | |
1007 | } | |
1008 | ||
1009 | dev_dbg(&pdev->dev, | |
1010 | "%s memory allocation for private data success\n", __func__); | |
1011 | ||
1012 | /* enable PCI device */ | |
1013 | retval = pci_enable_device(pdev); | |
1014 | if (retval != 0) { | |
1015 | dev_err(&pdev->dev, "%s pci_enable_device FAILED\n", __func__); | |
1016 | ||
1017 | goto err_pci_en_device; | |
1018 | } | |
1019 | ||
1020 | dev_dbg(&pdev->dev, "%s pci_enable_device returned=%d\n", | |
1021 | __func__, retval); | |
1022 | ||
1023 | board_dat->pdev = pdev; | |
1024 | ||
1025 | /* alllocate memory for SPI master */ | |
1026 | master = spi_alloc_master(&pdev->dev, sizeof(struct pch_spi_data)); | |
1027 | if (master == NULL) { | |
1028 | retval = -ENOMEM; | |
1029 | dev_err(&pdev->dev, "%s Fail.\n", __func__); | |
1030 | goto err_spi_alloc_master; | |
1031 | } | |
1032 | ||
1033 | dev_dbg(&pdev->dev, | |
1034 | "%s spi_alloc_master returned non NULL\n", __func__); | |
1035 | ||
1036 | /* initialize members of SPI master */ | |
1037 | master->bus_num = -1; | |
1038 | master->num_chipselect = PCH_MAX_CS; | |
1039 | master->setup = pch_spi_setup; | |
1040 | master->transfer = pch_spi_transfer; | |
1041 | dev_dbg(&pdev->dev, | |
1042 | "%s transfer member of SPI master initialized\n", __func__); | |
1043 | ||
1044 | board_dat->data = spi_master_get_devdata(master); | |
1045 | ||
1046 | board_dat->data->master = master; | |
1047 | board_dat->data->n_curnt_chip = 255; | |
1048 | board_dat->data->board_dat = board_dat; | |
65308c46 GL |
1049 | board_dat->data->status = STATUS_RUNNING; |
1050 | ||
1051 | INIT_LIST_HEAD(&board_dat->data->queue); | |
1052 | spin_lock_init(&board_dat->data->lock); | |
1053 | INIT_WORK(&board_dat->data->work, pch_spi_process_messages); | |
1054 | init_waitqueue_head(&board_dat->data->wait); | |
e8b17b5b MO |
1055 | |
1056 | /* allocate resources for PCH SPI */ | |
1057 | retval = pch_spi_get_resources(board_dat); | |
65308c46 GL |
1058 | if (retval) { |
1059 | dev_err(&pdev->dev, "%s fail(retval=%d)\n", __func__, retval); | |
e8b17b5b MO |
1060 | goto err_spi_get_resources; |
1061 | } | |
1062 | ||
1063 | dev_dbg(&pdev->dev, "%s pch_spi_get_resources returned=%d\n", | |
1064 | __func__, retval); | |
1065 | ||
1066 | /* save private data in dev */ | |
65308c46 | 1067 | pci_set_drvdata(pdev, board_dat); |
e8b17b5b MO |
1068 | dev_dbg(&pdev->dev, "%s invoked pci_set_drvdata\n", __func__); |
1069 | ||
1070 | /* set master mode */ | |
1071 | pch_spi_set_master_mode(master); | |
1072 | dev_dbg(&pdev->dev, | |
1073 | "%s invoked pch_spi_set_master_mode\n", __func__); | |
1074 | ||
1075 | /* Register the controller with the SPI core. */ | |
1076 | retval = spi_register_master(master); | |
1077 | if (retval != 0) { | |
1078 | dev_err(&pdev->dev, | |
1079 | "%s spi_register_master FAILED\n", __func__); | |
1080 | goto err_spi_reg_master; | |
1081 | } | |
1082 | ||
1083 | dev_dbg(&pdev->dev, "%s spi_register_master returned=%d\n", | |
1084 | __func__, retval); | |
1085 | ||
1086 | ||
1087 | return 0; | |
1088 | ||
1089 | err_spi_reg_master: | |
1090 | spi_unregister_master(master); | |
1091 | err_spi_get_resources: | |
1092 | err_spi_alloc_master: | |
1093 | spi_master_put(master); | |
1094 | pci_disable_device(pdev); | |
1095 | err_pci_en_device: | |
1096 | kfree(board_dat); | |
1097 | err_kmalloc: | |
1098 | return retval; | |
1099 | } | |
1100 | ||
1101 | static void pch_spi_remove(struct pci_dev *pdev) | |
1102 | { | |
1103 | struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev); | |
65308c46 | 1104 | int count; |
e8b17b5b MO |
1105 | |
1106 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | |
1107 | ||
1108 | if (!board_dat) { | |
1109 | dev_err(&pdev->dev, | |
1110 | "%s pci_get_drvdata returned NULL\n", __func__); | |
1111 | return; | |
1112 | } | |
1113 | ||
65308c46 GL |
1114 | /* check for any pending messages; no action is taken if the queue |
1115 | * is still full; but at least we tried. Unload anyway */ | |
1116 | count = 500; | |
1117 | spin_lock(&board_dat->data->lock); | |
1118 | board_dat->data->status = STATUS_EXITING; | |
1119 | while ((list_empty(&board_dat->data->queue) == 0) && --count) { | |
1120 | dev_dbg(&board_dat->pdev->dev, "%s :queue not empty\n", | |
1121 | __func__); | |
1122 | spin_unlock(&board_dat->data->lock); | |
1123 | msleep(PCH_SLEEP_TIME); | |
1124 | spin_lock(&board_dat->data->lock); | |
e8b17b5b | 1125 | } |
65308c46 | 1126 | spin_unlock(&board_dat->data->lock); |
e8b17b5b MO |
1127 | |
1128 | /* Free resources allocated for PCH SPI */ | |
1129 | pch_spi_free_resources(board_dat); | |
1130 | ||
e8b17b5b MO |
1131 | spi_unregister_master(board_dat->data->master); |
1132 | ||
1133 | /* free memory for private data */ | |
1134 | kfree(board_dat); | |
1135 | ||
1136 | pci_set_drvdata(pdev, NULL); | |
1137 | ||
1138 | /* disable PCI device */ | |
1139 | pci_disable_device(pdev); | |
1140 | ||
1141 | dev_dbg(&pdev->dev, "%s invoked pci_disable_device\n", __func__); | |
1142 | } | |
1143 | ||
1144 | #ifdef CONFIG_PM | |
1145 | static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state) | |
1146 | { | |
1147 | u8 count; | |
1148 | int retval; | |
1149 | ||
1150 | struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev); | |
1151 | ||
1152 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | |
1153 | ||
1154 | if (!board_dat) { | |
1155 | dev_err(&pdev->dev, | |
1156 | "%s pci_get_drvdata returned NULL\n", __func__); | |
1157 | return -EFAULT; | |
1158 | } | |
1159 | ||
1160 | retval = 0; | |
1161 | board_dat->suspend_sts = true; | |
1162 | ||
1163 | /* check if the current message is processed: | |
1164 | Only after thats done the transfer will be suspended */ | |
1165 | count = 255; | |
1166 | while ((--count) > 0) { | |
1167 | if (!(board_dat->data->bcurrent_msg_processing)) { | |
1168 | dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_" | |
1169 | "msg_processing = false\n", __func__); | |
1170 | break; | |
1171 | } else { | |
1172 | dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_msg_" | |
1173 | "processing = true\n", __func__); | |
1174 | } | |
1175 | msleep(PCH_SLEEP_TIME); | |
1176 | } | |
1177 | ||
1178 | /* Free IRQ */ | |
1179 | if (board_dat->irq_reg_sts) { | |
1180 | /* disable all interrupts */ | |
65308c46 GL |
1181 | pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0, |
1182 | PCH_ALL); | |
e8b17b5b | 1183 | pch_spi_reset(board_dat->data->master); |
e8b17b5b | 1184 | |
65308c46 | 1185 | free_irq(board_dat->pdev->irq, board_dat); |
e8b17b5b MO |
1186 | |
1187 | board_dat->irq_reg_sts = false; | |
1188 | dev_dbg(&pdev->dev, | |
1189 | "%s free_irq invoked successfully.\n", __func__); | |
1190 | } | |
1191 | ||
1192 | /* save config space */ | |
1193 | retval = pci_save_state(pdev); | |
1194 | ||
1195 | if (retval == 0) { | |
1196 | dev_dbg(&pdev->dev, "%s pci_save_state returned=%d\n", | |
1197 | __func__, retval); | |
1198 | /* disable PM notifications */ | |
1199 | pci_enable_wake(pdev, PCI_D3hot, 0); | |
1200 | dev_dbg(&pdev->dev, | |
1201 | "%s pci_enable_wake invoked successfully\n", __func__); | |
1202 | /* disable PCI device */ | |
1203 | pci_disable_device(pdev); | |
1204 | dev_dbg(&pdev->dev, | |
1205 | "%s pci_disable_device invoked successfully\n", | |
1206 | __func__); | |
1207 | /* move device to D3hot state */ | |
1208 | pci_set_power_state(pdev, PCI_D3hot); | |
1209 | dev_dbg(&pdev->dev, | |
1210 | "%s pci_set_power_state invoked successfully\n", | |
1211 | __func__); | |
1212 | } else { | |
1213 | dev_err(&pdev->dev, "%s pci_save_state failed\n", __func__); | |
1214 | } | |
1215 | ||
1216 | dev_dbg(&pdev->dev, "%s return=%d\n", __func__, retval); | |
1217 | ||
1218 | return retval; | |
1219 | } | |
1220 | ||
1221 | static int pch_spi_resume(struct pci_dev *pdev) | |
1222 | { | |
1223 | int retval; | |
1224 | ||
1225 | struct pch_spi_board_data *board = pci_get_drvdata(pdev); | |
1226 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | |
1227 | ||
1228 | if (!board) { | |
1229 | dev_err(&pdev->dev, | |
1230 | "%s pci_get_drvdata returned NULL\n", __func__); | |
1231 | return -EFAULT; | |
1232 | } | |
1233 | ||
1234 | /* move device to DO power state */ | |
1235 | pci_set_power_state(pdev, PCI_D0); | |
1236 | ||
1237 | /* restore state */ | |
1238 | pci_restore_state(pdev); | |
1239 | ||
1240 | retval = pci_enable_device(pdev); | |
1241 | if (retval < 0) { | |
1242 | dev_err(&pdev->dev, | |
1243 | "%s pci_enable_device failed\n", __func__); | |
1244 | } else { | |
1245 | /* disable PM notifications */ | |
1246 | pci_enable_wake(pdev, PCI_D3hot, 0); | |
1247 | ||
1248 | /* register IRQ handler */ | |
65308c46 | 1249 | if (!board->irq_reg_sts) { |
e8b17b5b MO |
1250 | /* register IRQ */ |
1251 | retval = request_irq(board->pdev->irq, pch_spi_handler, | |
1252 | IRQF_SHARED, KBUILD_MODNAME, | |
1253 | board); | |
1254 | if (retval < 0) { | |
1255 | dev_err(&pdev->dev, | |
1256 | "%s request_irq failed\n", __func__); | |
1257 | return retval; | |
1258 | } | |
1259 | board->irq_reg_sts = true; | |
1260 | ||
1261 | /* reset PCH SPI h/w */ | |
1262 | pch_spi_reset(board->data->master); | |
1263 | pch_spi_set_master_mode(board->data->master); | |
1264 | ||
1265 | /* set suspend status to false */ | |
1266 | board->suspend_sts = false; | |
1267 | ||
1268 | } | |
1269 | } | |
1270 | ||
1271 | dev_dbg(&pdev->dev, "%s returning=%d\n", __func__, retval); | |
1272 | ||
1273 | return retval; | |
1274 | } | |
1275 | #else | |
1276 | #define pch_spi_suspend NULL | |
1277 | #define pch_spi_resume NULL | |
1278 | ||
1279 | #endif | |
1280 | ||
1281 | static struct pci_driver pch_spi_pcidev = { | |
1282 | .name = "pch_spi", | |
1283 | .id_table = pch_spi_pcidev_id, | |
1284 | .probe = pch_spi_probe, | |
1285 | .remove = pch_spi_remove, | |
1286 | .suspend = pch_spi_suspend, | |
1287 | .resume = pch_spi_resume, | |
1288 | }; | |
1289 | ||
1290 | static int __init pch_spi_init(void) | |
1291 | { | |
1292 | return pci_register_driver(&pch_spi_pcidev); | |
1293 | } | |
1294 | module_init(pch_spi_init); | |
1295 | ||
e8b17b5b MO |
1296 | static void __exit pch_spi_exit(void) |
1297 | { | |
1298 | pci_unregister_driver(&pch_spi_pcidev); | |
1299 | } | |
1300 | module_exit(pch_spi_exit); | |
1301 | ||
1302 | MODULE_LICENSE("GPL"); | |
65308c46 | 1303 | MODULE_DESCRIPTION("Topcliff PCH SPI PCI Driver"); |