Blame view
drivers/spi/spi-topcliff-pch.c
45 KB
8e8e69d67 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
e8b17b5b3 spi/topcliff: Add... |
2 3 |
/* * SPI bus driver for the Topcliff PCH used by Intel SoCs |
65308c46b spi/topcliff: cle... |
4 |
* |
2b2462832 spi-topcliff-pch:... |
5 |
* Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. |
e8b17b5b3 spi/topcliff: Add... |
6 |
*/ |
65308c46b spi/topcliff: cle... |
7 |
#include <linux/delay.h> |
e8b17b5b3 spi/topcliff: Add... |
8 9 10 11 12 13 14 15 |
#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 spi/topcliff_pch:... |
16 |
#include <linux/platform_device.h> |
e8b17b5b3 spi/topcliff: Add... |
17 |
|
c37f3c274 spi/topcliff_pch:... |
18 19 |
#include <linux/dmaengine.h> #include <linux/pch_dma.h> |
e8b17b5b3 spi/topcliff: Add... |
20 21 22 23 24 25 26 27 |
/* 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 spi/topcliff_pch:... |
28 |
#define PCH_ADDRESS_SIZE 0x20 |
e8b17b5b3 spi/topcliff: Add... |
29 30 31 32 33 34 35 36 37 |
#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 spi/topcliff: Add... |
38 |
|
f3e03e2eb spi-topcliff-pch:... |
39 |
#define PCH_TX_THOLD 2 |
e8b17b5b3 spi/topcliff: Add... |
40 41 42 43 44 45 |
#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 spi/topcliff: Add... |
46 |
#define SSN_LOW 0x02U |
8b7aa961a spi-topcliff-pch:... |
47 |
#define SSN_HIGH 0x03U |
e8b17b5b3 spi/topcliff: Add... |
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#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 spi/topcliff_pch:... |
66 |
#define SPSR_ORF_BIT (1 << 3) |
e8b17b5b3 spi/topcliff: Add... |
67 |
#define SPBRR_SIZE_BIT (1 << 10) |
f016aeb65 spi/topcliff_pch:... |
68 69 |
#define PCH_ALL (SPCR_TFIE_BIT|SPCR_RFIE_BIT|SPCR_FIE_BIT|\ SPCR_ORIE_BIT|SPCR_MDFIE_BIT) |
65308c46b spi/topcliff: cle... |
70 |
|
e8b17b5b3 spi/topcliff: Add... |
71 72 |
#define SPCR_RFIC_FIELD 20 #define SPCR_TFIC_FIELD 16 |
c37f3c274 spi/topcliff_pch:... |
73 74 75 |
#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 spi/topcliff: Add... |
76 77 78 |
#define PCH_CLOCK_HZ 50000000 #define PCH_MAX_SPBR 1023 |
2b2462832 spi-topcliff-pch:... |
79 |
/* Definition for ML7213/ML7223/ML7831 by LAPIS Semiconductor */ |
f016aeb65 spi/topcliff_pch:... |
80 |
#define PCI_DEVICE_ID_ML7213_SPI 0x802c |
2e2de2e31 spi/topcliff-pch:... |
81 |
#define PCI_DEVICE_ID_ML7223_SPI 0x800F |
92b3a5c1b spi-topcliff-pch:... |
82 |
#define PCI_DEVICE_ID_ML7831_SPI 0x8816 |
f016aeb65 spi/topcliff_pch:... |
83 84 85 86 |
/* * Set the number of SPI instance max * Intel EG20T PCH : 1ch |
2b2462832 spi-topcliff-pch:... |
87 88 89 |
* LAPIS Semiconductor ML7213 IOH : 2ch * LAPIS Semiconductor ML7223 IOH : 1ch * LAPIS Semiconductor ML7831 IOH : 1ch |
f016aeb65 spi/topcliff_pch:... |
90 91 |
*/ #define PCH_SPI_MAX_DEV 2 |
e8b17b5b3 spi/topcliff: Add... |
92 |
|
c37f3c274 spi/topcliff_pch:... |
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
#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 spi/topcliff: Add... |
115 116 117 |
/** * struct pch_spi_data - Holds the SPI channel specific details * @io_remap_addr: The remapped PCI base address |
decf53269 spi: spi-topcliff... |
118 |
* @io_base_addr: Base address |
e8b17b5b3 spi/topcliff: Add... |
119 120 |
* @master: Pointer to the SPI master structure * @work: Reference to work queue handler |
e8b17b5b3 spi/topcliff: Add... |
121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
* @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 |
decf53269 spi: spi-topcliff... |
135 136 |
* @pkt_tx_buff: Buffer for data to be transmitted * @pkt_rx_buff: Buffer for received data |
e8b17b5b3 spi/topcliff: Add... |
137 138 139 140 141 142 143 144 145 |
* @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 spi/topcliff_pch:... |
146 147 |
* @plat_dev: platform_device structure * @ch: SPI channel number |
decf53269 spi: spi-topcliff... |
148 149 |
* @dma: Local DMA information * @use_dma: True if DMA is to be used |
f016aeb65 spi/topcliff_pch:... |
150 |
* @irq_reg_sts: Status of IRQ registration |
decf53269 spi: spi-topcliff... |
151 |
* @save_total_len: Save length while data is being transferred |
e8b17b5b3 spi/topcliff: Add... |
152 153 154 |
*/ struct pch_spi_data { void __iomem *io_remap_addr; |
c37f3c274 spi/topcliff_pch:... |
155 |
unsigned long io_base_addr; |
e8b17b5b3 spi/topcliff: Add... |
156 157 |
struct spi_master *master; struct work_struct work; |
e8b17b5b3 spi/topcliff: Add... |
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
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 spi/topcliff_pch:... |
175 176 |
struct platform_device *plat_dev; int ch; |
c37f3c274 spi/topcliff_pch:... |
177 178 |
struct pch_spi_dma_ctrl dma; int use_dma; |
f016aeb65 spi/topcliff_pch:... |
179 |
u8 irq_reg_sts; |
7d05b3e86 spi-topcliff-pch:... |
180 |
int save_total_len; |
e8b17b5b3 spi/topcliff: Add... |
181 182 183 184 185 |
}; /** * struct pch_spi_board_data - Holds the SPI device specific details * @pdev: Pointer to the PCI device |
e8b17b5b3 spi/topcliff: Add... |
186 |
* @suspend_sts: Status of suspend |
f016aeb65 spi/topcliff_pch:... |
187 |
* @num: The number of SPI device instance |
e8b17b5b3 spi/topcliff: Add... |
188 189 190 |
*/ struct pch_spi_board_data { struct pci_dev *pdev; |
e8b17b5b3 spi/topcliff: Add... |
191 |
u8 suspend_sts; |
f016aeb65 spi/topcliff_pch:... |
192 193 194 195 196 197 198 |
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 spi/topcliff: Add... |
199 |
}; |
9a21e4770 spi: remove DEFIN... |
200 |
static const struct pci_device_id pch_spi_pcidev_id[] = { |
f016aeb65 spi/topcliff_pch:... |
201 202 |
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI), 1, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, }, |
2e2de2e31 spi/topcliff-pch:... |
203 |
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), 1, }, |
92b3a5c1b spi-topcliff-pch:... |
204 |
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_SPI), 1, }, |
f016aeb65 spi/topcliff_pch:... |
205 |
{ } |
e8b17b5b3 spi/topcliff: Add... |
206 |
}; |
e8b17b5b3 spi/topcliff: Add... |
207 208 209 210 211 212 213 214 |
/** * 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 spi/topcliff: Add... |
215 |
struct pch_spi_data *data = spi_master_get_devdata(master); |
e8b17b5b3 spi/topcliff: Add... |
216 217 218 219 220 221 222 223 224 225 226 |
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 spi/topcliff: Add... |
227 228 |
return ioread32(data->io_remap_addr + idx); } |
e8b17b5b3 spi/topcliff: Add... |
229 230 231 232 233 234 235 |
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 spi/topcliff: Add... |
236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
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 spi/topcliff: Add... |
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
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 spi/topcliff: cle... |
285 |
reg_spcr_val &= ~SPCR_RFIE_BIT; /* disable RFI */ |
e8b17b5b3 spi/topcliff: Add... |
286 287 |
/* reset rx threshold */ |
c37f3c274 spi/topcliff_pch:... |
288 |
reg_spcr_val &= ~MASK_RFIC_SPCR_BITS; |
e8b17b5b3 spi/topcliff: Add... |
289 |
reg_spcr_val |= (PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD); |
c37f3c274 spi/topcliff_pch:... |
290 291 |
iowrite32(reg_spcr_val, (io_remap_addr + PCH_SPCR)); |
e8b17b5b3 spi/topcliff: Add... |
292 293 294 295 296 |
} /* update counts */ data->tx_index = tx_index; data->rx_index = rx_index; |
de3bd7e6d spi-topcliff-pch:... |
297 298 299 300 301 302 303 304 305 306 307 308 309 |
/* if transfer complete interrupt */ if (reg_spsr_val & SPSR_FI_BIT) { 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 { |
342451df0 spi: topcliff-pch... |
310 |
dev_vdbg(&data->master->dev, |
de3bd7e6d spi-topcliff-pch:... |
311 312 313 |
"%s : Transfer is not completed", __func__); } |
373b0eb64 spi-topcliff-pch:... |
314 |
} |
e8b17b5b3 spi/topcliff: Add... |
315 316 |
} } |
e8b17b5b3 spi/topcliff: Add... |
317 318 319 320 321 322 323 324 |
/** * 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 spi/topcliff: Add... |
325 326 327 |
void __iomem *spsr; void __iomem *io_remap_addr; irqreturn_t ret = IRQ_NONE; |
f016aeb65 spi/topcliff_pch:... |
328 329 |
struct pch_spi_data *data = dev_id; struct pch_spi_board_data *board_dat = data->board_dat; |
e8b17b5b3 spi/topcliff: Add... |
330 331 332 333 334 335 336 |
if (board_dat->suspend_sts) { dev_dbg(&board_dat->pdev->dev, "%s returning due to suspend ", __func__); return IRQ_NONE; } |
e8b17b5b3 spi/topcliff: Add... |
337 338 339 340 |
io_remap_addr = data->io_remap_addr; spsr = io_remap_addr + PCH_SPSR; reg_spsr_val = ioread32(spsr); |
25e803f9c spi-topcliff-pch:... |
341 342 343 |
if (reg_spsr_val & SPSR_ORF_BIT) { dev_err(&board_dat->pdev->dev, "%s Over run error ", __func__); |
f5d8ee3f1 spi: spi-topcliff... |
344 |
if (data->current_msg->complete) { |
25e803f9c spi-topcliff-pch:... |
345 346 347 348 349 350 351 352 353 354 355 |
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 spi/topcliff_pch:... |
356 |
|
e8b17b5b3 spi/topcliff: Add... |
357 |
/* Check if the interrupt is for SPI device */ |
e8b17b5b3 spi/topcliff: Add... |
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
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 spi/topcliff: cle... |
377 |
u32 n_spbr = PCH_CLOCK_HZ / (speed_hz * 2); |
e8b17b5b3 spi/topcliff: Add... |
378 379 |
/* if baud rate is less than we can support limit it */ |
e8b17b5b3 spi/topcliff: Add... |
380 381 |
if (n_spbr > PCH_MAX_SPBR) n_spbr = PCH_MAX_SPBR; |
c37f3c274 spi/topcliff_pch:... |
382 |
pch_spi_setclr_reg(master, PCH_SPBRR, n_spbr, MASK_SPBRR_SPBR_BITS); |
e8b17b5b3 spi/topcliff: Add... |
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
} /** * 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 spi/topcliff: cle... |
405 |
u32 flags = 0; |
e8b17b5b3 spi/topcliff: Add... |
406 407 408 409 410 |
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 spi/topcliff: Add... |
411 412 413 414 |
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 spi/topcliff: cle... |
415 416 |
if (!(spi->mode & SPI_LSB_FIRST)) flags |= SPCR_LSBF_BIT; |
e8b17b5b3 spi/topcliff: Add... |
417 |
if (spi->mode & SPI_CPOL) |
65308c46b spi/topcliff: cle... |
418 |
flags |= SPCR_CPOL_BIT; |
e8b17b5b3 spi/topcliff: Add... |
419 |
if (spi->mode & SPI_CPHA) |
65308c46b spi/topcliff: cle... |
420 421 422 |
flags |= SPCR_CPHA_BIT; pch_spi_setclr_reg(spi->master, PCH_SPCR, flags, (SPCR_LSBF_BIT | SPCR_CPOL_BIT | SPCR_CPHA_BIT)); |
e8b17b5b3 spi/topcliff: Add... |
423 424 425 426 427 428 |
/* Clear the FIFO by toggling FICLR to 1 and back to 0 */ pch_spi_clear_fifo(spi->master); } /** |
e8b17b5b3 spi/topcliff: Add... |
429 430 431 432 433 434 435 436 437 438 439 |
* 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); } |
e8b17b5b3 spi/topcliff: Add... |
440 441 442 443 444 445 446 |
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; |
c37f3c274 spi/topcliff_pch:... |
447 |
spin_lock_irqsave(&data->lock, flags); |
e8b17b5b3 spi/topcliff: Add... |
448 449 |
/* validate Tx/Rx buffers and Transfer length */ list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { |
65308c46b spi/topcliff: cle... |
450 |
if (!transfer->tx_buf && !transfer->rx_buf) { |
e8b17b5b3 spi/topcliff: Add... |
451 452 453 454 |
dev_err(&pspi->dev, "%s Tx and Rx buffer NULL ", __func__); retval = -EINVAL; |
c37f3c274 spi/topcliff_pch:... |
455 |
goto err_return_spinlock; |
e8b17b5b3 spi/topcliff: Add... |
456 |
} |
65308c46b spi/topcliff: cle... |
457 |
if (!transfer->len) { |
e8b17b5b3 spi/topcliff: Add... |
458 459 460 461 |
dev_err(&pspi->dev, "%s Transfer length invalid ", __func__); retval = -EINVAL; |
c37f3c274 spi/topcliff_pch:... |
462 |
goto err_return_spinlock; |
e8b17b5b3 spi/topcliff: Add... |
463 |
} |
f6bd03a74 spi: Don't break ... |
464 465 466 467 |
dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length valid ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
468 |
} |
c37f3c274 spi/topcliff_pch:... |
469 |
spin_unlock_irqrestore(&data->lock, flags); |
e8b17b5b3 spi/topcliff: Add... |
470 |
|
65308c46b spi/topcliff: cle... |
471 472 |
/* We won't process any messages if we have been asked to terminate */ if (data->status == STATUS_EXITING) { |
e8b17b5b3 spi/topcliff: Add... |
473 474 475 |
dev_err(&pspi->dev, "%s status = STATUS_EXITING. ", __func__); retval = -ESHUTDOWN; |
c37f3c274 spi/topcliff_pch:... |
476 |
goto err_out; |
e8b17b5b3 spi/topcliff: Add... |
477 478 479 480 |
} /* If suspended ,return -EINVAL */ if (data->board_dat->suspend_sts) { |
65308c46b spi/topcliff: cle... |
481 482 |
dev_err(&pspi->dev, "%s suspend; returning EINVAL ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
483 |
retval = -EINVAL; |
c37f3c274 spi/topcliff_pch:... |
484 |
goto err_out; |
e8b17b5b3 spi/topcliff: Add... |
485 486 487 488 |
} /* set status of message */ pmsg->actual_length = 0; |
e8b17b5b3 spi/topcliff: Add... |
489 490 491 492 |
dev_dbg(&pspi->dev, "%s - pmsg->status =%d ", __func__, pmsg->status); pmsg->status = -EINPROGRESS; |
c37f3c274 spi/topcliff_pch:... |
493 |
spin_lock_irqsave(&data->lock, flags); |
e8b17b5b3 spi/topcliff: Add... |
494 495 |
/* add message to queue */ list_add_tail(&pmsg->queue, &data->queue); |
c37f3c274 spi/topcliff_pch:... |
496 |
spin_unlock_irqrestore(&data->lock, flags); |
e8b17b5b3 spi/topcliff: Add... |
497 498 |
dev_dbg(&pspi->dev, "%s - Invoked list_add_tail ", __func__); |
0d3577397 spi: spi-topcliff... |
499 |
schedule_work(&data->work); |
e8b17b5b3 spi/topcliff: Add... |
500 501 502 503 |
dev_dbg(&pspi->dev, "%s - Invoked queue work ", __func__); retval = 0; |
e8b17b5b3 spi/topcliff: Add... |
504 505 506 507 |
err_out: dev_dbg(&pspi->dev, "%s RETURN=%d ", __func__, retval); return retval; |
c37f3c274 spi/topcliff_pch:... |
508 509 510 511 512 |
err_return_spinlock: dev_dbg(&pspi->dev, "%s RETURN=%d ", __func__, retval); spin_unlock_irqrestore(&data->lock, flags); return retval; |
e8b17b5b3 spi/topcliff: Add... |
513 514 515 516 517 |
} static inline void pch_spi_select_chip(struct pch_spi_data *data, struct spi_device *pspi) { |
65308c46b spi/topcliff: cle... |
518 519 520 521 |
if (data->current_chip != NULL) { if (pspi->chip_select != data->n_curnt_chip) { dev_dbg(&pspi->dev, "%s : different slave ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
522 523 524 525 526 527 528 529 530 531 532 533 |
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 spi/topcliff_pch:... |
534 |
static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw) |
e8b17b5b3 spi/topcliff: Add... |
535 |
{ |
e8b17b5b3 spi/topcliff: Add... |
536 537 538 |
int size; u32 n_writes; int j; |
cd8d984f0 spi-topcliff-pch:... |
539 |
struct spi_message *pmsg, *tmp; |
e8b17b5b3 spi/topcliff: Add... |
540 541 |
const u8 *tx_buf; const u16 *tx_sbuf; |
e8b17b5b3 spi/topcliff: Add... |
542 543 |
/* set baud rate if needed */ if (data->cur_trans->speed_hz) { |
65308c46b spi/topcliff: cle... |
544 545 546 |
dev_dbg(&data->master->dev, "%s:setting baud rate ", __func__); pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz); |
e8b17b5b3 spi/topcliff: Add... |
547 548 549 |
} /* set bits per word if needed */ |
65308c46b spi/topcliff: cle... |
550 551 552 553 |
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 spi/topcliff: Add... |
554 |
pch_spi_set_bits_per_word(data->master, |
65308c46b spi/topcliff: cle... |
555 |
data->cur_trans->bits_per_word); |
e8b17b5b3 spi/topcliff: Add... |
556 557 558 559 560 561 562 563 564 565 |
*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 spi/topcliff: Add... |
566 567 |
/* find alloc size */ |
65308c46b spi/topcliff: cle... |
568 |
size = data->cur_trans->len * sizeof(*data->pkt_tx_buff); |
e8b17b5b3 spi/topcliff: Add... |
569 570 |
/* allocate memory for pkt_tx_buff & pkt_rx_buffer */ data->pkt_tx_buff = kzalloc(size, GFP_KERNEL); |
e8b17b5b3 spi/topcliff: Add... |
571 572 |
if (data->pkt_tx_buff != NULL) { data->pkt_rx_buff = kzalloc(size, GFP_KERNEL); |
65308c46b spi/topcliff: cle... |
573 |
if (!data->pkt_rx_buff) |
e8b17b5b3 spi/topcliff: Add... |
574 |
kfree(data->pkt_tx_buff); |
e8b17b5b3 spi/topcliff: Add... |
575 |
} |
65308c46b spi/topcliff: cle... |
576 |
if (!data->pkt_rx_buff) { |
e8b17b5b3 spi/topcliff: Add... |
577 |
/* flush queue and set status of all transfers to -ENOMEM */ |
cd8d984f0 spi-topcliff-pch:... |
578 |
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) { |
e8b17b5b3 spi/topcliff: Add... |
579 |
pmsg->status = -ENOMEM; |
f5d8ee3f1 spi: spi-topcliff... |
580 |
if (pmsg->complete) |
e8b17b5b3 spi/topcliff: Add... |
581 582 583 584 585 |
pmsg->complete(pmsg->context); /* delete from queue */ list_del_init(&pmsg->queue); } |
e8b17b5b3 spi/topcliff: Add... |
586 587 588 589 |
return; } /* copy Tx Data */ |
65308c46b spi/topcliff: cle... |
590 |
if (data->cur_trans->tx_buf != NULL) { |
e8b17b5b3 spi/topcliff: Add... |
591 |
if (*bpw == 8) { |
65308c46b spi/topcliff: cle... |
592 593 594 |
tx_buf = data->cur_trans->tx_buf; for (j = 0; j < data->bpw_len; j++) data->pkt_tx_buff[j] = *tx_buf++; |
e8b17b5b3 spi/topcliff: Add... |
595 |
} else { |
65308c46b spi/topcliff: cle... |
596 597 598 |
tx_sbuf = data->cur_trans->tx_buf; for (j = 0; j < data->bpw_len; j++) data->pkt_tx_buff[j] = *tx_sbuf++; |
e8b17b5b3 spi/topcliff: Add... |
599 600 601 602 |
} } /* if len greater than PCH_MAX_FIFO_DEPTH, write 16,else len bytes */ |
65308c46b spi/topcliff: cle... |
603 604 |
n_writes = data->bpw_len; if (n_writes > PCH_MAX_FIFO_DEPTH) |
e8b17b5b3 spi/topcliff: Add... |
605 |
n_writes = PCH_MAX_FIFO_DEPTH; |
e8b17b5b3 spi/topcliff: Add... |
606 |
|
b996356d3 spi/topcliff-pch:... |
607 608 609 610 611 |
dev_dbg(&data->master->dev, " %s:Pulling down SSN low - writing 0x2 to SSNXCR ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
612 |
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); |
65308c46b spi/topcliff: cle... |
613 614 |
for (j = 0; j < n_writes; j++) pch_spi_writereg(data->master, PCH_SPDWR, data->pkt_tx_buff[j]); |
e8b17b5b3 spi/topcliff: Add... |
615 616 617 618 619 620 621 622 |
/* update tx_index */ data->tx_index = j; /* reset transfer complete flag */ data->transfer_complete = false; data->transfer_active = true; } |
c37f3c274 spi/topcliff_pch:... |
623 |
static void pch_spi_nomore_transfer(struct pch_spi_data *data) |
e8b17b5b3 spi/topcliff: Add... |
624 |
{ |
cd8d984f0 spi-topcliff-pch:... |
625 |
struct spi_message *pmsg, *tmp; |
65308c46b spi/topcliff: cle... |
626 627 |
dev_dbg(&data->master->dev, "%s called ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
628 |
/* Invoke complete callback |
65308c46b spi/topcliff: cle... |
629 |
* [To the spi core..indicating end of transfer] */ |
e8b17b5b3 spi/topcliff: Add... |
630 |
data->current_msg->status = 0; |
f5d8ee3f1 spi: spi-topcliff... |
631 |
if (data->current_msg->complete) { |
e8b17b5b3 spi/topcliff: Add... |
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 |
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 spi/topcliff: cle... |
647 648 |
/* check if we have items in list and not suspending * return 1 if list empty */ |
e8b17b5b3 spi/topcliff: Add... |
649 |
if ((list_empty(&data->queue) == 0) && |
65308c46b spi/topcliff: cle... |
650 651 |
(!data->board_dat->suspend_sts) && (data->status != STATUS_EXITING)) { |
e8b17b5b3 spi/topcliff: Add... |
652 |
/* We have some more work to do (either there is more tranint |
65308c46b spi/topcliff: cle... |
653 654 655 656 657 |
* bpw;sfer requests in the current message or there are *more messages) */ dev_dbg(&data->master->dev, "%s:Invoke queue_work ", __func__); |
0d3577397 spi: spi-topcliff... |
658 |
schedule_work(&data->work); |
65308c46b spi/topcliff: cle... |
659 660 |
} else if (data->board_dat->suspend_sts || data->status == STATUS_EXITING) { |
e8b17b5b3 spi/topcliff: Add... |
661 662 663 664 |
dev_dbg(&data->master->dev, "%s suspend/remove initiated, flushing queue ", __func__); |
cd8d984f0 spi-topcliff-pch:... |
665 |
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) { |
e8b17b5b3 spi/topcliff: Add... |
666 |
pmsg->status = -EIO; |
65308c46b spi/topcliff: cle... |
667 |
if (pmsg->complete) |
e8b17b5b3 spi/topcliff: Add... |
668 669 670 671 672 673 674 675 676 677 |
pmsg->complete(pmsg->context); /* delete from queue */ list_del_init(&pmsg->queue); } } } static void pch_spi_set_ir(struct pch_spi_data *data) { |
c37f3c274 spi/topcliff_pch:... |
678 679 |
/* enable interrupts, set threshold, enable SPI */ if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) |
77e58efd1 spi/topcliff: Typ... |
680 |
/* set receive threshold to PCH_RX_THOLD */ |
65308c46b spi/topcliff: cle... |
681 |
pch_spi_setclr_reg(data->master, PCH_SPCR, |
c37f3c274 spi/topcliff_pch:... |
682 683 684 685 686 |
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 spi/topcliff: Typ... |
687 |
/* set receive threshold to maximum */ |
65308c46b spi/topcliff: cle... |
688 |
pch_spi_setclr_reg(data->master, PCH_SPCR, |
c37f3c274 spi/topcliff_pch:... |
689 690 691 692 |
PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD | SPCR_FIE_BIT | SPCR_ORIE_BIT | SPCR_SPE_BIT, MASK_RFIC_SPCR_BITS | PCH_ALL); |
e8b17b5b3 spi/topcliff: Add... |
693 694 695 696 697 698 699 700 |
/* 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 spi/topcliff: Add... |
701 702 |
/* clear all interrupts */ pch_spi_writereg(data->master, PCH_SPSR, |
65308c46b spi/topcliff: cle... |
703 |
pch_spi_readreg(data->master, PCH_SPSR)); |
c37f3c274 spi/topcliff_pch:... |
704 705 706 707 |
/* 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 spi/topcliff: Add... |
708 709 710 711 712 713 714 715 716 |
} 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 spi/topcliff: cle... |
717 |
if (!data->cur_trans->rx_buf) |
e8b17b5b3 spi/topcliff: Add... |
718 719 720 |
return; if (bpw == 8) { |
65308c46b spi/topcliff: cle... |
721 722 723 |
rx_buf = data->cur_trans->rx_buf; for (j = 0; j < data->bpw_len; j++) *rx_buf++ = data->pkt_rx_buff[j] & 0xFF; |
e8b17b5b3 spi/topcliff: Add... |
724 |
} else { |
65308c46b spi/topcliff: cle... |
725 726 727 |
rx_sbuf = data->cur_trans->rx_buf; for (j = 0; j < data->bpw_len; j++) *rx_sbuf++ = data->pkt_rx_buff[j]; |
e8b17b5b3 spi/topcliff: Add... |
728 729 |
} } |
c37f3c274 spi/topcliff_pch:... |
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 |
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; |
7d05b3e86 spi-topcliff-pch:... |
747 |
data->cur_trans->rx_buf = rx_buf; |
c37f3c274 spi/topcliff_pch:... |
748 749 750 751 752 |
} 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++; |
7d05b3e86 spi-topcliff-pch:... |
753 |
data->cur_trans->rx_buf = rx_sbuf; |
c37f3c274 spi/topcliff_pch:... |
754 755 |
} } |
25e803f9c spi-topcliff-pch:... |
756 |
static int pch_spi_start_transfer(struct pch_spi_data *data) |
c37f3c274 spi/topcliff_pch:... |
757 758 759 |
{ struct pch_spi_dma_ctrl *dma; unsigned long flags; |
25e803f9c spi-topcliff-pch:... |
760 |
int rtn; |
c37f3c274 spi/topcliff_pch:... |
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 |
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 spi-topcliff-pch:... |
776 777 778 |
rtn = wait_event_interruptible_timeout(data->wait, data->transfer_complete, msecs_to_jiffies(2 * HZ)); |
7d05b3e86 spi-topcliff-pch:... |
779 780 781 782 |
if (!rtn) dev_err(&data->master->dev, "%s wait-event timeout ", __func__); |
c37f3c274 spi/topcliff_pch:... |
783 784 785 |
dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, DMA_FROM_DEVICE); |
27504be5c spi-topcliff-pch:... |
786 787 788 789 |
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 spi/topcliff_pch:... |
790 791 792 793 794 795 |
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 spi/topcliff_pch:... |
796 797 798 799 800 801 802 803 804 805 806 807 |
/* 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 spi-topcliff-pch:... |
808 809 |
return rtn; |
c37f3c274 spi/topcliff_pch:... |
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 |
} 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 */ |
a9082105b spi: topcliff-pch... |
853 854 |
dma_dev = pci_get_slot(data->board_dat->pdev->bus, PCI_DEVFN(PCI_SLOT(data->board_dat->pdev->devfn), 0)); |
c37f3c274 spi/topcliff_pch:... |
855 856 857 858 |
/* Set Tx DMA */ param = &dma->param_tx; param->dma_dev = &dma_dev->dev; |
10e413faa spi/topcliff-pch:... |
859 |
param->chan_id = data->ch * 2; /* Tx = 0, 2 */ |
c37f3c274 spi/topcliff_pch:... |
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 |
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; |
10e413faa spi/topcliff-pch:... |
875 |
param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */ |
c37f3c274 spi/topcliff_pch:... |
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 |
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; } |
c37f3c274 spi/topcliff_pch:... |
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
} 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; |
7d05b3e86 spi-topcliff-pch:... |
919 |
int head; |
c37f3c274 spi/topcliff_pch:... |
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 |
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); |
7d05b3e86 spi-topcliff-pch:... |
949 950 951 952 |
if (data->bpw_len > PCH_BUF_SIZE) { data->bpw_len = PCH_BUF_SIZE; data->cur_trans->len -= PCH_BUF_SIZE; } |
c37f3c274 spi/topcliff_pch:... |
953 954 955 956 957 958 959 960 961 962 963 964 965 966 |
/* 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++; } } |
7d05b3e86 spi-topcliff-pch:... |
967 968 |
/* Calculate Rx parameter for DMA transmitting */ |
c37f3c274 spi/topcliff_pch:... |
969 |
if (data->bpw_len > PCH_DMA_TRANS_SIZE) { |
7d05b3e86 spi-topcliff-pch:... |
970 971 972 973 974 975 976 |
if (data->bpw_len % PCH_DMA_TRANS_SIZE) { num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; rem = data->bpw_len % PCH_DMA_TRANS_SIZE; } else { num = data->bpw_len / PCH_DMA_TRANS_SIZE; rem = PCH_DMA_TRANS_SIZE; } |
c37f3c274 spi/topcliff_pch:... |
977 |
size = PCH_DMA_TRANS_SIZE; |
c37f3c274 spi/topcliff_pch:... |
978 979 980 981 982 983 984 985 986 987 988 989 990 |
} 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 spi-topcliff-pch:... |
991 |
(PCH_TX_THOLD << SPCR_TFIC_FIELD), |
c37f3c274 spi/topcliff_pch:... |
992 993 994 995 996 |
MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS); spin_unlock_irqrestore(&data->lock, flags); /* RX */ |
ca03dba30 spi/topcliff-pch:... |
997 |
dma->sg_rx_p = kmalloc_array(num, sizeof(*dma->sg_rx_p), GFP_ATOMIC); |
e902cdcb5 spi/topcliff_pch:... |
998 999 |
if (!dma->sg_rx_p) return; |
c37f3c274 spi/topcliff_pch:... |
1000 1001 1002 1003 |
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 spi-topcliff-pch:... |
1004 1005 1006 |
if (i == (num - 2)) { sg->offset = size * i; sg->offset = sg->offset * (*bpw / 8); |
c37f3c274 spi/topcliff_pch:... |
1007 1008 1009 |
sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem, sg->offset); sg_dma_len(sg) = rem; |
f3e03e2eb spi-topcliff-pch:... |
1010 1011 1012 1013 1014 1015 |
} 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 spi/topcliff_pch:... |
1016 |
} else { |
f3e03e2eb spi-topcliff-pch:... |
1017 |
sg->offset = size * i; |
c37f3c274 spi/topcliff_pch:... |
1018 1019 1020 1021 1022 1023 1024 1025 |
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; |
16052827d dmaengine/dma_sla... |
1026 |
desc_rx = dmaengine_prep_slave_sg(dma->chan_rx, sg, |
a485df4b4 spi, serial: move... |
1027 |
num, DMA_DEV_TO_MEM, |
c37f3c274 spi/topcliff_pch:... |
1028 1029 |
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_rx) { |
2857d80ac spi: topcliff-pch... |
1030 1031 1032 |
dev_err(&data->master->dev, "%s:dmaengine_prep_slave_sg Failed ", __func__); |
c37f3c274 spi/topcliff_pch:... |
1033 1034 1035 1036 1037 1038 1039 |
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; |
7d05b3e86 spi-topcliff-pch:... |
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 |
/* Calculate Tx parameter for DMA transmitting */ if (data->bpw_len > PCH_MAX_FIFO_DEPTH) { head = PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE; if (data->bpw_len % PCH_DMA_TRANS_SIZE > 4) { num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; rem = data->bpw_len % PCH_DMA_TRANS_SIZE - head; } else { num = data->bpw_len / PCH_DMA_TRANS_SIZE; rem = data->bpw_len % PCH_DMA_TRANS_SIZE + PCH_DMA_TRANS_SIZE - head; } |
f3e03e2eb spi-topcliff-pch:... |
1051 |
size = PCH_DMA_TRANS_SIZE; |
f3e03e2eb spi-topcliff-pch:... |
1052 1053 1054 1055 |
} else { num = 1; size = data->bpw_len; rem = data->bpw_len; |
7d05b3e86 spi-topcliff-pch:... |
1056 |
head = 0; |
f3e03e2eb spi-topcliff-pch:... |
1057 |
} |
ca03dba30 spi/topcliff-pch:... |
1058 |
dma->sg_tx_p = kmalloc_array(num, sizeof(*dma->sg_tx_p), GFP_ATOMIC); |
e902cdcb5 spi/topcliff_pch:... |
1059 1060 |
if (!dma->sg_tx_p) return; |
c37f3c274 spi/topcliff_pch:... |
1061 1062 1063 1064 1065 1066 |
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; |
7d05b3e86 spi-topcliff-pch:... |
1067 1068 1069 1070 1071 1072 |
sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size + head, sg->offset); sg_dma_len(sg) = size + head; } else if (i == (num - 1)) { sg->offset = head + size * i; sg->offset = sg->offset * (*bpw / 8); |
c37f3c274 spi/topcliff_pch:... |
1073 1074 1075 1076 |
sg_set_page(sg, virt_to_page(dma->tx_buf_virt), rem, sg->offset); sg_dma_len(sg) = rem; } else { |
7d05b3e86 spi-topcliff-pch:... |
1077 |
sg->offset = head + size * i; |
c37f3c274 spi/topcliff_pch:... |
1078 1079 1080 1081 1082 1083 1084 1085 |
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; |
16052827d dmaengine/dma_sla... |
1086 |
desc_tx = dmaengine_prep_slave_sg(dma->chan_tx, |
a485df4b4 spi, serial: move... |
1087 |
sg, num, DMA_MEM_TO_DEV, |
c37f3c274 spi/topcliff_pch:... |
1088 1089 |
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc_tx) { |
2857d80ac spi: topcliff-pch... |
1090 1091 1092 |
dev_err(&data->master->dev, "%s:dmaengine_prep_slave_sg Failed ", __func__); |
c37f3c274 spi/topcliff_pch:... |
1093 1094 1095 1096 1097 1098 1099 |
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; |
c1b20aa5d spi/topcliff-pch:... |
1100 1101 |
dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR ", __func__); |
c37f3c274 spi/topcliff_pch:... |
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 |
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 spi/topcliff: Add... |
1112 1113 1114 |
static void pch_spi_process_messages(struct work_struct *pwork) { |
cd8d984f0 spi-topcliff-pch:... |
1115 |
struct spi_message *pmsg, *tmp; |
65308c46b spi/topcliff: cle... |
1116 |
struct pch_spi_data *data; |
e8b17b5b3 spi/topcliff: Add... |
1117 |
int bpw; |
65308c46b spi/topcliff: cle... |
1118 |
data = container_of(pwork, struct pch_spi_data, work); |
8e41b527f spi/topcliff: Fix... |
1119 1120 |
dev_dbg(&data->master->dev, "%s data initialized ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
1121 1122 |
spin_lock(&data->lock); |
e8b17b5b3 spi/topcliff: Add... |
1123 |
/* check if suspend has been initiated;if yes flush queue */ |
65308c46b spi/topcliff: cle... |
1124 |
if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) { |
f6bd03a74 spi: Don't break ... |
1125 1126 1127 |
dev_dbg(&data->master->dev, "%s suspend/remove initiated, flushing queue ", __func__); |
cd8d984f0 spi-topcliff-pch:... |
1128 |
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) { |
e8b17b5b3 spi/topcliff: Add... |
1129 |
pmsg->status = -EIO; |
f5d8ee3f1 spi: spi-topcliff... |
1130 |
if (pmsg->complete) { |
e8b17b5b3 spi/topcliff: Add... |
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 |
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 spi/topcliff: cle... |
1150 1151 |
data->current_msg = list_entry(data->queue.next, struct spi_message, queue); |
e8b17b5b3 spi/topcliff: Add... |
1152 1153 1154 1155 1156 1157 1158 1159 |
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 spi/topcliff_pch:... |
1160 1161 1162 |
if (data->use_dma) pch_spi_request_dma(data, data->current_msg->spi->bits_per_word); |
8b7aa961a spi-topcliff-pch:... |
1163 |
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); |
e8b17b5b3 spi/topcliff: Add... |
1164 |
do { |
7d05b3e86 spi-topcliff-pch:... |
1165 |
int cnt; |
e8b17b5b3 spi/topcliff: Add... |
1166 1167 1168 1169 |
/* 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 spi/topcliff: Add... |
1170 1171 |
if (data->cur_trans == NULL) { data->cur_trans = |
c37f3c274 spi/topcliff_pch:... |
1172 1173 |
list_entry(data->current_msg->transfers.next, struct spi_transfer, transfer_list); |
b996356d3 spi/topcliff-pch:... |
1174 1175 1176 1177 |
dev_dbg(&data->master->dev, "%s :Getting 1st transfer message ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
1178 1179 |
} else { data->cur_trans = |
c37f3c274 spi/topcliff_pch:... |
1180 1181 |
list_entry(data->cur_trans->transfer_list.next, struct spi_transfer, transfer_list); |
b996356d3 spi/topcliff-pch:... |
1182 1183 1184 1185 |
dev_dbg(&data->master->dev, "%s :Getting next transfer message ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
1186 |
} |
e8b17b5b3 spi/topcliff: Add... |
1187 |
spin_unlock(&data->lock); |
7d05b3e86 spi-topcliff-pch:... |
1188 1189 1190 1191 |
if (!data->cur_trans->len) goto out; cnt = (data->cur_trans->len - 1) / PCH_BUF_SIZE + 1; data->save_total_len = data->cur_trans->len; |
c37f3c274 spi/topcliff_pch:... |
1192 |
if (data->use_dma) { |
7d05b3e86 spi-topcliff-pch:... |
1193 1194 1195 1196 |
int i; char *save_rx_buf = data->cur_trans->rx_buf; for (i = 0; i < cnt; i ++) { pch_spi_handle_dma(data, &bpw); |
0f57e168a spi-topcliff-pch:... |
1197 1198 1199 1200 1201 1202 1203 1204 |
if (!pch_spi_start_transfer(data)) { 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; |
7d05b3e86 spi-topcliff-pch:... |
1205 |
goto out; |
0f57e168a spi-topcliff-pch:... |
1206 |
} |
7d05b3e86 spi-topcliff-pch:... |
1207 1208 1209 |
pch_spi_copy_rx_data_for_dma(data, bpw); } data->cur_trans->rx_buf = save_rx_buf; |
c37f3c274 spi/topcliff_pch:... |
1210 1211 1212 1213 1214 1215 1216 1217 1218 |
} 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 spi/topcliff: Add... |
1219 |
/* increment message count */ |
7d05b3e86 spi-topcliff-pch:... |
1220 |
data->cur_trans->len = data->save_total_len; |
e8b17b5b3 spi/topcliff: Add... |
1221 1222 1223 1224 1225 1226 |
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); |
e74dc5c76 spi: use new `spi... |
1227 |
spi_transfer_delay_exec(data->cur_trans); |
e8b17b5b3 spi/topcliff: Add... |
1228 1229 1230 1231 1232 1233 |
spin_lock(&data->lock); /* No more transfer in this message. */ if ((data->cur_trans->transfer_list.next) == &(data->current_msg->transfers)) { |
c37f3c274 spi/topcliff_pch:... |
1234 |
pch_spi_nomore_transfer(data); |
e8b17b5b3 spi/topcliff: Add... |
1235 1236 1237 |
} spin_unlock(&data->lock); |
65308c46b spi/topcliff: cle... |
1238 |
} while (data->cur_trans != NULL); |
c37f3c274 spi/topcliff_pch:... |
1239 |
|
25e803f9c spi-topcliff-pch:... |
1240 |
out: |
8b7aa961a spi-topcliff-pch:... |
1241 |
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); |
c37f3c274 spi/topcliff_pch:... |
1242 1243 |
if (data->use_dma) pch_spi_release_dma(data); |
e8b17b5b3 spi/topcliff: Add... |
1244 |
} |
f016aeb65 spi/topcliff_pch:... |
1245 1246 |
static void pch_spi_free_resources(struct pch_spi_board_data *board_dat, struct pch_spi_data *data) |
e8b17b5b3 spi/topcliff: Add... |
1247 1248 1249 |
{ dev_dbg(&board_dat->pdev->dev, "%s ENTRY ", __func__); |
0d3577397 spi: spi-topcliff... |
1250 |
flush_work(&data->work); |
e8b17b5b3 spi/topcliff: Add... |
1251 |
} |
f016aeb65 spi/topcliff_pch:... |
1252 1253 |
static int pch_spi_get_resources(struct pch_spi_board_data *board_dat, struct pch_spi_data *data) |
e8b17b5b3 spi/topcliff: Add... |
1254 |
{ |
e8b17b5b3 spi/topcliff: Add... |
1255 1256 |
dev_dbg(&board_dat->pdev->dev, "%s ENTRY ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
1257 |
/* reset PCH SPI h/w */ |
f016aeb65 spi/topcliff_pch:... |
1258 |
pch_spi_reset(data->master); |
e8b17b5b3 spi/topcliff: Add... |
1259 1260 1261 |
dev_dbg(&board_dat->pdev->dev, "%s pch_spi_reset invoked successfully ", __func__); |
65308c46b spi/topcliff: cle... |
1262 1263 |
dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
1264 |
|
9677e7dd1 spi: spi-topcliff... |
1265 |
return 0; |
e8b17b5b3 spi/topcliff: Add... |
1266 |
} |
c37f3c274 spi/topcliff_pch:... |
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 |
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); |
c37f3c274 spi/topcliff_pch:... |
1279 |
} |
f37d8e67f spi : spi-topclif... |
1280 |
static int pch_alloc_dma_buf(struct pch_spi_board_data *board_dat, |
c37f3c274 spi/topcliff_pch:... |
1281 1282 1283 |
struct pch_spi_data *data) { struct pch_spi_dma_ctrl *dma; |
f37d8e67f spi : spi-topclif... |
1284 |
int ret; |
c37f3c274 spi/topcliff_pch:... |
1285 1286 |
dma = &data->dma; |
f37d8e67f spi : spi-topclif... |
1287 |
ret = 0; |
c37f3c274 spi/topcliff_pch:... |
1288 1289 1290 |
/* 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); |
f37d8e67f spi : spi-topclif... |
1291 1292 |
if (!dma->tx_buf_virt) ret = -ENOMEM; |
c37f3c274 spi/topcliff_pch:... |
1293 1294 1295 |
/* 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); |
f37d8e67f spi : spi-topclif... |
1296 1297 1298 1299 |
if (!dma->rx_buf_virt) ret = -ENOMEM; return ret; |
c37f3c274 spi/topcliff_pch:... |
1300 |
} |
fd4a319bc spi: Remove HOTPL... |
1301 |
static int pch_spi_pd_probe(struct platform_device *plat_dev) |
e8b17b5b3 spi/topcliff: Add... |
1302 |
{ |
f016aeb65 spi/topcliff_pch:... |
1303 |
int ret; |
e8b17b5b3 spi/topcliff: Add... |
1304 |
struct spi_master *master; |
f016aeb65 spi/topcliff_pch:... |
1305 1306 |
struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev); struct pch_spi_data *data; |
e8b17b5b3 spi/topcliff: Add... |
1307 |
|
c37f3c274 spi/topcliff_pch:... |
1308 1309 |
dev_dbg(&plat_dev->dev, "%s:debug ", __func__); |
f016aeb65 spi/topcliff_pch:... |
1310 1311 1312 1313 1314 1315 1316 |
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 spi/topcliff: Add... |
1317 |
} |
f016aeb65 spi/topcliff_pch:... |
1318 1319 |
data = spi_master_get_devdata(master); data->master = master; |
e8b17b5b3 spi/topcliff: Add... |
1320 |
|
f016aeb65 spi/topcliff_pch:... |
1321 |
platform_set_drvdata(plat_dev, data); |
e8b17b5b3 spi/topcliff: Add... |
1322 |
|
c37f3c274 spi/topcliff_pch:... |
1323 1324 1325 |
/* baseaddress + address offset) */ data->io_base_addr = pci_resource_start(board_dat->pdev, 1) + PCH_ADDRESS_SIZE * plat_dev->id; |
9553821ea spi: spi-topcliff... |
1326 |
data->io_remap_addr = pci_iomap(board_dat->pdev, 1, 0); |
f016aeb65 spi/topcliff_pch:... |
1327 1328 1329 1330 1331 |
if (!data->io_remap_addr) { dev_err(&plat_dev->dev, "%s pci_iomap failed ", __func__); ret = -ENOMEM; goto err_pci_iomap; |
e8b17b5b3 spi/topcliff: Add... |
1332 |
} |
9553821ea spi: spi-topcliff... |
1333 |
data->io_remap_addr += PCH_ADDRESS_SIZE * plat_dev->id; |
e8b17b5b3 spi/topcliff: Add... |
1334 |
|
f016aeb65 spi/topcliff_pch:... |
1335 1336 1337 |
dev_dbg(&plat_dev->dev, "[ch%d] remap_addr=%p ", plat_dev->id, data->io_remap_addr); |
e8b17b5b3 spi/topcliff: Add... |
1338 1339 |
/* initialize members of SPI master */ |
e8b17b5b3 spi/topcliff: Add... |
1340 |
master->num_chipselect = PCH_MAX_CS; |
e8b17b5b3 spi/topcliff: Add... |
1341 |
master->transfer = pch_spi_transfer; |
f258b44e2 spi-topcliff-pch:... |
1342 |
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; |
24778be20 spi: convert driv... |
1343 |
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); |
fe3a1ad0c spi: topcliff-pch... |
1344 |
master->max_speed_hz = PCH_MAX_BAUDRATE; |
e8b17b5b3 spi/topcliff: Add... |
1345 |
|
f016aeb65 spi/topcliff_pch:... |
1346 1347 1348 1349 1350 |
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 spi/topcliff_pch:... |
1351 |
data->use_dma = use_dma; |
e8b17b5b3 spi/topcliff: Add... |
1352 |
|
f016aeb65 spi/topcliff_pch:... |
1353 1354 1355 1356 |
INIT_LIST_HEAD(&data->queue); spin_lock_init(&data->lock); INIT_WORK(&data->work, pch_spi_process_messages); init_waitqueue_head(&data->wait); |
65308c46b spi/topcliff: cle... |
1357 |
|
f016aeb65 spi/topcliff_pch:... |
1358 1359 1360 1361 |
ret = pch_spi_get_resources(board_dat, data); if (ret) { dev_err(&plat_dev->dev, "%s fail(retval=%d) ", __func__, ret); |
e8b17b5b3 spi/topcliff: Add... |
1362 1363 |
goto err_spi_get_resources; } |
f016aeb65 spi/topcliff_pch:... |
1364 1365 1366 1367 1368 1369 1370 1371 1372 |
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 spi/topcliff: Add... |
1373 |
|
e8b17b5b3 spi/topcliff: Add... |
1374 |
pch_spi_set_master_mode(master); |
e8b17b5b3 spi/topcliff: Add... |
1375 |
|
7995d74ab spi-topcliff-pch:... |
1376 1377 1378 |
if (use_dma) { dev_info(&plat_dev->dev, "Use DMA for data transfers "); |
f37d8e67f spi : spi-topclif... |
1379 1380 1381 |
ret = pch_alloc_dma_buf(board_dat, data); if (ret) goto err_spi_register_master; |
7995d74ab spi-topcliff-pch:... |
1382 |
} |
f016aeb65 spi/topcliff_pch:... |
1383 1384 1385 |
ret = spi_register_master(master); if (ret != 0) { dev_err(&plat_dev->dev, |
e8b17b5b3 spi/topcliff: Add... |
1386 1387 |
"%s spi_register_master FAILED ", __func__); |
f016aeb65 spi/topcliff_pch:... |
1388 |
goto err_spi_register_master; |
e8b17b5b3 spi/topcliff: Add... |
1389 |
} |
e8b17b5b3 spi/topcliff: Add... |
1390 |
return 0; |
f016aeb65 spi/topcliff_pch:... |
1391 |
err_spi_register_master: |
7995d74ab spi-topcliff-pch:... |
1392 |
pch_free_dma_buf(board_dat, data); |
e1e576282 spi: topcliff-pch... |
1393 |
free_irq(board_dat->pdev->irq, data); |
f016aeb65 spi/topcliff_pch:... |
1394 1395 |
err_request_irq: pch_spi_free_resources(board_dat, data); |
e8b17b5b3 spi/topcliff: Add... |
1396 |
err_spi_get_resources: |
f016aeb65 spi/topcliff_pch:... |
1397 1398 |
pci_iounmap(board_dat->pdev, data->io_remap_addr); err_pci_iomap: |
e8b17b5b3 spi/topcliff: Add... |
1399 |
spi_master_put(master); |
f016aeb65 spi/topcliff_pch:... |
1400 1401 |
return ret; |
e8b17b5b3 spi/topcliff: Add... |
1402 |
} |
fd4a319bc spi: Remove HOTPL... |
1403 |
static int pch_spi_pd_remove(struct platform_device *plat_dev) |
e8b17b5b3 spi/topcliff: Add... |
1404 |
{ |
f016aeb65 spi/topcliff_pch:... |
1405 1406 |
struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev); struct pch_spi_data *data = platform_get_drvdata(plat_dev); |
65308c46b spi/topcliff: cle... |
1407 |
int count; |
c37f3c274 spi/topcliff_pch:... |
1408 |
unsigned long flags; |
e8b17b5b3 spi/topcliff: Add... |
1409 |
|
f016aeb65 spi/topcliff_pch:... |
1410 1411 1412 |
dev_dbg(&plat_dev->dev, "%s:[ch%d] irq=%d ", __func__, plat_dev->id, board_dat->pdev->irq); |
c37f3c274 spi/topcliff_pch:... |
1413 1414 1415 |
if (use_dma) pch_free_dma_buf(board_dat, data); |
65308c46b spi/topcliff: cle... |
1416 1417 1418 |
/* 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 spi/topcliff_pch:... |
1419 |
spin_lock_irqsave(&data->lock, flags); |
f016aeb65 spi/topcliff_pch:... |
1420 1421 |
data->status = STATUS_EXITING; while ((list_empty(&data->queue) == 0) && --count) { |
65308c46b spi/topcliff: cle... |
1422 1423 1424 |
dev_dbg(&board_dat->pdev->dev, "%s :queue not empty ", __func__); |
c37f3c274 spi/topcliff_pch:... |
1425 |
spin_unlock_irqrestore(&data->lock, flags); |
65308c46b spi/topcliff: cle... |
1426 |
msleep(PCH_SLEEP_TIME); |
c37f3c274 spi/topcliff_pch:... |
1427 |
spin_lock_irqsave(&data->lock, flags); |
e8b17b5b3 spi/topcliff: Add... |
1428 |
} |
c37f3c274 spi/topcliff_pch:... |
1429 |
spin_unlock_irqrestore(&data->lock, flags); |
e8b17b5b3 spi/topcliff: Add... |
1430 |
|
f016aeb65 spi/topcliff_pch:... |
1431 1432 1433 1434 1435 1436 1437 1438 |
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 spi/topcliff: Add... |
1439 |
|
f016aeb65 spi/topcliff_pch:... |
1440 1441 |
pci_iounmap(board_dat->pdev, data->io_remap_addr); spi_unregister_master(data->master); |
e8b17b5b3 spi/topcliff: Add... |
1442 |
|
f016aeb65 spi/topcliff_pch:... |
1443 |
return 0; |
e8b17b5b3 spi/topcliff: Add... |
1444 |
} |
e8b17b5b3 spi/topcliff: Add... |
1445 |
#ifdef CONFIG_PM |
f016aeb65 spi/topcliff_pch:... |
1446 1447 |
static int pch_spi_pd_suspend(struct platform_device *pd_dev, pm_message_t state) |
e8b17b5b3 spi/topcliff: Add... |
1448 1449 |
{ u8 count; |
f016aeb65 spi/topcliff_pch:... |
1450 1451 |
struct pch_spi_board_data *board_dat = dev_get_platdata(&pd_dev->dev); struct pch_spi_data *data = platform_get_drvdata(pd_dev); |
e8b17b5b3 spi/topcliff: Add... |
1452 |
|
f016aeb65 spi/topcliff_pch:... |
1453 1454 |
dev_dbg(&pd_dev->dev, "%s ENTRY ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
1455 1456 |
if (!board_dat) { |
f016aeb65 spi/topcliff_pch:... |
1457 |
dev_err(&pd_dev->dev, |
e8b17b5b3 spi/topcliff: Add... |
1458 1459 1460 1461 |
"%s pci_get_drvdata returned NULL ", __func__); return -EFAULT; } |
e8b17b5b3 spi/topcliff: Add... |
1462 1463 1464 |
/* check if the current message is processed: Only after thats done the transfer will be suspended */ count = 255; |
c37f3c274 spi/topcliff_pch:... |
1465 1466 |
while ((--count) > 0) { if (!(data->bcurrent_msg_processing)) |
e8b17b5b3 spi/topcliff: Add... |
1467 |
break; |
e8b17b5b3 spi/topcliff: Add... |
1468 1469 1470 1471 |
msleep(PCH_SLEEP_TIME); } /* Free IRQ */ |
f016aeb65 spi/topcliff_pch:... |
1472 |
if (data->irq_reg_sts) { |
e8b17b5b3 spi/topcliff: Add... |
1473 |
/* disable all interrupts */ |
f016aeb65 spi/topcliff_pch:... |
1474 1475 1476 |
pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); pch_spi_reset(data->master); free_irq(board_dat->pdev->irq, data); |
e8b17b5b3 spi/topcliff: Add... |
1477 |
|
f016aeb65 spi/topcliff_pch:... |
1478 1479 |
data->irq_reg_sts = false; dev_dbg(&pd_dev->dev, |
e8b17b5b3 spi/topcliff: Add... |
1480 1481 1482 |
"%s free_irq invoked successfully. ", __func__); } |
f016aeb65 spi/topcliff_pch:... |
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 |
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", |
f016aeb65 spi/topcliff_pch:... |
1525 1526 |
}, .probe = pch_spi_pd_probe, |
fd4a319bc spi: Remove HOTPL... |
1527 |
.remove = pch_spi_pd_remove, |
f016aeb65 spi/topcliff_pch:... |
1528 1529 1530 |
.suspend = pch_spi_pd_suspend, .resume = pch_spi_pd_resume }; |
b86e81d9a spi: topcliff-pch... |
1531 |
static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
f016aeb65 spi/topcliff_pch:... |
1532 1533 1534 1535 1536 1537 |
{ 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; |
baa35f573 spi/topcliff-pch:... |
1538 |
pd_dev_save = kzalloc(sizeof(*pd_dev_save), GFP_KERNEL); |
fe75cbc1b spi: topcliff-pch... |
1539 |
if (!pd_dev_save) |
f016aeb65 spi/topcliff_pch:... |
1540 |
return -ENOMEM; |
f016aeb65 spi/topcliff_pch:... |
1541 |
|
baa35f573 spi/topcliff-pch:... |
1542 |
board_dat = kzalloc(sizeof(*board_dat), GFP_KERNEL); |
f016aeb65 spi/topcliff_pch:... |
1543 |
if (!board_dat) { |
f016aeb65 spi/topcliff_pch:... |
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 |
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 "); |
bac902d50 spi: topcliff-pch... |
1572 |
retval = -ENOMEM; |
f016aeb65 spi/topcliff_pch:... |
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 |
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: |
b86e81d9a spi: topcliff-pch... |
1602 1603 |
while (--i >= 0) platform_device_unregister(pd_dev_save->pd_save[i]); |
f016aeb65 spi/topcliff_pch:... |
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 |
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; } |
fd4a319bc spi: Remove HOTPL... |
1614 |
static void pch_spi_remove(struct pci_dev *pdev) |
f016aeb65 spi/topcliff_pch:... |
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 |
{ 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); } |
f185bcc77 spi: spi-topcliff... |
1630 |
static int __maybe_unused pch_spi_suspend(struct device *dev) |
f016aeb65 spi/topcliff_pch:... |
1631 |
{ |
f185bcc77 spi: spi-topcliff... |
1632 |
struct pch_pd_dev_save *pd_dev_save = dev_get_drvdata(dev); |
f016aeb65 spi/topcliff_pch:... |
1633 |
|
f185bcc77 spi: spi-topcliff... |
1634 1635 |
dev_dbg(dev, "%s ENTRY ", __func__); |
f016aeb65 spi/topcliff_pch:... |
1636 1637 |
pd_dev_save->board_dat->suspend_sts = true; |
f185bcc77 spi: spi-topcliff... |
1638 |
return 0; |
e8b17b5b3 spi/topcliff: Add... |
1639 |
} |
f185bcc77 spi: spi-topcliff... |
1640 |
static int __maybe_unused pch_spi_resume(struct device *dev) |
e8b17b5b3 spi/topcliff: Add... |
1641 |
{ |
f185bcc77 spi: spi-topcliff... |
1642 |
struct pch_pd_dev_save *pd_dev_save = dev_get_drvdata(dev); |
e8b17b5b3 spi/topcliff: Add... |
1643 |
|
f185bcc77 spi: spi-topcliff... |
1644 1645 |
dev_dbg(dev, "%s ENTRY ", __func__); |
e8b17b5b3 spi/topcliff: Add... |
1646 |
|
f185bcc77 spi: spi-topcliff... |
1647 1648 |
/* set suspend status to false */ pd_dev_save->board_dat->suspend_sts = false; |
e8b17b5b3 spi/topcliff: Add... |
1649 |
|
f185bcc77 spi: spi-topcliff... |
1650 |
return 0; |
e8b17b5b3 spi/topcliff: Add... |
1651 |
} |
e8b17b5b3 spi/topcliff: Add... |
1652 |
|
f185bcc77 spi: spi-topcliff... |
1653 |
static SIMPLE_DEV_PM_OPS(pch_spi_pm_ops, pch_spi_suspend, pch_spi_resume); |
e8b17b5b3 spi/topcliff: Add... |
1654 |
|
c88db2332 spi-topcliff-pch:... |
1655 |
static struct pci_driver pch_spi_pcidev_driver = { |
e8b17b5b3 spi/topcliff: Add... |
1656 1657 1658 |
.name = "pch_spi", .id_table = pch_spi_pcidev_id, .probe = pch_spi_probe, |
fd4a319bc spi: Remove HOTPL... |
1659 |
.remove = pch_spi_remove, |
f185bcc77 spi: spi-topcliff... |
1660 |
.driver.pm = &pch_spi_pm_ops, |
e8b17b5b3 spi/topcliff: Add... |
1661 1662 1663 1664 |
}; static int __init pch_spi_init(void) { |
f016aeb65 spi/topcliff_pch:... |
1665 1666 1667 1668 |
int ret; ret = platform_driver_register(&pch_spi_pd_driver); if (ret) return ret; |
c88db2332 spi-topcliff-pch:... |
1669 |
ret = pci_register_driver(&pch_spi_pcidev_driver); |
0113f22ee spi-topcliff-pch:... |
1670 1671 |
if (ret) { platform_driver_unregister(&pch_spi_pd_driver); |
f016aeb65 spi/topcliff_pch:... |
1672 |
return ret; |
0113f22ee spi-topcliff-pch:... |
1673 |
} |
f016aeb65 spi/topcliff_pch:... |
1674 1675 |
return 0; |
e8b17b5b3 spi/topcliff: Add... |
1676 1677 |
} module_init(pch_spi_init); |
e8b17b5b3 spi/topcliff: Add... |
1678 1679 |
static void __exit pch_spi_exit(void) { |
c88db2332 spi-topcliff-pch:... |
1680 |
pci_unregister_driver(&pch_spi_pcidev_driver); |
f016aeb65 spi/topcliff_pch:... |
1681 |
platform_driver_unregister(&pch_spi_pd_driver); |
e8b17b5b3 spi/topcliff: Add... |
1682 1683 |
} module_exit(pch_spi_exit); |
c37f3c274 spi/topcliff_pch:... |
1684 1685 1686 |
module_param(use_dma, int, 0644); MODULE_PARM_DESC(use_dma, "to use DMA for data transfers pass 1 else 0; default 1"); |
e8b17b5b3 spi/topcliff: Add... |
1687 |
MODULE_LICENSE("GPL"); |
2b2462832 spi-topcliff-pch:... |
1688 |
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor ML7xxx IOH SPI Driver"); |
2f1603c6f spi-topcliff-pch:... |
1689 |
MODULE_DEVICE_TABLE(pci, pch_spi_pcidev_id); |