diff options
author | Roland Stigge <stigge@antcom.de> | 2012-08-22 09:49:17 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-08-22 15:00:44 -0400 |
commit | f6f46de1063c8829713cd9d5b960dd8cb66cde8b (patch) | |
tree | 3367d20d24223f9e149188eb2997b66111237633 /drivers | |
parent | 3ce8859e2e72713d3619285cab609d05c3591fc4 (diff) |
spi/pl022: Add chip select handling via GPIO
This patch adds the ability for the driver to control the chip select directly.
This enables independence from cs_control callbacks. Configurable via
platform_data, to be extended as DT in the following patch.
Based on the initial patch by Alexandre Pereira da Silva <aletes.xgr@gmail.com>
Signed-off-by: Roland Stigge <stigge@antcom.de>
Acked-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/spi/spi-pl022.c | 48 |
1 files changed, 34 insertions, 14 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 47c6753fb31b..cf47802f00c9 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/dma-mapping.h> | 40 | #include <linux/dma-mapping.h> |
41 | #include <linux/scatterlist.h> | 41 | #include <linux/scatterlist.h> |
42 | #include <linux/pm_runtime.h> | 42 | #include <linux/pm_runtime.h> |
43 | #include <linux/gpio.h> | ||
43 | 44 | ||
44 | /* | 45 | /* |
45 | * This macro is used to define some register default values. | 46 | * This macro is used to define some register default values. |
@@ -356,6 +357,8 @@ struct vendor_data { | |||
356 | * @sgt_rx: scattertable for the RX transfer | 357 | * @sgt_rx: scattertable for the RX transfer |
357 | * @sgt_tx: scattertable for the TX transfer | 358 | * @sgt_tx: scattertable for the TX transfer |
358 | * @dummypage: a dummy page used for driving data on the bus with DMA | 359 | * @dummypage: a dummy page used for driving data on the bus with DMA |
360 | * @cur_cs: current chip select (gpio) | ||
361 | * @chipselects: list of chipselects (gpios) | ||
359 | */ | 362 | */ |
360 | struct pl022 { | 363 | struct pl022 { |
361 | struct amba_device *adev; | 364 | struct amba_device *adev; |
@@ -389,6 +392,8 @@ struct pl022 { | |||
389 | char *dummypage; | 392 | char *dummypage; |
390 | bool dma_running; | 393 | bool dma_running; |
391 | #endif | 394 | #endif |
395 | int cur_cs; | ||
396 | int *chipselects; | ||
392 | }; | 397 | }; |
393 | 398 | ||
394 | /** | 399 | /** |
@@ -433,6 +438,14 @@ static void null_cs_control(u32 command) | |||
433 | pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); | 438 | pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); |
434 | } | 439 | } |
435 | 440 | ||
441 | static void pl022_cs_control(struct pl022 *pl022, u32 command) | ||
442 | { | ||
443 | if (gpio_is_valid(pl022->cur_cs)) | ||
444 | gpio_set_value(pl022->cur_cs, command); | ||
445 | else | ||
446 | pl022->cur_chip->cs_control(command); | ||
447 | } | ||
448 | |||
436 | /** | 449 | /** |
437 | * giveback - current spi_message is over, schedule next message and call | 450 | * giveback - current spi_message is over, schedule next message and call |
438 | * callback of this message. Assumes that caller already | 451 | * callback of this message. Assumes that caller already |
@@ -479,7 +492,7 @@ static void giveback(struct pl022 *pl022) | |||
479 | if (next_msg && next_msg->spi != pl022->cur_msg->spi) | 492 | if (next_msg && next_msg->spi != pl022->cur_msg->spi) |
480 | next_msg = NULL; | 493 | next_msg = NULL; |
481 | if (!next_msg || pl022->cur_msg->state == STATE_ERROR) | 494 | if (!next_msg || pl022->cur_msg->state == STATE_ERROR) |
482 | pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); | 495 | pl022_cs_control(pl022, SSP_CHIP_DESELECT); |
483 | else | 496 | else |
484 | pl022->next_msg_cs_active = true; | 497 | pl022->next_msg_cs_active = true; |
485 | 498 | ||
@@ -818,8 +831,7 @@ static void dma_callback(void *data) | |||
818 | /* Update total bytes transferred */ | 831 | /* Update total bytes transferred */ |
819 | msg->actual_length += pl022->cur_transfer->len; | 832 | msg->actual_length += pl022->cur_transfer->len; |
820 | if (pl022->cur_transfer->cs_change) | 833 | if (pl022->cur_transfer->cs_change) |
821 | pl022->cur_chip-> | 834 | pl022_cs_control(pl022, SSP_CHIP_DESELECT); |
822 | cs_control(SSP_CHIP_DESELECT); | ||
823 | 835 | ||
824 | /* Move to next transfer */ | 836 | /* Move to next transfer */ |
825 | msg->state = next_transfer(pl022); | 837 | msg->state = next_transfer(pl022); |
@@ -1252,8 +1264,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) | |||
1252 | /* Update total bytes transferred */ | 1264 | /* Update total bytes transferred */ |
1253 | msg->actual_length += pl022->cur_transfer->len; | 1265 | msg->actual_length += pl022->cur_transfer->len; |
1254 | if (pl022->cur_transfer->cs_change) | 1266 | if (pl022->cur_transfer->cs_change) |
1255 | pl022->cur_chip-> | 1267 | pl022_cs_control(pl022, SSP_CHIP_DESELECT); |
1256 | cs_control(SSP_CHIP_DESELECT); | ||
1257 | /* Move to next transfer */ | 1268 | /* Move to next transfer */ |
1258 | msg->state = next_transfer(pl022); | 1269 | msg->state = next_transfer(pl022); |
1259 | tasklet_schedule(&pl022->pump_transfers); | 1270 | tasklet_schedule(&pl022->pump_transfers); |
@@ -1338,7 +1349,7 @@ static void pump_transfers(unsigned long data) | |||
1338 | 1349 | ||
1339 | /* Reselect chip select only if cs_change was requested */ | 1350 | /* Reselect chip select only if cs_change was requested */ |
1340 | if (previous->cs_change) | 1351 | if (previous->cs_change) |
1341 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | 1352 | pl022_cs_control(pl022, SSP_CHIP_SELECT); |
1342 | } else { | 1353 | } else { |
1343 | /* STATE_START */ | 1354 | /* STATE_START */ |
1344 | message->state = STATE_RUNNING; | 1355 | message->state = STATE_RUNNING; |
@@ -1377,7 +1388,7 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022) | |||
1377 | 1388 | ||
1378 | /* Enable target chip, if not already active */ | 1389 | /* Enable target chip, if not already active */ |
1379 | if (!pl022->next_msg_cs_active) | 1390 | if (!pl022->next_msg_cs_active) |
1380 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | 1391 | pl022_cs_control(pl022, SSP_CHIP_SELECT); |
1381 | 1392 | ||
1382 | if (set_up_next_transfer(pl022, pl022->cur_transfer)) { | 1393 | if (set_up_next_transfer(pl022, pl022->cur_transfer)) { |
1383 | /* Error path */ | 1394 | /* Error path */ |
@@ -1429,12 +1440,12 @@ static void do_polling_transfer(struct pl022 *pl022) | |||
1429 | if (previous->delay_usecs) | 1440 | if (previous->delay_usecs) |
1430 | udelay(previous->delay_usecs); | 1441 | udelay(previous->delay_usecs); |
1431 | if (previous->cs_change) | 1442 | if (previous->cs_change) |
1432 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | 1443 | pl022_cs_control(pl022, SSP_CHIP_SELECT); |
1433 | } else { | 1444 | } else { |
1434 | /* STATE_START */ | 1445 | /* STATE_START */ |
1435 | message->state = STATE_RUNNING; | 1446 | message->state = STATE_RUNNING; |
1436 | if (!pl022->next_msg_cs_active) | 1447 | if (!pl022->next_msg_cs_active) |
1437 | pl022->cur_chip->cs_control(SSP_CHIP_SELECT); | 1448 | pl022_cs_control(pl022, SSP_CHIP_SELECT); |
1438 | } | 1449 | } |
1439 | 1450 | ||
1440 | /* Configuration Changing Per Transfer */ | 1451 | /* Configuration Changing Per Transfer */ |
@@ -1466,7 +1477,7 @@ static void do_polling_transfer(struct pl022 *pl022) | |||
1466 | /* Update total byte transferred */ | 1477 | /* Update total byte transferred */ |
1467 | message->actual_length += pl022->cur_transfer->len; | 1478 | message->actual_length += pl022->cur_transfer->len; |
1468 | if (pl022->cur_transfer->cs_change) | 1479 | if (pl022->cur_transfer->cs_change) |
1469 | pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); | 1480 | pl022_cs_control(pl022, SSP_CHIP_DESELECT); |
1470 | /* Move to next transfer */ | 1481 | /* Move to next transfer */ |
1471 | message->state = next_transfer(pl022); | 1482 | message->state = next_transfer(pl022); |
1472 | } | 1483 | } |
@@ -1495,6 +1506,7 @@ static int pl022_transfer_one_message(struct spi_master *master, | |||
1495 | 1506 | ||
1496 | /* Setup the SPI using the per chip configuration */ | 1507 | /* Setup the SPI using the per chip configuration */ |
1497 | pl022->cur_chip = spi_get_ctldata(msg->spi); | 1508 | pl022->cur_chip = spi_get_ctldata(msg->spi); |
1509 | pl022->cur_cs = pl022->chipselects[msg->spi->chip_select]; | ||
1498 | 1510 | ||
1499 | restore_state(pl022); | 1511 | restore_state(pl022); |
1500 | flush(pl022); | 1512 | flush(pl022); |
@@ -1840,8 +1852,9 @@ static int pl022_setup(struct spi_device *spi) | |||
1840 | chip->xfer_type = chip_info->com_mode; | 1852 | chip->xfer_type = chip_info->com_mode; |
1841 | if (!chip_info->cs_control) { | 1853 | if (!chip_info->cs_control) { |
1842 | chip->cs_control = null_cs_control; | 1854 | chip->cs_control = null_cs_control; |
1843 | dev_warn(&spi->dev, | 1855 | if (!gpio_is_valid(pl022->chipselects[spi->chip_select])) |
1844 | "chip select function is NULL for this chip\n"); | 1856 | dev_warn(&spi->dev, |
1857 | "invalid chip select\n"); | ||
1845 | } else | 1858 | } else |
1846 | chip->cs_control = chip_info->cs_control; | 1859 | chip->cs_control = chip_info->cs_control; |
1847 | 1860 | ||
@@ -1993,7 +2006,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
1993 | struct pl022_ssp_controller *platform_info = adev->dev.platform_data; | 2006 | struct pl022_ssp_controller *platform_info = adev->dev.platform_data; |
1994 | struct spi_master *master; | 2007 | struct spi_master *master; |
1995 | struct pl022 *pl022 = NULL; /*Data for this driver */ | 2008 | struct pl022 *pl022 = NULL; /*Data for this driver */ |
1996 | int status = 0; | 2009 | int status = 0, i; |
1997 | 2010 | ||
1998 | dev_info(&adev->dev, | 2011 | dev_info(&adev->dev, |
1999 | "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); | 2012 | "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); |
@@ -2004,7 +2017,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2004 | } | 2017 | } |
2005 | 2018 | ||
2006 | /* Allocate master with space for data */ | 2019 | /* Allocate master with space for data */ |
2007 | master = spi_alloc_master(dev, sizeof(struct pl022)); | 2020 | master = spi_alloc_master(dev, sizeof(struct pl022) + sizeof(int) * |
2021 | platform_info->num_chipselect); | ||
2008 | if (master == NULL) { | 2022 | if (master == NULL) { |
2009 | dev_err(&adev->dev, "probe - cannot alloc SPI master\n"); | 2023 | dev_err(&adev->dev, "probe - cannot alloc SPI master\n"); |
2010 | status = -ENOMEM; | 2024 | status = -ENOMEM; |
@@ -2016,6 +2030,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2016 | pl022->master_info = platform_info; | 2030 | pl022->master_info = platform_info; |
2017 | pl022->adev = adev; | 2031 | pl022->adev = adev; |
2018 | pl022->vendor = id->data; | 2032 | pl022->vendor = id->data; |
2033 | /* Point chipselects to allocated memory beyond the main struct */ | ||
2034 | pl022->chipselects = (int *) pl022 + sizeof(struct pl022); | ||
2019 | 2035 | ||
2020 | /* | 2036 | /* |
2021 | * Bus Number Which has been Assigned to this SSP controller | 2037 | * Bus Number Which has been Assigned to this SSP controller |
@@ -2030,6 +2046,10 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2030 | master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; | 2046 | master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; |
2031 | master->rt = platform_info->rt; | 2047 | master->rt = platform_info->rt; |
2032 | 2048 | ||
2049 | if (platform_info->num_chipselect && platform_info->chipselects) | ||
2050 | for (i = 0; i < platform_info->num_chipselect; i++) | ||
2051 | pl022->chipselects[i] = platform_info->chipselects[i]; | ||
2052 | |||
2033 | /* | 2053 | /* |
2034 | * Supports mode 0-3, loopback, and active low CS. Transfers are | 2054 | * Supports mode 0-3, loopback, and active low CS. Transfers are |
2035 | * always MS bit first on the original pl022. | 2055 | * always MS bit first on the original pl022. |