aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyrille Pitchen <cyrille.pitchen@atmel.com>2015-06-09 07:53:52 -0400
committerMark Brown <broonie@kernel.org>2015-06-09 13:25:53 -0400
commit4820303480a18773f30e2c5ad1178d5960facdbf (patch)
tree0ddc4f313c7bbaa3a0f7430468e75e8faaaa37db
parentb787f68c36d49bb1d9236f403813641efa74a031 (diff)
spi: atmel: add support for the internal chip-select of the spi controller
This patch relies on the CSAAT (Chip Select Active After Transfer) feature introduced by the version 2 of the spi controller. This new mode allows to use properly the internal chip-select output pin of the spi controller instead of using external gpios. Consequently, the "cs-gpios" device-tree property becomes optional. When the new CSAAT bit is set into the Chip Select Register, the internal chip-select output pin remains asserted till both the following conditions become true: - the LASTXFER bit is set into the Control Register (or the Transmit Data Register) - the Transmit Data Register and its shift register are empty. WARNING: if the LASTXFER bit is set into the Control Register then new data are written into the Transmit Data Register fast enough to keep its shifter not empty, the chip-select output pin remains asserted. Only when the shifter becomes empty, the chip-select output pin is unasserted. When the CSAAT bit is clear in the Chip Select Register, the LASTXFER bit is ignored in both the Control Register and the Transmit Data Register. The internal chip-select output pin remains active as long as the Transmit Data Register or its shift register are not empty. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-atmel.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index a2f40b1b2225..aa7d202d6905 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -246,6 +246,7 @@ struct atmel_spi {
246 246
247 bool use_dma; 247 bool use_dma;
248 bool use_pdc; 248 bool use_pdc;
249 bool use_cs_gpios;
249 /* dmaengine data */ 250 /* dmaengine data */
250 struct atmel_spi_dma dma; 251 struct atmel_spi_dma dma;
251 252
@@ -321,7 +322,8 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
321 } 322 }
322 323
323 mr = spi_readl(as, MR); 324 mr = spi_readl(as, MR);
324 gpio_set_value(asd->npcs_pin, active); 325 if (as->use_cs_gpios)
326 gpio_set_value(asd->npcs_pin, active);
325 } else { 327 } else {
326 u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; 328 u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
327 int i; 329 int i;
@@ -337,7 +339,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
337 339
338 mr = spi_readl(as, MR); 340 mr = spi_readl(as, MR);
339 mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); 341 mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
340 if (spi->chip_select != 0) 342 if (as->use_cs_gpios && spi->chip_select != 0)
341 gpio_set_value(asd->npcs_pin, active); 343 gpio_set_value(asd->npcs_pin, active);
342 spi_writel(as, MR, mr); 344 spi_writel(as, MR, mr);
343 } 345 }
@@ -366,7 +368,9 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
366 asd->npcs_pin, active ? " (low)" : "", 368 asd->npcs_pin, active ? " (low)" : "",
367 mr); 369 mr);
368 370
369 if (atmel_spi_is_v2(as) || spi->chip_select != 0) 371 if (!as->use_cs_gpios)
372 spi_writel(as, CR, SPI_BIT(LASTXFER));
373 else if (atmel_spi_is_v2(as) || spi->chip_select != 0)
370 gpio_set_value(asd->npcs_pin, !active); 374 gpio_set_value(asd->npcs_pin, !active);
371} 375}
372 376
@@ -996,6 +1000,8 @@ static int atmel_spi_setup(struct spi_device *spi)
996 csr |= SPI_BIT(CPOL); 1000 csr |= SPI_BIT(CPOL);
997 if (!(spi->mode & SPI_CPHA)) 1001 if (!(spi->mode & SPI_CPHA))
998 csr |= SPI_BIT(NCPHA); 1002 csr |= SPI_BIT(NCPHA);
1003 if (!as->use_cs_gpios)
1004 csr |= SPI_BIT(CSAAT);
999 1005
1000 /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. 1006 /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
1001 * 1007 *
@@ -1009,7 +1015,9 @@ static int atmel_spi_setup(struct spi_device *spi)
1009 /* chipselect must have been muxed as GPIO (e.g. in board setup) */ 1015 /* chipselect must have been muxed as GPIO (e.g. in board setup) */
1010 npcs_pin = (unsigned long)spi->controller_data; 1016 npcs_pin = (unsigned long)spi->controller_data;
1011 1017
1012 if (gpio_is_valid(spi->cs_gpio)) 1018 if (!as->use_cs_gpios)
1019 npcs_pin = spi->chip_select;
1020 else if (gpio_is_valid(spi->cs_gpio))
1013 npcs_pin = spi->cs_gpio; 1021 npcs_pin = spi->cs_gpio;
1014 1022
1015 asd = spi->controller_state; 1023 asd = spi->controller_state;
@@ -1018,15 +1026,19 @@ static int atmel_spi_setup(struct spi_device *spi)
1018 if (!asd) 1026 if (!asd)
1019 return -ENOMEM; 1027 return -ENOMEM;
1020 1028
1021 ret = gpio_request(npcs_pin, dev_name(&spi->dev)); 1029 if (as->use_cs_gpios) {
1022 if (ret) { 1030 ret = gpio_request(npcs_pin, dev_name(&spi->dev));
1023 kfree(asd); 1031 if (ret) {
1024 return ret; 1032 kfree(asd);
1033 return ret;
1034 }
1035
1036 gpio_direction_output(npcs_pin,
1037 !(spi->mode & SPI_CS_HIGH));
1025 } 1038 }
1026 1039
1027 asd->npcs_pin = npcs_pin; 1040 asd->npcs_pin = npcs_pin;
1028 spi->controller_state = asd; 1041 spi->controller_state = asd;
1029 gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
1030 } 1042 }
1031 1043
1032 asd->csr = csr; 1044 asd->csr = csr;
@@ -1338,6 +1350,13 @@ static int atmel_spi_probe(struct platform_device *pdev)
1338 1350
1339 atmel_get_caps(as); 1351 atmel_get_caps(as);
1340 1352
1353 as->use_cs_gpios = true;
1354 if (atmel_spi_is_v2(as) &&
1355 !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
1356 as->use_cs_gpios = false;
1357 master->num_chipselect = 4;
1358 }
1359
1341 as->use_dma = false; 1360 as->use_dma = false;
1342 as->use_pdc = false; 1361 as->use_pdc = false;
1343 if (as->caps.has_dma_support) { 1362 if (as->caps.has_dma_support) {