Commit f6f46de1063c8829713cd9d5b960dd8cb66cde8b

Authored by Roland Stigge
Committed by Mark Brown
1 parent 3ce8859e2e

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>

Showing 2 changed files with 36 additions and 14 deletions Side-by-side Diff

drivers/spi/spi-pl022.c
... ... @@ -40,6 +40,7 @@
40 40 #include <linux/dma-mapping.h>
41 41 #include <linux/scatterlist.h>
42 42 #include <linux/pm_runtime.h>
  43 +#include <linux/gpio.h>
43 44  
44 45 /*
45 46 * This macro is used to define some register default values.
... ... @@ -356,6 +357,8 @@
356 357 * @sgt_rx: scattertable for the RX transfer
357 358 * @sgt_tx: scattertable for the TX transfer
358 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 363 struct pl022 {
361 364 struct amba_device *adev;
... ... @@ -389,6 +392,8 @@
389 392 char *dummypage;
390 393 bool dma_running;
391 394 #endif
  395 + int cur_cs;
  396 + int *chipselects;
392 397 };
393 398  
394 399 /**
... ... @@ -433,6 +438,14 @@
433 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 450 * giveback - current spi_message is over, schedule next message and call
438 451 * callback of this message. Assumes that caller already
... ... @@ -479,7 +492,7 @@
479 492 if (next_msg && next_msg->spi != pl022->cur_msg->spi)
480 493 next_msg = NULL;
481 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 496 else
484 497 pl022->next_msg_cs_active = true;
485 498  
... ... @@ -818,8 +831,7 @@
818 831 /* Update total bytes transferred */
819 832 msg->actual_length += pl022->cur_transfer->len;
820 833 if (pl022->cur_transfer->cs_change)
821   - pl022->cur_chip->
822   - cs_control(SSP_CHIP_DESELECT);
  834 + pl022_cs_control(pl022, SSP_CHIP_DESELECT);
823 835  
824 836 /* Move to next transfer */
825 837 msg->state = next_transfer(pl022);
... ... @@ -1252,8 +1264,7 @@
1252 1264 /* Update total bytes transferred */
1253 1265 msg->actual_length += pl022->cur_transfer->len;
1254 1266 if (pl022->cur_transfer->cs_change)
1255   - pl022->cur_chip->
1256   - cs_control(SSP_CHIP_DESELECT);
  1267 + pl022_cs_control(pl022, SSP_CHIP_DESELECT);
1257 1268 /* Move to next transfer */
1258 1269 msg->state = next_transfer(pl022);
1259 1270 tasklet_schedule(&pl022->pump_transfers);
... ... @@ -1338,7 +1349,7 @@
1338 1349  
1339 1350 /* Reselect chip select only if cs_change was requested */
1340 1351 if (previous->cs_change)
1341   - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
  1352 + pl022_cs_control(pl022, SSP_CHIP_SELECT);
1342 1353 } else {
1343 1354 /* STATE_START */
1344 1355 message->state = STATE_RUNNING;
... ... @@ -1377,7 +1388,7 @@
1377 1388  
1378 1389 /* Enable target chip, if not already active */
1379 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 1393 if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
1383 1394 /* Error path */
1384 1395  
... ... @@ -1429,12 +1440,12 @@
1429 1440 if (previous->delay_usecs)
1430 1441 udelay(previous->delay_usecs);
1431 1442 if (previous->cs_change)
1432   - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
  1443 + pl022_cs_control(pl022, SSP_CHIP_SELECT);
1433 1444 } else {
1434 1445 /* STATE_START */
1435 1446 message->state = STATE_RUNNING;
1436 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 1451 /* Configuration Changing Per Transfer */
... ... @@ -1466,7 +1477,7 @@
1466 1477 /* Update total byte transferred */
1467 1478 message->actual_length += pl022->cur_transfer->len;
1468 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 1481 /* Move to next transfer */
1471 1482 message->state = next_transfer(pl022);
1472 1483 }
... ... @@ -1495,6 +1506,7 @@
1495 1506  
1496 1507 /* Setup the SPI using the per chip configuration */
1497 1508 pl022->cur_chip = spi_get_ctldata(msg->spi);
  1509 + pl022->cur_cs = pl022->chipselects[msg->spi->chip_select];
1498 1510  
1499 1511 restore_state(pl022);
1500 1512 flush(pl022);
... ... @@ -1840,8 +1852,9 @@
1840 1852 chip->xfer_type = chip_info->com_mode;
1841 1853 if (!chip_info->cs_control) {
1842 1854 chip->cs_control = null_cs_control;
1843   - dev_warn(&spi->dev,
1844   - "chip select function is NULL for this chip\n");
  1855 + if (!gpio_is_valid(pl022->chipselects[spi->chip_select]))
  1856 + dev_warn(&spi->dev,
  1857 + "invalid chip select\n");
1845 1858 } else
1846 1859 chip->cs_control = chip_info->cs_control;
1847 1860  
... ... @@ -1993,7 +2006,7 @@
1993 2006 struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
1994 2007 struct spi_master *master;
1995 2008 struct pl022 *pl022 = NULL; /*Data for this driver */
1996   - int status = 0;
  2009 + int status = 0, i;
1997 2010  
1998 2011 dev_info(&adev->dev,
1999 2012 "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
... ... @@ -2004,7 +2017,8 @@
2004 2017 }
2005 2018  
2006 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 2022 if (master == NULL) {
2009 2023 dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
2010 2024 status = -ENOMEM;
... ... @@ -2016,6 +2030,8 @@
2016 2030 pl022->master_info = platform_info;
2017 2031 pl022->adev = adev;
2018 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 2037 * Bus Number Which has been Assigned to this SSP controller
... ... @@ -2029,6 +2045,10 @@
2029 2045 master->transfer_one_message = pl022_transfer_one_message;
2030 2046 master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
2031 2047 master->rt = platform_info->rt;
  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];
2032 2052  
2033 2053 /*
2034 2054 * Supports mode 0-3, loopback, and active low CS. Transfers are
include/linux/amba/pl022.h
... ... @@ -244,6 +244,7 @@
244 244 * indicates no delay and the device will be suspended immediately.
245 245 * @rt: indicates the controller should run the message pump with realtime
246 246 * priority to minimise the transfer latency on the bus.
  247 + * @chipselects: list of <num_chipselects> chip select gpios
247 248 */
248 249 struct pl022_ssp_controller {
249 250 u16 bus_id;
... ... @@ -254,6 +255,7 @@
254 255 void *dma_tx_param;
255 256 int autosuspend_delay;
256 257 bool rt;
  258 + int *chipselects;
257 259 };
258 260  
259 261 /**