diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:32:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 13:32:00 -0400 |
commit | 5f0e685f316a1de6d3af8b23eaf46651faca32ab (patch) | |
tree | af1ed231b7fcfc65b146be59a0aee699aa9f6353 /drivers/spi/spi-topcliff-pch.c | |
parent | f8974cb71310a05632aada76be6a27576d61e609 (diff) | |
parent | 87bf5ab82884c829366914aaa813cc8b07b9fe58 (diff) |
Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6
Pull SPI changes for v3.4 from Grant Likely:
"Mostly a bunch of new drivers and driver bug fixes; but this also
includes a few patches that create a core message queue infrastructure
for the spi subsystem instead of making each driver open code it."
* tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6: (34 commits)
spi/fsl-espi: Make sure pm is within 2..32
spi/fsl-espi: make the clock computation easier to read
spi: sh-hspi: modify write/read method
spi: sh-hspi: control spi clock more correctly
spi: sh-hspi: convert to using core message queue
spi: s3c64xx: Fix build
spi: s3c64xx: remove unnecessary callback msg->complete
spi: remove redundant variable assignment
spi: release lock on error path in spi_pump_messages()
spi: Compatibility with direction which is used in samsung DMA operation
spi-topcliff-pch: add recovery processing in case wait-event timeout
spi-topcliff-pch: supports a spi mode setup and bit order setup by IO control
spi-topcliff-pch: Fix issue for transmitting over 4KByte
spi-topcliff-pch: Modify pci-bus number dynamically to get DMA device info
spi/imx: simplify error handling to free gpios
spi: Convert to DEFINE_PCI_DEVICE_TABLE
spi: add Broadcom BCM63xx SPI controller driver
SPI: add CSR SiRFprimaII SPI controller driver
spi-topcliff-pch: fix -Wuninitialized warning
spi: Mark spi_register_board_info() __devinit
...
Diffstat (limited to 'drivers/spi/spi-topcliff-pch.c')
-rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 113 |
1 files changed, 84 insertions, 29 deletions
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 10182eb50068..5c6fa5ed3366 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c | |||
@@ -196,6 +196,7 @@ struct pch_spi_data { | |||
196 | struct pch_spi_dma_ctrl dma; | 196 | struct pch_spi_dma_ctrl dma; |
197 | int use_dma; | 197 | int use_dma; |
198 | u8 irq_reg_sts; | 198 | u8 irq_reg_sts; |
199 | int save_total_len; | ||
199 | }; | 200 | }; |
200 | 201 | ||
201 | /** | 202 | /** |
@@ -216,7 +217,7 @@ struct pch_pd_dev_save { | |||
216 | struct pch_spi_board_data *board_dat; | 217 | struct pch_spi_board_data *board_dat; |
217 | }; | 218 | }; |
218 | 219 | ||
219 | static struct pci_device_id pch_spi_pcidev_id[] = { | 220 | static DEFINE_PCI_DEVICE_TABLE(pch_spi_pcidev_id) = { |
220 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI), 1, }, | 221 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI), 1, }, |
221 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, }, | 222 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, }, |
222 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), 1, }, | 223 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_SPI), 1, }, |
@@ -318,22 +319,23 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, | |||
318 | data->tx_index = tx_index; | 319 | data->tx_index = tx_index; |
319 | data->rx_index = rx_index; | 320 | data->rx_index = rx_index; |
320 | 321 | ||
321 | } | 322 | /* if transfer complete interrupt */ |
322 | 323 | if (reg_spsr_val & SPSR_FI_BIT) { | |
323 | /* if transfer complete interrupt */ | 324 | if ((tx_index == bpw_len) && (rx_index == tx_index)) { |
324 | if (reg_spsr_val & SPSR_FI_BIT) { | 325 | /* disable interrupts */ |
325 | if ((tx_index == bpw_len) && (rx_index == tx_index)) { | 326 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, |
326 | /* disable interrupts */ | 327 | PCH_ALL); |
327 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); | 328 | |
328 | 329 | /* transfer is completed; | |
329 | /* transfer is completed; | 330 | inform pch_spi_process_messages */ |
330 | inform pch_spi_process_messages */ | 331 | data->transfer_complete = true; |
331 | data->transfer_complete = true; | 332 | data->transfer_active = false; |
332 | data->transfer_active = false; | 333 | wake_up(&data->wait); |
333 | wake_up(&data->wait); | 334 | } else { |
334 | } else { | 335 | dev_err(&data->master->dev, |
335 | dev_err(&data->master->dev, | 336 | "%s : Transfer is not completed", |
336 | "%s : Transfer is not completed", __func__); | 337 | __func__); |
338 | } | ||
337 | } | 339 | } |
338 | } | 340 | } |
339 | } | 341 | } |
@@ -822,11 +824,13 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw) | |||
822 | rx_dma_buf = data->dma.rx_buf_virt; | 824 | rx_dma_buf = data->dma.rx_buf_virt; |
823 | for (j = 0; j < data->bpw_len; j++) | 825 | for (j = 0; j < data->bpw_len; j++) |
824 | *rx_buf++ = *rx_dma_buf++ & 0xFF; | 826 | *rx_buf++ = *rx_dma_buf++ & 0xFF; |
827 | data->cur_trans->rx_buf = rx_buf; | ||
825 | } else { | 828 | } else { |
826 | rx_sbuf = data->cur_trans->rx_buf; | 829 | rx_sbuf = data->cur_trans->rx_buf; |
827 | rx_dma_sbuf = data->dma.rx_buf_virt; | 830 | rx_dma_sbuf = data->dma.rx_buf_virt; |
828 | for (j = 0; j < data->bpw_len; j++) | 831 | for (j = 0; j < data->bpw_len; j++) |
829 | *rx_sbuf++ = *rx_dma_sbuf++; | 832 | *rx_sbuf++ = *rx_dma_sbuf++; |
833 | data->cur_trans->rx_buf = rx_sbuf; | ||
830 | } | 834 | } |
831 | } | 835 | } |
832 | 836 | ||
@@ -852,6 +856,9 @@ static int pch_spi_start_transfer(struct pch_spi_data *data) | |||
852 | rtn = wait_event_interruptible_timeout(data->wait, | 856 | rtn = wait_event_interruptible_timeout(data->wait, |
853 | data->transfer_complete, | 857 | data->transfer_complete, |
854 | msecs_to_jiffies(2 * HZ)); | 858 | msecs_to_jiffies(2 * HZ)); |
859 | if (!rtn) | ||
860 | dev_err(&data->master->dev, | ||
861 | "%s wait-event timeout\n", __func__); | ||
855 | 862 | ||
856 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, | 863 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, |
857 | DMA_FROM_DEVICE); | 864 | DMA_FROM_DEVICE); |
@@ -923,7 +930,8 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw) | |||
923 | dma_cap_set(DMA_SLAVE, mask); | 930 | dma_cap_set(DMA_SLAVE, mask); |
924 | 931 | ||
925 | /* Get DMA's dev information */ | 932 | /* Get DMA's dev information */ |
926 | dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(12, 0)); | 933 | dma_dev = pci_get_bus_and_slot(data->board_dat->pdev->bus->number, |
934 | PCI_DEVFN(12, 0)); | ||
927 | 935 | ||
928 | /* Set Tx DMA */ | 936 | /* Set Tx DMA */ |
929 | param = &dma->param_tx; | 937 | param = &dma->param_tx; |
@@ -987,6 +995,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
987 | int i; | 995 | int i; |
988 | int size; | 996 | int size; |
989 | int rem; | 997 | int rem; |
998 | int head; | ||
990 | unsigned long flags; | 999 | unsigned long flags; |
991 | struct pch_spi_dma_ctrl *dma; | 1000 | struct pch_spi_dma_ctrl *dma; |
992 | 1001 | ||
@@ -1015,6 +1024,11 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1015 | } | 1024 | } |
1016 | data->bpw_len = data->cur_trans->len / (*bpw / 8); | 1025 | data->bpw_len = data->cur_trans->len / (*bpw / 8); |
1017 | 1026 | ||
1027 | if (data->bpw_len > PCH_BUF_SIZE) { | ||
1028 | data->bpw_len = PCH_BUF_SIZE; | ||
1029 | data->cur_trans->len -= PCH_BUF_SIZE; | ||
1030 | } | ||
1031 | |||
1018 | /* copy Tx Data */ | 1032 | /* copy Tx Data */ |
1019 | if (data->cur_trans->tx_buf != NULL) { | 1033 | if (data->cur_trans->tx_buf != NULL) { |
1020 | if (*bpw == 8) { | 1034 | if (*bpw == 8) { |
@@ -1029,10 +1043,17 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1029 | *tx_dma_sbuf++ = *tx_sbuf++; | 1043 | *tx_dma_sbuf++ = *tx_sbuf++; |
1030 | } | 1044 | } |
1031 | } | 1045 | } |
1046 | |||
1047 | /* Calculate Rx parameter for DMA transmitting */ | ||
1032 | if (data->bpw_len > PCH_DMA_TRANS_SIZE) { | 1048 | if (data->bpw_len > PCH_DMA_TRANS_SIZE) { |
1033 | num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; | 1049 | if (data->bpw_len % PCH_DMA_TRANS_SIZE) { |
1050 | num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; | ||
1051 | rem = data->bpw_len % PCH_DMA_TRANS_SIZE; | ||
1052 | } else { | ||
1053 | num = data->bpw_len / PCH_DMA_TRANS_SIZE; | ||
1054 | rem = PCH_DMA_TRANS_SIZE; | ||
1055 | } | ||
1034 | size = PCH_DMA_TRANS_SIZE; | 1056 | size = PCH_DMA_TRANS_SIZE; |
1035 | rem = data->bpw_len % PCH_DMA_TRANS_SIZE; | ||
1036 | } else { | 1057 | } else { |
1037 | num = 1; | 1058 | num = 1; |
1038 | size = data->bpw_len; | 1059 | size = data->bpw_len; |
@@ -1092,15 +1113,23 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1092 | dma->nent = num; | 1113 | dma->nent = num; |
1093 | dma->desc_rx = desc_rx; | 1114 | dma->desc_rx = desc_rx; |
1094 | 1115 | ||
1095 | /* TX */ | 1116 | /* Calculate Tx parameter for DMA transmitting */ |
1096 | if (data->bpw_len > PCH_DMA_TRANS_SIZE) { | 1117 | if (data->bpw_len > PCH_MAX_FIFO_DEPTH) { |
1097 | num = data->bpw_len / PCH_DMA_TRANS_SIZE; | 1118 | head = PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE; |
1119 | if (data->bpw_len % PCH_DMA_TRANS_SIZE > 4) { | ||
1120 | num = data->bpw_len / PCH_DMA_TRANS_SIZE + 1; | ||
1121 | rem = data->bpw_len % PCH_DMA_TRANS_SIZE - head; | ||
1122 | } else { | ||
1123 | num = data->bpw_len / PCH_DMA_TRANS_SIZE; | ||
1124 | rem = data->bpw_len % PCH_DMA_TRANS_SIZE + | ||
1125 | PCH_DMA_TRANS_SIZE - head; | ||
1126 | } | ||
1098 | size = PCH_DMA_TRANS_SIZE; | 1127 | size = PCH_DMA_TRANS_SIZE; |
1099 | rem = 16; | ||
1100 | } else { | 1128 | } else { |
1101 | num = 1; | 1129 | num = 1; |
1102 | size = data->bpw_len; | 1130 | size = data->bpw_len; |
1103 | rem = data->bpw_len; | 1131 | rem = data->bpw_len; |
1132 | head = 0; | ||
1104 | } | 1133 | } |
1105 | 1134 | ||
1106 | dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); | 1135 | dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); |
@@ -1110,11 +1139,17 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1110 | for (i = 0; i < num; i++, sg++) { | 1139 | for (i = 0; i < num; i++, sg++) { |
1111 | if (i == 0) { | 1140 | if (i == 0) { |
1112 | sg->offset = 0; | 1141 | sg->offset = 0; |
1142 | sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size + head, | ||
1143 | sg->offset); | ||
1144 | sg_dma_len(sg) = size + head; | ||
1145 | } else if (i == (num - 1)) { | ||
1146 | sg->offset = head + size * i; | ||
1147 | sg->offset = sg->offset * (*bpw / 8); | ||
1113 | sg_set_page(sg, virt_to_page(dma->tx_buf_virt), rem, | 1148 | sg_set_page(sg, virt_to_page(dma->tx_buf_virt), rem, |
1114 | sg->offset); | 1149 | sg->offset); |
1115 | sg_dma_len(sg) = rem; | 1150 | sg_dma_len(sg) = rem; |
1116 | } else { | 1151 | } else { |
1117 | sg->offset = rem + size * (i - 1); | 1152 | sg->offset = head + size * i; |
1118 | sg->offset = sg->offset * (*bpw / 8); | 1153 | sg->offset = sg->offset * (*bpw / 8); |
1119 | sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size, | 1154 | sg_set_page(sg, virt_to_page(dma->tx_buf_virt), size, |
1120 | sg->offset); | 1155 | sg->offset); |
@@ -1202,6 +1237,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1202 | data->current_msg->spi->bits_per_word); | 1237 | data->current_msg->spi->bits_per_word); |
1203 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | 1238 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); |
1204 | do { | 1239 | do { |
1240 | int cnt; | ||
1205 | /* If we are already processing a message get the next | 1241 | /* If we are already processing a message get the next |
1206 | transfer structure from the message otherwise retrieve | 1242 | transfer structure from the message otherwise retrieve |
1207 | the 1st transfer request from the message. */ | 1243 | the 1st transfer request from the message. */ |
@@ -1221,11 +1257,28 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1221 | } | 1257 | } |
1222 | spin_unlock(&data->lock); | 1258 | spin_unlock(&data->lock); |
1223 | 1259 | ||
1260 | if (!data->cur_trans->len) | ||
1261 | goto out; | ||
1262 | cnt = (data->cur_trans->len - 1) / PCH_BUF_SIZE + 1; | ||
1263 | data->save_total_len = data->cur_trans->len; | ||
1224 | if (data->use_dma) { | 1264 | if (data->use_dma) { |
1225 | pch_spi_handle_dma(data, &bpw); | 1265 | int i; |
1226 | if (!pch_spi_start_transfer(data)) | 1266 | char *save_rx_buf = data->cur_trans->rx_buf; |
1227 | goto out; | 1267 | for (i = 0; i < cnt; i ++) { |
1228 | pch_spi_copy_rx_data_for_dma(data, bpw); | 1268 | pch_spi_handle_dma(data, &bpw); |
1269 | if (!pch_spi_start_transfer(data)) { | ||
1270 | data->transfer_complete = true; | ||
1271 | data->current_msg->status = -EIO; | ||
1272 | data->current_msg->complete | ||
1273 | (data->current_msg->context); | ||
1274 | data->bcurrent_msg_processing = false; | ||
1275 | data->current_msg = NULL; | ||
1276 | data->cur_trans = NULL; | ||
1277 | goto out; | ||
1278 | } | ||
1279 | pch_spi_copy_rx_data_for_dma(data, bpw); | ||
1280 | } | ||
1281 | data->cur_trans->rx_buf = save_rx_buf; | ||
1229 | } else { | 1282 | } else { |
1230 | pch_spi_set_tx(data, &bpw); | 1283 | pch_spi_set_tx(data, &bpw); |
1231 | pch_spi_set_ir(data); | 1284 | pch_spi_set_ir(data); |
@@ -1236,6 +1289,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1236 | data->pkt_tx_buff = NULL; | 1289 | data->pkt_tx_buff = NULL; |
1237 | } | 1290 | } |
1238 | /* increment message count */ | 1291 | /* increment message count */ |
1292 | data->cur_trans->len = data->save_total_len; | ||
1239 | data->current_msg->actual_length += data->cur_trans->len; | 1293 | data->current_msg->actual_length += data->cur_trans->len; |
1240 | 1294 | ||
1241 | dev_dbg(&data->master->dev, | 1295 | dev_dbg(&data->master->dev, |
@@ -1388,6 +1442,7 @@ static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev) | |||
1388 | master->num_chipselect = PCH_MAX_CS; | 1442 | master->num_chipselect = PCH_MAX_CS; |
1389 | master->setup = pch_spi_setup; | 1443 | master->setup = pch_spi_setup; |
1390 | master->transfer = pch_spi_transfer; | 1444 | master->transfer = pch_spi_transfer; |
1445 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; | ||
1391 | 1446 | ||
1392 | data->board_dat = board_dat; | 1447 | data->board_dat = board_dat; |
1393 | data->plat_dev = plat_dev; | 1448 | data->plat_dev = plat_dev; |