Commit 2a8626a9e2d86d114a2d9f813a1acebf9d53dd10
1 parent
d0777f2c3e
Exists in
master
and in
4 other branches
spi/pxa2xx: Add chipselect support for Sodaville
The SPI core on Sodaville supports chip selects. Its configuration moved into the SSSR register at bit 0 and 1. Thus Sodaville can be hooked up with up to 4 devices. This patch ensures that the bits which are otherwiese reserved are only touched on Sodaville and not on any other PXAs. Also it makes sure that the status register does not lose the CS information while clearing the ROR bit. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
Showing 2 changed files with 70 additions and 25 deletions Side-by-side Diff
drivers/spi/pxa2xx_spi.c
... | ... | @@ -163,7 +163,10 @@ |
163 | 163 | u8 enable_dma; |
164 | 164 | u8 bits_per_word; |
165 | 165 | u32 speed_hz; |
166 | - int gpio_cs; | |
166 | + union { | |
167 | + int gpio_cs; | |
168 | + unsigned int frm; | |
169 | + }; | |
167 | 170 | int gpio_cs_inverted; |
168 | 171 | int (*write)(struct driver_data *drv_data); |
169 | 172 | int (*read)(struct driver_data *drv_data); |
... | ... | @@ -176,6 +179,11 @@ |
176 | 179 | { |
177 | 180 | struct chip_data *chip = drv_data->cur_chip; |
178 | 181 | |
182 | + if (drv_data->ssp_type == CE4100_SSP) { | |
183 | + write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr); | |
184 | + return; | |
185 | + } | |
186 | + | |
179 | 187 | if (chip->cs_control) { |
180 | 188 | chip->cs_control(PXA2XX_CS_ASSERT); |
181 | 189 | return; |
... | ... | @@ -189,6 +197,9 @@ |
189 | 197 | { |
190 | 198 | struct chip_data *chip = drv_data->cur_chip; |
191 | 199 | |
200 | + if (drv_data->ssp_type == CE4100_SSP) | |
201 | + return; | |
202 | + | |
192 | 203 | if (chip->cs_control) { |
193 | 204 | chip->cs_control(PXA2XX_CS_DEASSERT); |
194 | 205 | return; |
... | ... | @@ -198,6 +209,25 @@ |
198 | 209 | gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted); |
199 | 210 | } |
200 | 211 | |
212 | +static void write_SSSR_CS(struct driver_data *drv_data, u32 val) | |
213 | +{ | |
214 | + void __iomem *reg = drv_data->ioaddr; | |
215 | + | |
216 | + if (drv_data->ssp_type == CE4100_SSP) | |
217 | + val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK; | |
218 | + | |
219 | + write_SSSR(val, reg); | |
220 | +} | |
221 | + | |
222 | +static int pxa25x_ssp_comp(struct driver_data *drv_data) | |
223 | +{ | |
224 | + if (drv_data->ssp_type == PXA25x_SSP) | |
225 | + return 1; | |
226 | + if (drv_data->ssp_type == CE4100_SSP) | |
227 | + return 1; | |
228 | + return 0; | |
229 | +} | |
230 | + | |
201 | 231 | static int flush(struct driver_data *drv_data) |
202 | 232 | { |
203 | 233 | unsigned long limit = loops_per_jiffy << 1; |
... | ... | @@ -209,7 +239,7 @@ |
209 | 239 | read_SSDR(reg); |
210 | 240 | } |
211 | 241 | } while ((read_SSSR(reg) & SSSR_BSY) && --limit); |
212 | - write_SSSR(SSSR_ROR, reg); | |
242 | + write_SSSR_CS(drv_data, SSSR_ROR); | |
213 | 243 | |
214 | 244 | return limit; |
215 | 245 | } |
216 | 246 | |
... | ... | @@ -502,9 +532,9 @@ |
502 | 532 | /* Stop and reset */ |
503 | 533 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
504 | 534 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
505 | - write_SSSR(drv_data->clear_sr, reg); | |
535 | + write_SSSR_CS(drv_data, drv_data->clear_sr); | |
506 | 536 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); |
507 | - if (drv_data->ssp_type != PXA25x_SSP) | |
537 | + if (!pxa25x_ssp_comp(drv_data)) | |
508 | 538 | write_SSTO(0, reg); |
509 | 539 | flush(drv_data); |
510 | 540 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); |
... | ... | @@ -524,7 +554,7 @@ |
524 | 554 | |
525 | 555 | /* Clear and disable interrupts on SSP and DMA channels*/ |
526 | 556 | write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); |
527 | - write_SSSR(drv_data->clear_sr, reg); | |
557 | + write_SSSR_CS(drv_data, drv_data->clear_sr); | |
528 | 558 | DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; |
529 | 559 | DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; |
530 | 560 | |
... | ... | @@ -617,7 +647,7 @@ |
617 | 647 | |
618 | 648 | /* Clear and disable timeout interrupt, do the rest in |
619 | 649 | * dma_transfer_complete */ |
620 | - if (drv_data->ssp_type != PXA25x_SSP) | |
650 | + if (!pxa25x_ssp_comp(drv_data)) | |
621 | 651 | write_SSTO(0, reg); |
622 | 652 | |
623 | 653 | /* finish this transfer, start the next */ |
624 | 654 | |
... | ... | @@ -635,9 +665,9 @@ |
635 | 665 | void __iomem *reg = drv_data->ioaddr; |
636 | 666 | |
637 | 667 | /* Stop and reset SSP */ |
638 | - write_SSSR(drv_data->clear_sr, reg); | |
668 | + write_SSSR_CS(drv_data, drv_data->clear_sr); | |
639 | 669 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); |
640 | - if (drv_data->ssp_type != PXA25x_SSP) | |
670 | + if (!pxa25x_ssp_comp(drv_data)) | |
641 | 671 | write_SSTO(0, reg); |
642 | 672 | flush(drv_data); |
643 | 673 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); |
644 | 674 | |
... | ... | @@ -653,9 +683,9 @@ |
653 | 683 | void __iomem *reg = drv_data->ioaddr; |
654 | 684 | |
655 | 685 | /* Stop SSP */ |
656 | - write_SSSR(drv_data->clear_sr, reg); | |
686 | + write_SSSR_CS(drv_data, drv_data->clear_sr); | |
657 | 687 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); |
658 | - if (drv_data->ssp_type != PXA25x_SSP) | |
688 | + if (!pxa25x_ssp_comp(drv_data)) | |
659 | 689 | write_SSTO(0, reg); |
660 | 690 | |
661 | 691 | /* Update total byte transfered return count actual bytes read */ |
... | ... | @@ -711,7 +741,7 @@ |
711 | 741 | if (drv_data->tx == drv_data->tx_end) { |
712 | 742 | write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); |
713 | 743 | /* PXA25x_SSP has no timeout, read trailing bytes */ |
714 | - if (drv_data->ssp_type == PXA25x_SSP) { | |
744 | + if (pxa25x_ssp_comp(drv_data)) { | |
715 | 745 | if (!wait_ssp_rx_stall(reg)) |
716 | 746 | { |
717 | 747 | int_error_stop(drv_data, "interrupt_transfer: " |
718 | 748 | |
... | ... | @@ -754,9 +784,9 @@ |
754 | 784 | |
755 | 785 | write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); |
756 | 786 | write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); |
757 | - if (drv_data->ssp_type != PXA25x_SSP) | |
787 | + if (!pxa25x_ssp_comp(drv_data)) | |
758 | 788 | write_SSTO(0, reg); |
759 | - write_SSSR(drv_data->clear_sr, reg); | |
789 | + write_SSSR_CS(drv_data, drv_data->clear_sr); | |
760 | 790 | |
761 | 791 | dev_err(&drv_data->pdev->dev, "bad message state " |
762 | 792 | "in interrupt handler\n"); |
... | ... | @@ -869,7 +899,7 @@ |
869 | 899 | { |
870 | 900 | unsigned long ssp_clk = clk_get_rate(ssp->clk); |
871 | 901 | |
872 | - if (ssp->type == PXA25x_SSP) | |
902 | + if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP) | |
873 | 903 | return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; |
874 | 904 | else |
875 | 905 | return ((ssp_clk / rate - 1) & 0xfff) << 8; |
... | ... | @@ -1095,7 +1125,7 @@ |
1095 | 1125 | |
1096 | 1126 | /* Clear status */ |
1097 | 1127 | cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1; |
1098 | - write_SSSR(drv_data->clear_sr, reg); | |
1128 | + write_SSSR_CS(drv_data, drv_data->clear_sr); | |
1099 | 1129 | } |
1100 | 1130 | |
1101 | 1131 | /* see if we need to reload the config registers */ |
... | ... | @@ -1105,7 +1135,7 @@ |
1105 | 1135 | |
1106 | 1136 | /* stop the SSP, and update the other bits */ |
1107 | 1137 | write_SSCR0(cr0 & ~SSCR0_SSE, reg); |
1108 | - if (drv_data->ssp_type != PXA25x_SSP) | |
1138 | + if (!pxa25x_ssp_comp(drv_data)) | |
1109 | 1139 | write_SSTO(chip->timeout, reg); |
1110 | 1140 | /* first set CR1 without interrupt and service enables */ |
1111 | 1141 | write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg); |
... | ... | @@ -1113,7 +1143,7 @@ |
1113 | 1143 | write_SSCR0(cr0, reg); |
1114 | 1144 | |
1115 | 1145 | } else { |
1116 | - if (drv_data->ssp_type != PXA25x_SSP) | |
1146 | + if (!pxa25x_ssp_comp(drv_data)) | |
1117 | 1147 | write_SSTO(chip->timeout, reg); |
1118 | 1148 | } |
1119 | 1149 | |
1120 | 1150 | |
... | ... | @@ -1240,14 +1270,13 @@ |
1240 | 1270 | uint tx_thres = TX_THRESH_DFLT; |
1241 | 1271 | uint rx_thres = RX_THRESH_DFLT; |
1242 | 1272 | |
1243 | - if (drv_data->ssp_type != PXA25x_SSP | |
1273 | + if (!pxa25x_ssp_comp(drv_data) | |
1244 | 1274 | && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) { |
1245 | 1275 | dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d " |
1246 | 1276 | "b/w not 4-32 for type non-PXA25x_SSP\n", |
1247 | 1277 | drv_data->ssp_type, spi->bits_per_word); |
1248 | 1278 | return -EINVAL; |
1249 | - } | |
1250 | - else if (drv_data->ssp_type == PXA25x_SSP | |
1279 | + } else if (pxa25x_ssp_comp(drv_data) | |
1251 | 1280 | && (spi->bits_per_word < 4 |
1252 | 1281 | || spi->bits_per_word > 16)) { |
1253 | 1282 | dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d " |
... | ... | @@ -1266,7 +1295,17 @@ |
1266 | 1295 | return -ENOMEM; |
1267 | 1296 | } |
1268 | 1297 | |
1269 | - chip->gpio_cs = -1; | |
1298 | + if (drv_data->ssp_type == CE4100_SSP) { | |
1299 | + if (spi->chip_select > 4) { | |
1300 | + dev_err(&spi->dev, "failed setup: " | |
1301 | + "cs number must not be > 4.\n"); | |
1302 | + kfree(chip); | |
1303 | + return -EINVAL; | |
1304 | + } | |
1305 | + | |
1306 | + chip->frm = spi->chip_select; | |
1307 | + } else | |
1308 | + chip->gpio_cs = -1; | |
1270 | 1309 | chip->enable_dma = 0; |
1271 | 1310 | chip->timeout = TIMOUT_DFLT; |
1272 | 1311 | chip->dma_burst_size = drv_data->master_info->enable_dma ? |
... | ... | @@ -1322,7 +1361,7 @@ |
1322 | 1361 | | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); |
1323 | 1362 | |
1324 | 1363 | /* NOTE: PXA25x_SSP _could_ use external clocking ... */ |
1325 | - if (drv_data->ssp_type != PXA25x_SSP) | |
1364 | + if (!pxa25x_ssp_comp(drv_data)) | |
1326 | 1365 | dev_dbg(&spi->dev, "%ld Hz actual, %s\n", |
1327 | 1366 | clk_get_rate(ssp->clk) |
1328 | 1367 | / (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)), |
1329 | 1368 | |
1330 | 1369 | |
... | ... | @@ -1357,17 +1396,21 @@ |
1357 | 1396 | |
1358 | 1397 | spi_set_ctldata(spi, chip); |
1359 | 1398 | |
1399 | + if (drv_data->ssp_type == CE4100_SSP) | |
1400 | + return 0; | |
1401 | + | |
1360 | 1402 | return setup_cs(spi, chip, chip_info); |
1361 | 1403 | } |
1362 | 1404 | |
1363 | 1405 | static void cleanup(struct spi_device *spi) |
1364 | 1406 | { |
1365 | 1407 | struct chip_data *chip = spi_get_ctldata(spi); |
1408 | + struct driver_data *drv_data = spi_master_get_devdata(spi->master); | |
1366 | 1409 | |
1367 | 1410 | if (!chip) |
1368 | 1411 | return; |
1369 | 1412 | |
1370 | - if (gpio_is_valid(chip->gpio_cs)) | |
1413 | + if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs)) | |
1371 | 1414 | gpio_free(chip->gpio_cs); |
1372 | 1415 | |
1373 | 1416 | kfree(chip); |
... | ... | @@ -1507,7 +1550,7 @@ |
1507 | 1550 | |
1508 | 1551 | drv_data->ioaddr = ssp->mmio_base; |
1509 | 1552 | drv_data->ssdr_physical = ssp->phys_base + SSDR; |
1510 | - if (ssp->type == PXA25x_SSP) { | |
1553 | + if (pxa25x_ssp_comp(drv_data)) { | |
1511 | 1554 | drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; |
1512 | 1555 | drv_data->dma_cr1 = 0; |
1513 | 1556 | drv_data->clear_sr = SSSR_ROR; |
... | ... | @@ -1569,7 +1612,7 @@ |
1569 | 1612 | | SSCR0_Motorola |
1570 | 1613 | | SSCR0_DataSize(8), |
1571 | 1614 | drv_data->ioaddr); |
1572 | - if (drv_data->ssp_type != PXA25x_SSP) | |
1615 | + if (!pxa25x_ssp_comp(drv_data)) | |
1573 | 1616 | write_SSTO(0, drv_data->ioaddr); |
1574 | 1617 | write_SSPSP(0, drv_data->ioaddr); |
1575 | 1618 |
include/linux/pxa2xx_ssp.h
... | ... | @@ -72,6 +72,7 @@ |
72 | 72 | #define SSCR1_SPH (1 << 4) /* Motorola SPI SSPSCLK phase setting */ |
73 | 73 | #define SSCR1_MWDS (1 << 5) /* Microwire Transmit Data Size */ |
74 | 74 | |
75 | +#define SSSR_ALT_FRM_MASK 3 /* Masks the SFRM signal number */ | |
75 | 76 | #define SSSR_TNF (1 << 2) /* Transmit FIFO Not Full */ |
76 | 77 | #define SSSR_RNE (1 << 3) /* Receive FIFO Not Empty */ |
77 | 78 | #define SSSR_BSY (1 << 4) /* SSP Busy */ |
... | ... | @@ -160,6 +161,7 @@ |
160 | 161 | PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */ |
161 | 162 | PXA27x_SSP, |
162 | 163 | PXA168_SSP, |
164 | + CE4100_SSP, | |
163 | 165 | }; |
164 | 166 | |
165 | 167 | struct ssp_device { |