diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-04 12:52:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-04 12:52:56 -0400 |
commit | f8451c3f15982ebdf71f7b5e155ade38efc5993f (patch) | |
tree | 7d0437ef000896413ca5161a4c956baec2474d75 | |
parent | 5f39e6705faade2e89d119958a8c51b9b6e2c53c (diff) | |
parent | f3e03e2eb0bcd9266720695b82a523e6bc526ff7 (diff) |
Merge branch 'spi/merge' of git://git.secretlab.ca/git/linux-2.6
* 'spi/merge' of git://git.secretlab.ca/git/linux-2.6:
spi-topcliff-pch: Fix overrun issue
spi-topcliff-pch: Add recovery processing in case FIFO overrun error occurs
spi-topcliff-pch: Fix CPU read complete condition issue
spi-topcliff-pch: Fix SSN Control issue
spi-topcliff-pch: add tx-memory clear after complete transmitting
-rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 93 |
1 files changed, 66 insertions, 27 deletions
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 1d23f3831866..6a80749391db 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c | |||
@@ -50,6 +50,8 @@ | |||
50 | #define PCH_RX_THOLD 7 | 50 | #define PCH_RX_THOLD 7 |
51 | #define PCH_RX_THOLD_MAX 15 | 51 | #define PCH_RX_THOLD_MAX 15 |
52 | 52 | ||
53 | #define PCH_TX_THOLD 2 | ||
54 | |||
53 | #define PCH_MAX_BAUDRATE 5000000 | 55 | #define PCH_MAX_BAUDRATE 5000000 |
54 | #define PCH_MAX_FIFO_DEPTH 16 | 56 | #define PCH_MAX_FIFO_DEPTH 16 |
55 | 57 | ||
@@ -58,6 +60,7 @@ | |||
58 | #define PCH_SLEEP_TIME 10 | 60 | #define PCH_SLEEP_TIME 10 |
59 | 61 | ||
60 | #define SSN_LOW 0x02U | 62 | #define SSN_LOW 0x02U |
63 | #define SSN_HIGH 0x03U | ||
61 | #define SSN_NO_CONTROL 0x00U | 64 | #define SSN_NO_CONTROL 0x00U |
62 | #define PCH_MAX_CS 0xFF | 65 | #define PCH_MAX_CS 0xFF |
63 | #define PCI_DEVICE_ID_GE_SPI 0x8816 | 66 | #define PCI_DEVICE_ID_GE_SPI 0x8816 |
@@ -316,16 +319,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, | |||
316 | 319 | ||
317 | /* if transfer complete interrupt */ | 320 | /* if transfer complete interrupt */ |
318 | if (reg_spsr_val & SPSR_FI_BIT) { | 321 | if (reg_spsr_val & SPSR_FI_BIT) { |
319 | if (tx_index < bpw_len) | 322 | if ((tx_index == bpw_len) && (rx_index == tx_index)) { |
323 | /* disable interrupts */ | ||
324 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); | ||
325 | |||
326 | /* transfer is completed; | ||
327 | inform pch_spi_process_messages */ | ||
328 | data->transfer_complete = true; | ||
329 | data->transfer_active = false; | ||
330 | wake_up(&data->wait); | ||
331 | } else { | ||
320 | dev_err(&data->master->dev, | 332 | dev_err(&data->master->dev, |
321 | "%s : Transfer is not completed", __func__); | 333 | "%s : Transfer is not completed", __func__); |
322 | /* disable interrupts */ | 334 | } |
323 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); | ||
324 | |||
325 | /* transfer is completed;inform pch_spi_process_messages */ | ||
326 | data->transfer_complete = true; | ||
327 | data->transfer_active = false; | ||
328 | wake_up(&data->wait); | ||
329 | } | 335 | } |
330 | } | 336 | } |
331 | 337 | ||
@@ -348,16 +354,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id) | |||
348 | "%s returning due to suspend\n", __func__); | 354 | "%s returning due to suspend\n", __func__); |
349 | return IRQ_NONE; | 355 | return IRQ_NONE; |
350 | } | 356 | } |
351 | if (data->use_dma) | ||
352 | return IRQ_NONE; | ||
353 | 357 | ||
354 | io_remap_addr = data->io_remap_addr; | 358 | io_remap_addr = data->io_remap_addr; |
355 | spsr = io_remap_addr + PCH_SPSR; | 359 | spsr = io_remap_addr + PCH_SPSR; |
356 | 360 | ||
357 | reg_spsr_val = ioread32(spsr); | 361 | reg_spsr_val = ioread32(spsr); |
358 | 362 | ||
359 | if (reg_spsr_val & SPSR_ORF_BIT) | 363 | if (reg_spsr_val & SPSR_ORF_BIT) { |
360 | dev_err(&board_dat->pdev->dev, "%s Over run error", __func__); | 364 | dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__); |
365 | if (data->current_msg->complete != 0) { | ||
366 | data->transfer_complete = true; | ||
367 | data->current_msg->status = -EIO; | ||
368 | data->current_msg->complete(data->current_msg->context); | ||
369 | data->bcurrent_msg_processing = false; | ||
370 | data->current_msg = NULL; | ||
371 | data->cur_trans = NULL; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | if (data->use_dma) | ||
376 | return IRQ_NONE; | ||
361 | 377 | ||
362 | /* Check if the interrupt is for SPI device */ | 378 | /* Check if the interrupt is for SPI device */ |
363 | if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { | 379 | if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { |
@@ -756,10 +772,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data) | |||
756 | 772 | ||
757 | wait_event_interruptible(data->wait, data->transfer_complete); | 773 | wait_event_interruptible(data->wait, data->transfer_complete); |
758 | 774 | ||
759 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | ||
760 | dev_dbg(&data->master->dev, | ||
761 | "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); | ||
762 | |||
763 | /* clear all interrupts */ | 775 | /* clear all interrupts */ |
764 | pch_spi_writereg(data->master, PCH_SPSR, | 776 | pch_spi_writereg(data->master, PCH_SPSR, |
765 | pch_spi_readreg(data->master, PCH_SPSR)); | 777 | pch_spi_readreg(data->master, PCH_SPSR)); |
@@ -815,10 +827,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw) | |||
815 | } | 827 | } |
816 | } | 828 | } |
817 | 829 | ||
818 | static void pch_spi_start_transfer(struct pch_spi_data *data) | 830 | static int pch_spi_start_transfer(struct pch_spi_data *data) |
819 | { | 831 | { |
820 | struct pch_spi_dma_ctrl *dma; | 832 | struct pch_spi_dma_ctrl *dma; |
821 | unsigned long flags; | 833 | unsigned long flags; |
834 | int rtn; | ||
822 | 835 | ||
823 | dma = &data->dma; | 836 | dma = &data->dma; |
824 | 837 | ||
@@ -833,19 +846,23 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) | |||
833 | initiating the transfer. */ | 846 | initiating the transfer. */ |
834 | dev_dbg(&data->master->dev, | 847 | dev_dbg(&data->master->dev, |
835 | "%s:waiting for transfer to get over\n", __func__); | 848 | "%s:waiting for transfer to get over\n", __func__); |
836 | wait_event_interruptible(data->wait, data->transfer_complete); | 849 | rtn = wait_event_interruptible_timeout(data->wait, |
850 | data->transfer_complete, | ||
851 | msecs_to_jiffies(2 * HZ)); | ||
837 | 852 | ||
838 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, | 853 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, |
839 | DMA_FROM_DEVICE); | 854 | DMA_FROM_DEVICE); |
855 | |||
856 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent, | ||
857 | DMA_FROM_DEVICE); | ||
858 | memset(data->dma.tx_buf_virt, 0, PAGE_SIZE); | ||
859 | |||
840 | async_tx_ack(dma->desc_rx); | 860 | async_tx_ack(dma->desc_rx); |
841 | async_tx_ack(dma->desc_tx); | 861 | async_tx_ack(dma->desc_tx); |
842 | kfree(dma->sg_tx_p); | 862 | kfree(dma->sg_tx_p); |
843 | kfree(dma->sg_rx_p); | 863 | kfree(dma->sg_rx_p); |
844 | 864 | ||
845 | spin_lock_irqsave(&data->lock, flags); | 865 | spin_lock_irqsave(&data->lock, flags); |
846 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | ||
847 | dev_dbg(&data->master->dev, | ||
848 | "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); | ||
849 | 866 | ||
850 | /* clear fifo threshold, disable interrupts, disable SPI transfer */ | 867 | /* clear fifo threshold, disable interrupts, disable SPI transfer */ |
851 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, | 868 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, |
@@ -858,6 +875,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) | |||
858 | pch_spi_clear_fifo(data->master); | 875 | pch_spi_clear_fifo(data->master); |
859 | 876 | ||
860 | spin_unlock_irqrestore(&data->lock, flags); | 877 | spin_unlock_irqrestore(&data->lock, flags); |
878 | |||
879 | return rtn; | ||
861 | } | 880 | } |
862 | 881 | ||
863 | static void pch_dma_rx_complete(void *arg) | 882 | static void pch_dma_rx_complete(void *arg) |
@@ -1023,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1023 | /* set receive fifo threshold and transmit fifo threshold */ | 1042 | /* set receive fifo threshold and transmit fifo threshold */ |
1024 | pch_spi_setclr_reg(data->master, PCH_SPCR, | 1043 | pch_spi_setclr_reg(data->master, PCH_SPCR, |
1025 | ((size - 1) << SPCR_RFIC_FIELD) | | 1044 | ((size - 1) << SPCR_RFIC_FIELD) | |
1026 | ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) << | 1045 | (PCH_TX_THOLD << SPCR_TFIC_FIELD), |
1027 | SPCR_TFIC_FIELD), | ||
1028 | MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS); | 1046 | MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS); |
1029 | 1047 | ||
1030 | spin_unlock_irqrestore(&data->lock, flags); | 1048 | spin_unlock_irqrestore(&data->lock, flags); |
@@ -1035,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1035 | /* offset, length setting */ | 1053 | /* offset, length setting */ |
1036 | sg = dma->sg_rx_p; | 1054 | sg = dma->sg_rx_p; |
1037 | for (i = 0; i < num; i++, sg++) { | 1055 | for (i = 0; i < num; i++, sg++) { |
1038 | if (i == 0) { | 1056 | if (i == (num - 2)) { |
1039 | sg->offset = 0; | 1057 | sg->offset = size * i; |
1058 | sg->offset = sg->offset * (*bpw / 8); | ||
1040 | sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem, | 1059 | sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem, |
1041 | sg->offset); | 1060 | sg->offset); |
1042 | sg_dma_len(sg) = rem; | 1061 | sg_dma_len(sg) = rem; |
1062 | } else if (i == (num - 1)) { | ||
1063 | sg->offset = size * (i - 1) + rem; | ||
1064 | sg->offset = sg->offset * (*bpw / 8); | ||
1065 | sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, | ||
1066 | sg->offset); | ||
1067 | sg_dma_len(sg) = size; | ||
1043 | } else { | 1068 | } else { |
1044 | sg->offset = rem + size * (i - 1); | 1069 | sg->offset = size * i; |
1045 | sg->offset = sg->offset * (*bpw / 8); | 1070 | sg->offset = sg->offset * (*bpw / 8); |
1046 | sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, | 1071 | sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, |
1047 | sg->offset); | 1072 | sg->offset); |
@@ -1065,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1065 | dma->desc_rx = desc_rx; | 1090 | dma->desc_rx = desc_rx; |
1066 | 1091 | ||
1067 | /* TX */ | 1092 | /* TX */ |
1093 | if (data->bpw_len > PCH_DMA_TRANS_SIZE) { | ||
1094 | num = data->bpw_len / PCH_DMA_TRANS_SIZE; | ||
1095 | size = PCH_DMA_TRANS_SIZE; | ||
1096 | rem = 16; | ||
1097 | } else { | ||
1098 | num = 1; | ||
1099 | size = data->bpw_len; | ||
1100 | rem = data->bpw_len; | ||
1101 | } | ||
1102 | |||
1068 | dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); | 1103 | dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); |
1069 | sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ | 1104 | sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ |
1070 | /* offset, length setting */ | 1105 | /* offset, length setting */ |
@@ -1162,6 +1197,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1162 | if (data->use_dma) | 1197 | if (data->use_dma) |
1163 | pch_spi_request_dma(data, | 1198 | pch_spi_request_dma(data, |
1164 | data->current_msg->spi->bits_per_word); | 1199 | data->current_msg->spi->bits_per_word); |
1200 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | ||
1165 | do { | 1201 | do { |
1166 | /* If we are already processing a message get the next | 1202 | /* If we are already processing a message get the next |
1167 | transfer structure from the message otherwise retrieve | 1203 | transfer structure from the message otherwise retrieve |
@@ -1184,7 +1220,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1184 | 1220 | ||
1185 | if (data->use_dma) { | 1221 | if (data->use_dma) { |
1186 | pch_spi_handle_dma(data, &bpw); | 1222 | pch_spi_handle_dma(data, &bpw); |
1187 | pch_spi_start_transfer(data); | 1223 | if (!pch_spi_start_transfer(data)) |
1224 | goto out; | ||
1188 | pch_spi_copy_rx_data_for_dma(data, bpw); | 1225 | pch_spi_copy_rx_data_for_dma(data, bpw); |
1189 | } else { | 1226 | } else { |
1190 | pch_spi_set_tx(data, &bpw); | 1227 | pch_spi_set_tx(data, &bpw); |
@@ -1222,6 +1259,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1222 | 1259 | ||
1223 | } while (data->cur_trans != NULL); | 1260 | } while (data->cur_trans != NULL); |
1224 | 1261 | ||
1262 | out: | ||
1263 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); | ||
1225 | if (data->use_dma) | 1264 | if (data->use_dma) |
1226 | pch_spi_release_dma(data); | 1265 | pch_spi_release_dma(data); |
1227 | } | 1266 | } |