lkml.org 
[lkml]   [2012]   [Aug]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: [PATCH v5 1/2] spi/pl022: Add chip select handling via GPIO
From
On Tue, Aug 21, 2012 at 1:00 PM, Roland Stigge <stigge@antcom.de> wrote:
> 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>

> ---
> Applies to v3.6-rc2
>
> Patch set changes since v4:
> * Rename DT property: "pl022,num-chipselects" -> "num-cs"
> * Removed reference to Linux code in DT binding documentation
> * Removed property "pl022,hierarchy" - only support SPI master for now
> * Documented DT property pl022,interface
> * Removed property "pl022,slave-tx-disable" - not relevant in master mode
> * Added kerneldoc for cur_cs and chipselect list
> * Reorganized struct pl022 (int *chipselect)
> * Introduced int *chipselects to struct pl022_ssp_controller
> * Let platform data override DT data
> * Split patches into CS handling vs. DT support
>
> Changes since v3:
> * Proper use of IS_ENABLED
>
> Changes since v2:
> * Use IS_ENABLED instead of #ifdef
> * Remove bogus const change
>
> Changes since v1:
> * return EPROBE_DEFFER if gpios are not initialized yet
>
> Thanks Thierry Reding, Rob Herring and Linus Walleij for reviewing!
>
> drivers/spi/spi-pl022.c | 47 +++++++++++++++++++++++++++++++--------------
> include/linux/amba/pl022.h | 2 +
> 2 files changed, 35 insertions(+), 14 deletions(-)
>
> --- linux-2.6.orig/drivers/spi/spi-pl022.c
> +++ linux-2.6/drivers/spi/spi-pl022.c
> @@ -40,6 +40,7 @@
> #include <linux/dma-mapping.h>
> #include <linux/scatterlist.h>
> #include <linux/pm_runtime.h>
> +#include <linux/gpio.h>
>
> /*
> * This macro is used to define some register default values.
> @@ -356,6 +357,8 @@ struct vendor_data {
> * @sgt_rx: scattertable for the RX transfer
> * @sgt_tx: scattertable for the TX transfer
> * @dummypage: a dummy page used for driving data on the bus with DMA
> + * @cur_cs: current chip select (gpio)
> + * @chipselect: list of chipselects (gpios)
> */
> struct pl022 {
> struct amba_device *adev;
> @@ -389,6 +392,8 @@ struct pl022 {
> char *dummypage;
> bool dma_running;
> #endif
> + int cur_cs;
> + int *chipselect;
> };
>
> /**
> @@ -433,6 +438,14 @@ static void null_cs_control(u32 command)
> pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
> }
>
> +static void pl022_cs_control(struct pl022 *pl022, u32 command)
> +{
> + if (gpio_is_valid(pl022->cur_cs))
> + gpio_set_value(pl022->cur_cs, command);
> + else
> + pl022->cur_chip->cs_control(command);
> +}
> +
> /**
> * giveback - current spi_message is over, schedule next message and call
> * callback of this message. Assumes that caller already
> @@ -479,7 +492,7 @@ static void giveback(struct pl022 *pl022
> if (next_msg && next_msg->spi != pl022->cur_msg->spi)
> next_msg = NULL;
> if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
> - pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
> + pl022_cs_control(pl022, SSP_CHIP_DESELECT);
> else
> pl022->next_msg_cs_active = true;
>
> @@ -818,8 +831,7 @@ static void dma_callback(void *data)
> /* Update total bytes transferred */
> msg->actual_length += pl022->cur_transfer->len;
> if (pl022->cur_transfer->cs_change)
> - pl022->cur_chip->
> - cs_control(SSP_CHIP_DESELECT);
> + pl022_cs_control(pl022, SSP_CHIP_DESELECT);
>
> /* Move to next transfer */
> msg->state = next_transfer(pl022);
> @@ -1252,8 +1264,7 @@ static irqreturn_t pl022_interrupt_handl
> /* Update total bytes transferred */
> msg->actual_length += pl022->cur_transfer->len;
> if (pl022->cur_transfer->cs_change)
> - pl022->cur_chip->
> - cs_control(SSP_CHIP_DESELECT);
> + pl022_cs_control(pl022, SSP_CHIP_DESELECT);
> /* Move to next transfer */
> msg->state = next_transfer(pl022);
> tasklet_schedule(&pl022->pump_transfers);
> @@ -1338,7 +1349,7 @@ static void pump_transfers(unsigned long
>
> /* Reselect chip select only if cs_change was requested */
> if (previous->cs_change)
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + pl022_cs_control(pl022, SSP_CHIP_SELECT);
> } else {
> /* STATE_START */
> message->state = STATE_RUNNING;
> @@ -1377,7 +1388,7 @@ static void do_interrupt_dma_transfer(st
>
> /* Enable target chip, if not already active */
> if (!pl022->next_msg_cs_active)
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + pl022_cs_control(pl022, SSP_CHIP_SELECT);
>
> if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
> /* Error path */
> @@ -1429,12 +1440,12 @@ static void do_polling_transfer(struct p
> if (previous->delay_usecs)
> udelay(previous->delay_usecs);
> if (previous->cs_change)
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + pl022_cs_control(pl022, SSP_CHIP_SELECT);
> } else {
> /* STATE_START */
> message->state = STATE_RUNNING;
> if (!pl022->next_msg_cs_active)
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + pl022_cs_control(pl022, SSP_CHIP_SELECT);
> }
>
> /* Configuration Changing Per Transfer */
> @@ -1466,7 +1477,7 @@ static void do_polling_transfer(struct p
> /* Update total byte transferred */
> message->actual_length += pl022->cur_transfer->len;
> if (pl022->cur_transfer->cs_change)
> - pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
> + pl022_cs_control(pl022, SSP_CHIP_DESELECT);
> /* Move to next transfer */
> message->state = next_transfer(pl022);
> }
> @@ -1495,6 +1506,7 @@ static int pl022_transfer_one_message(st
>
> /* Setup the SPI using the per chip configuration */
> pl022->cur_chip = spi_get_ctldata(msg->spi);
> + pl022->cur_cs = pl022->chipselect[msg->spi->chip_select];
>
> restore_state(pl022);
> flush(pl022);
> @@ -1840,8 +1852,9 @@ static int pl022_setup(struct spi_device
> chip->xfer_type = chip_info->com_mode;
> if (!chip_info->cs_control) {
> chip->cs_control = null_cs_control;
> - dev_warn(&spi->dev,
> - "chip select function is NULL for this chip\n");
> + if (!gpio_is_valid(pl022->chipselect[spi->chip_select]))
> + dev_warn(&spi->dev,
> + "chip select function is NULL for this chip\n");
> } else
> chip->cs_control = chip_info->cs_control;
>
> @@ -1993,7 +2006,7 @@ pl022_probe(struct amba_device *adev, co
> struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
> struct spi_master *master;
> struct pl022 *pl022 = NULL; /*Data for this driver */
> - int status = 0;
> + int status = 0, i;
>
> dev_info(&adev->dev,
> "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid);
> @@ -2004,7 +2017,8 @@ pl022_probe(struct amba_device *adev, co
> }
>
> /* Allocate master with space for data */
> - master = spi_alloc_master(dev, sizeof(struct pl022));
> + master = spi_alloc_master(dev, sizeof(struct pl022) + sizeof(int) *
> + platform_info->num_chipselect);
> if (master == NULL) {
> dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
> status = -ENOMEM;
> @@ -2016,6 +2030,7 @@ pl022_probe(struct amba_device *adev, co
> pl022->master_info = platform_info;
> pl022->adev = adev;
> pl022->vendor = id->data;
> + pl022->chipselect = (int *)&master[1];
>
> /*
> * Bus Number Which has been Assigned to this SSP controller
> @@ -2030,6 +2045,10 @@ pl022_probe(struct amba_device *adev, co
> master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
> master->rt = platform_info->rt;
>
> + if (platform_info->num_chipselect && platform_info->chipselects)
> + for (i = 0; i < platform_info->num_chipselect; i++)
> + pl022->chipselect[i] = platform_info->chipselects[i];
> +
> /*
> * Supports mode 0-3, loopback, and active low CS. Transfers are
> * always MS bit first on the original pl022.
> --- linux-2.6.orig/include/linux/amba/pl022.h
> +++ linux-2.6/include/linux/amba/pl022.h
> @@ -244,6 +244,7 @@ struct dma_chan;
> * indicates no delay and the device will be suspended immediately.
> * @rt: indicates the controller should run the message pump with realtime
> * priority to minimise the transfer latency on the bus.
> + * @chipselects: list of <num_chipselects> chip select gpios
> */
> struct pl022_ssp_controller {
> u16 bus_id;
> @@ -254,6 +255,7 @@ struct pl022_ssp_controller {
> void *dma_tx_param;
> int autosuspend_delay;
> bool rt;
> + int *chipselects;
> };
>
> /**


\
 
 \ /
  Last update: 2012-08-22 02:01    [W:0.058 / U:0.360 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site