Commit a7bb3909 authored by Eric Miao's avatar Eric Miao Committed by Linus Torvalds

spi: pxa2xx_spi: introduce chipselect GPIO to simplify the common cases

Most SPI peripherals use GPIOs as their chip selects, introduce .gpio_cs
for this.
Signed-off-by: default avatarEric Miao <eric.miao@marvell.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c8fc657e
...@@ -38,6 +38,7 @@ struct pxa2xx_spi_chip { ...@@ -38,6 +38,7 @@ struct pxa2xx_spi_chip {
u8 dma_burst_size; u8 dma_burst_size;
u32 timeout; u32 timeout;
u8 enable_loopback; u8 enable_loopback;
int gpio_cs;
void (*cs_control)(u32 command); void (*cs_control)(u32 command);
}; };
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/gpio.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -166,6 +167,8 @@ struct chip_data { ...@@ -166,6 +167,8 @@ struct chip_data {
u8 enable_dma; u8 enable_dma;
u8 bits_per_word; u8 bits_per_word;
u32 speed_hz; u32 speed_hz;
int gpio_cs;
int gpio_cs_inverted;
int (*write)(struct driver_data *drv_data); int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data);
void (*cs_control)(u32 command); void (*cs_control)(u32 command);
...@@ -173,6 +176,32 @@ struct chip_data { ...@@ -173,6 +176,32 @@ struct chip_data {
static void pump_messages(struct work_struct *work); static void pump_messages(struct work_struct *work);
static void cs_assert(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_ASSERT);
return;
}
if (gpio_is_valid(chip->gpio_cs))
gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted);
}
static void cs_deassert(struct driver_data *drv_data)
{
struct chip_data *chip = drv_data->cur_chip;
if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_ASSERT);
return;
}
if (gpio_is_valid(chip->gpio_cs))
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
}
static int flush(struct driver_data *drv_data) static int flush(struct driver_data *drv_data)
{ {
unsigned long limit = loops_per_jiffy << 1; unsigned long limit = loops_per_jiffy << 1;
...@@ -189,10 +218,6 @@ static int flush(struct driver_data *drv_data) ...@@ -189,10 +218,6 @@ static int flush(struct driver_data *drv_data)
return limit; return limit;
} }
static void null_cs_control(u32 command)
{
}
static int null_writer(struct driver_data *drv_data) static int null_writer(struct driver_data *drv_data)
{ {
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
...@@ -400,7 +425,6 @@ static void giveback(struct driver_data *drv_data) ...@@ -400,7 +425,6 @@ static void giveback(struct driver_data *drv_data)
msg = drv_data->cur_msg; msg = drv_data->cur_msg;
drv_data->cur_msg = NULL; drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL; drv_data->cur_transfer = NULL;
drv_data->cur_chip = NULL;
queue_work(drv_data->workqueue, &drv_data->pump_messages); queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags); spin_unlock_irqrestore(&drv_data->lock, flags);
...@@ -416,7 +440,7 @@ static void giveback(struct driver_data *drv_data) ...@@ -416,7 +440,7 @@ static void giveback(struct driver_data *drv_data)
* a message with an error, or next message is for another chip * a message with an error, or next message is for another chip
*/ */
if (!last_transfer->cs_change) if (!last_transfer->cs_change)
drv_data->cs_control(PXA2XX_CS_DEASSERT); cs_deassert(drv_data);
else { else {
struct spi_message *next_msg; struct spi_message *next_msg;
...@@ -445,12 +469,14 @@ static void giveback(struct driver_data *drv_data) ...@@ -445,12 +469,14 @@ static void giveback(struct driver_data *drv_data)
if (next_msg && next_msg->spi != msg->spi) if (next_msg && next_msg->spi != msg->spi)
next_msg = NULL; next_msg = NULL;
if (!next_msg || msg->state == ERROR_STATE) if (!next_msg || msg->state == ERROR_STATE)
drv_data->cs_control(PXA2XX_CS_DEASSERT); cs_deassert(drv_data);
} }
msg->state = NULL; msg->state = NULL;
if (msg->complete) if (msg->complete)
msg->complete(msg->context); msg->complete(msg->context);
drv_data->cur_chip = NULL;
} }
static int wait_ssp_rx_stall(void const __iomem *ioaddr) static int wait_ssp_rx_stall(void const __iomem *ioaddr)
...@@ -887,7 +913,7 @@ static void pump_transfers(unsigned long data) ...@@ -887,7 +913,7 @@ static void pump_transfers(unsigned long data)
/* Drop chip select only if cs_change is requested */ /* Drop chip select only if cs_change is requested */
if (previous->cs_change) if (previous->cs_change)
drv_data->cs_control(PXA2XX_CS_DEASSERT); cs_deassert(drv_data);
} }
/* Check for transfers that need multiple DMA segments */ /* Check for transfers that need multiple DMA segments */
...@@ -922,7 +948,6 @@ static void pump_transfers(unsigned long data) ...@@ -922,7 +948,6 @@ static void pump_transfers(unsigned long data)
} }
drv_data->n_bytes = chip->n_bytes; drv_data->n_bytes = chip->n_bytes;
drv_data->dma_width = chip->dma_width; drv_data->dma_width = chip->dma_width;
drv_data->cs_control = chip->cs_control;
drv_data->tx = (void *)transfer->tx_buf; drv_data->tx = (void *)transfer->tx_buf;
drv_data->tx_end = drv_data->tx + transfer->len; drv_data->tx_end = drv_data->tx + transfer->len;
drv_data->rx = transfer->rx_buf; drv_data->rx = transfer->rx_buf;
...@@ -1084,11 +1109,7 @@ static void pump_transfers(unsigned long data) ...@@ -1084,11 +1109,7 @@ static void pump_transfers(unsigned long data)
write_SSTO(chip->timeout, reg); write_SSTO(chip->timeout, reg);
} }
/* FIXME, need to handle cs polarity, cs_assert(drv_data);
* this driver uses struct pxa2xx_spi_chip.cs_control to
* specify a CS handling function, and it ignores most
* struct spi_device.mode[s], including SPI_CS_HIGH */
drv_data->cs_control(PXA2XX_CS_ASSERT);
/* after chip select, release the data by enabling service /* after chip select, release the data by enabling service
* requests and interrupts, without changing any mode bits */ * requests and interrupts, without changing any mode bits */
...@@ -1166,6 +1187,44 @@ static int transfer(struct spi_device *spi, struct spi_message *msg) ...@@ -1166,6 +1187,44 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
#define MODEBITS (SPI_CPOL | SPI_CPHA) #define MODEBITS (SPI_CPOL | SPI_CPHA)
static int setup_cs(struct spi_device *spi, struct chip_data *chip,
struct pxa2xx_spi_chip *chip_info)
{
int err = 0;
if (chip == NULL || chip_info == NULL)
return 0;
/* NOTE: setup() can be called multiple times, possibly with
* different chip_info, release previously requested GPIO
*/
if (gpio_is_valid(chip->gpio_cs))
gpio_free(chip->gpio_cs);
/* If (*cs_control) is provided, ignore GPIO chip select */
if (chip_info->cs_control) {
chip->cs_control = chip_info->cs_control;
return 0;
}
if (gpio_is_valid(chip_info->gpio_cs)) {
err = gpio_request(chip_info->gpio_cs, "SPI_CS");
if (err) {
dev_err(&spi->dev, "failed to request chip select "
"GPIO%d\n", chip_info->gpio_cs);
return err;
}
chip->gpio_cs = chip_info->gpio_cs;
chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
err = gpio_direction_output(chip->gpio_cs,
!chip->gpio_cs_inverted);
}
return err;
}
static int setup(struct spi_device *spi) static int setup(struct spi_device *spi)
{ {
struct pxa2xx_spi_chip *chip_info = NULL; struct pxa2xx_spi_chip *chip_info = NULL;
...@@ -1211,7 +1270,7 @@ static int setup(struct spi_device *spi) ...@@ -1211,7 +1270,7 @@ static int setup(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
} }
chip->cs_control = null_cs_control; chip->gpio_cs = -1;
chip->enable_dma = 0; chip->enable_dma = 0;
chip->timeout = TIMOUT_DFLT; chip->timeout = TIMOUT_DFLT;
chip->dma_burst_size = drv_data->master_info->enable_dma ? chip->dma_burst_size = drv_data->master_info->enable_dma ?
...@@ -1225,8 +1284,6 @@ static int setup(struct spi_device *spi) ...@@ -1225,8 +1284,6 @@ static int setup(struct spi_device *spi)
/* chip_info isn't always needed */ /* chip_info isn't always needed */
chip->cr1 = 0; chip->cr1 = 0;
if (chip_info) { if (chip_info) {
if (chip_info->cs_control)
chip->cs_control = chip_info->cs_control;
if (chip_info->timeout) if (chip_info->timeout)
chip->timeout = chip_info->timeout; chip->timeout = chip_info->timeout;
if (chip_info->tx_threshold) if (chip_info->tx_threshold)
...@@ -1308,13 +1365,16 @@ static int setup(struct spi_device *spi) ...@@ -1308,13 +1365,16 @@ static int setup(struct spi_device *spi)
spi_set_ctldata(spi, chip); spi_set_ctldata(spi, chip);
return 0; return setup_cs(spi, chip, chip_info);
} }
static void cleanup(struct spi_device *spi) static void cleanup(struct spi_device *spi)
{ {
struct chip_data *chip = spi_get_ctldata(spi); struct chip_data *chip = spi_get_ctldata(spi);
if (gpio_is_valid(chip->gpio_cs))
gpio_free(chip->gpio_cs);
kfree(chip); kfree(chip);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment