diff options
author | Tomoya MORINAGA <tomoya.rohm@gmail.com> | 2011-12-08 23:13:27 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2012-03-09 22:54:57 -0500 |
commit | 7d05b3e868ee0f9231baf40cb77be3df5dd1f18c (patch) | |
tree | 7f59c33e0d08f2dca503e7709f2bb6b738ef2aec /drivers/spi | |
parent | ee2ece5261a639b89f194d141444b03b4c923179 (diff) |
spi-topcliff-pch: Fix issue for transmitting over 4KByte
Currently, when spi-topcliff-pch receives transmit request over 4KByte,
this driver can't process correctly. This driver needs to divide the data
into 4Kbyte unit.
This patch fixes the issue.
Signed-off-by: Tomoya MORINAGA <tomoya.rohm@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 66 |
1 files changed, 55 insertions, 11 deletions
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 4b32fd7d0570..4fdb83a765d8 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 | /** |
@@ -823,11 +824,13 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw) | |||
823 | rx_dma_buf = data->dma.rx_buf_virt; | 824 | rx_dma_buf = data->dma.rx_buf_virt; |
824 | for (j = 0; j < data->bpw_len; j++) | 825 | for (j = 0; j < data->bpw_len; j++) |
825 | *rx_buf++ = *rx_dma_buf++ & 0xFF; | 826 | *rx_buf++ = *rx_dma_buf++ & 0xFF; |
827 | data->cur_trans->rx_buf = rx_buf; | ||
826 | } else { | 828 | } else { |
827 | rx_sbuf = data->cur_trans->rx_buf; | 829 | rx_sbuf = data->cur_trans->rx_buf; |
828 | rx_dma_sbuf = data->dma.rx_buf_virt; | 830 | rx_dma_sbuf = data->dma.rx_buf_virt; |
829 | for (j = 0; j < data->bpw_len; j++) | 831 | for (j = 0; j < data->bpw_len; j++) |
830 | *rx_sbuf++ = *rx_dma_sbuf++; | 832 | *rx_sbuf++ = *rx_dma_sbuf++; |
833 | data->cur_trans->rx_buf = rx_sbuf; | ||
831 | } | 834 | } |
832 | } | 835 | } |
833 | 836 | ||
@@ -853,6 +856,9 @@ static int pch_spi_start_transfer(struct pch_spi_data *data) | |||
853 | rtn = wait_event_interruptible_timeout(data->wait, | 856 | rtn = wait_event_interruptible_timeout(data->wait, |
854 | data->transfer_complete, | 857 | data->transfer_complete, |
855 | 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__); | ||
856 | 862 | ||
857 | 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, |
858 | DMA_FROM_DEVICE); | 864 | DMA_FROM_DEVICE); |
@@ -989,6 +995,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
989 | int i; | 995 | int i; |
990 | int size; | 996 | int size; |
991 | int rem; | 997 | int rem; |
998 | int head; | ||
992 | unsigned long flags; | 999 | unsigned long flags; |
993 | struct pch_spi_dma_ctrl *dma; | 1000 | struct pch_spi_dma_ctrl *dma; |
994 | 1001 | ||
@@ -1017,6 +1024,11 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1017 | } | 1024 | } |
1018 | data->bpw_len = data->cur_trans->len / (*bpw / 8); | 1025 | data->bpw_len = data->cur_trans->len / (*bpw / 8); |
1019 | 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 | |||
1020 | /* copy Tx Data */ | 1032 | /* copy Tx Data */ |
1021 | if (data->cur_trans->tx_buf != NULL) { | 1033 | if (data->cur_trans->tx_buf != NULL) { |
1022 | if (*bpw == 8) { | 1034 | if (*bpw == 8) { |
@@ -1031,10 +1043,17 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1031 | *tx_dma_sbuf++ = *tx_sbuf++; | 1043 | *tx_dma_sbuf++ = *tx_sbuf++; |
1032 | } | 1044 | } |
1033 | } | 1045 | } |
1046 | |||
1047 | /* Calculate Rx parameter for DMA transmitting */ | ||
1034 | if (data->bpw_len > PCH_DMA_TRANS_SIZE) { | 1048 | if (data->bpw_len > PCH_DMA_TRANS_SIZE) { |
1035 | 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 | } | ||
1036 | size = PCH_DMA_TRANS_SIZE; | 1056 | size = PCH_DMA_TRANS_SIZE; |
1037 | rem = data->bpw_len % PCH_DMA_TRANS_SIZE; | ||
1038 | } else { | 1057 | } else { |
1039 | num = 1; | 1058 | num = 1; |
1040 | size = data->bpw_len; | 1059 | size = data->bpw_len; |
@@ -1094,15 +1113,23 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1094 | dma->nent = num; | 1113 | dma->nent = num; |
1095 | dma->desc_rx = desc_rx; | 1114 | dma->desc_rx = desc_rx; |
1096 | 1115 | ||
1097 | /* TX */ | 1116 | /* Calculate Tx parameter for DMA transmitting */ |
1098 | if (data->bpw_len > PCH_DMA_TRANS_SIZE) { | 1117 | if (data->bpw_len > PCH_MAX_FIFO_DEPTH) { |
1099 | 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 | } | ||
1100 | size = PCH_DMA_TRANS_SIZE; | 1127 | size = PCH_DMA_TRANS_SIZE; |
1101 | rem = 16; | ||
1102 | } else { | 1128 | } else { |
1103 | num = 1; | 1129 | num = 1; |
1104 | size = data->bpw_len; | 1130 | size = data->bpw_len; |
1105 | rem = data->bpw_len; | 1131 | rem = data->bpw_len; |
1132 | head = 0; | ||
1106 | } | 1133 | } |
1107 | 1134 | ||
1108 | dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); | 1135 | dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); |
@@ -1112,11 +1139,17 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) | |||
1112 | for (i = 0; i < num; i++, sg++) { | 1139 | for (i = 0; i < num; i++, sg++) { |
1113 | if (i == 0) { | 1140 | if (i == 0) { |
1114 | 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); | ||
1115 | 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, |
1116 | sg->offset); | 1149 | sg->offset); |
1117 | sg_dma_len(sg) = rem; | 1150 | sg_dma_len(sg) = rem; |
1118 | } else { | 1151 | } else { |
1119 | sg->offset = rem + size * (i - 1); | 1152 | sg->offset = head + size * i; |
1120 | sg->offset = sg->offset * (*bpw / 8); | 1153 | sg->offset = sg->offset * (*bpw / 8); |
1121 | 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, |
1122 | sg->offset); | 1155 | sg->offset); |
@@ -1204,6 +1237,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1204 | data->current_msg->spi->bits_per_word); | 1237 | data->current_msg->spi->bits_per_word); |
1205 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | 1238 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); |
1206 | do { | 1239 | do { |
1240 | int cnt; | ||
1207 | /* If we are already processing a message get the next | 1241 | /* If we are already processing a message get the next |
1208 | transfer structure from the message otherwise retrieve | 1242 | transfer structure from the message otherwise retrieve |
1209 | the 1st transfer request from the message. */ | 1243 | the 1st transfer request from the message. */ |
@@ -1223,11 +1257,20 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1223 | } | 1257 | } |
1224 | spin_unlock(&data->lock); | 1258 | spin_unlock(&data->lock); |
1225 | 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; | ||
1226 | if (data->use_dma) { | 1264 | if (data->use_dma) { |
1227 | pch_spi_handle_dma(data, &bpw); | 1265 | int i; |
1228 | if (!pch_spi_start_transfer(data)) | 1266 | char *save_rx_buf = data->cur_trans->rx_buf; |
1229 | goto out; | 1267 | for (i = 0; i < cnt; i ++) { |
1230 | pch_spi_copy_rx_data_for_dma(data, bpw); | 1268 | pch_spi_handle_dma(data, &bpw); |
1269 | if (!pch_spi_start_transfer(data)) | ||
1270 | goto out; | ||
1271 | pch_spi_copy_rx_data_for_dma(data, bpw); | ||
1272 | } | ||
1273 | data->cur_trans->rx_buf = save_rx_buf; | ||
1231 | } else { | 1274 | } else { |
1232 | pch_spi_set_tx(data, &bpw); | 1275 | pch_spi_set_tx(data, &bpw); |
1233 | pch_spi_set_ir(data); | 1276 | pch_spi_set_ir(data); |
@@ -1238,6 +1281,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1238 | data->pkt_tx_buff = NULL; | 1281 | data->pkt_tx_buff = NULL; |
1239 | } | 1282 | } |
1240 | /* increment message count */ | 1283 | /* increment message count */ |
1284 | data->cur_trans->len = data->save_total_len; | ||
1241 | data->current_msg->actual_length += data->cur_trans->len; | 1285 | data->current_msg->actual_length += data->cur_trans->len; |
1242 | 1286 | ||
1243 | dev_dbg(&data->master->dev, | 1287 | dev_dbg(&data->master->dev, |