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: Eric Miao <eric.miao@marvell.com> Cc: David Brownell <david-b@pacbell.net> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
c8fc657e6a
commit
a7bb3909b3
2 changed files with 79 additions and 18 deletions
|
@ -38,6 +38,7 @@ struct pxa2xx_spi_chip {
|
|||
u8 dma_burst_size;
|
||||
u32 timeout;
|
||||
u8 enable_loopback;
|
||||
int gpio_cs;
|
||||
void (*cs_control)(u32 command);
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
@ -166,6 +167,8 @@ struct chip_data {
|
|||
u8 enable_dma;
|
||||
u8 bits_per_word;
|
||||
u32 speed_hz;
|
||||
int gpio_cs;
|
||||
int gpio_cs_inverted;
|
||||
int (*write)(struct driver_data *drv_data);
|
||||
int (*read)(struct driver_data *drv_data);
|
||||
void (*cs_control)(u32 command);
|
||||
|
@ -173,6 +176,32 @@ struct chip_data {
|
|||
|
||||
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)
|
||||
{
|
||||
unsigned long limit = loops_per_jiffy << 1;
|
||||
|
@ -189,10 +218,6 @@ static int flush(struct driver_data *drv_data)
|
|||
return limit;
|
||||
}
|
||||
|
||||
static void null_cs_control(u32 command)
|
||||
{
|
||||
}
|
||||
|
||||
static int null_writer(struct driver_data *drv_data)
|
||||
{
|
||||
void __iomem *reg = drv_data->ioaddr;
|
||||
|
@ -400,7 +425,6 @@ static void giveback(struct driver_data *drv_data)
|
|||
msg = drv_data->cur_msg;
|
||||
drv_data->cur_msg = NULL;
|
||||
drv_data->cur_transfer = NULL;
|
||||
drv_data->cur_chip = NULL;
|
||||
queue_work(drv_data->workqueue, &drv_data->pump_messages);
|
||||
spin_unlock_irqrestore(&drv_data->lock, flags);
|
||||
|
||||
|
@ -416,7 +440,7 @@ static void giveback(struct driver_data *drv_data)
|
|||
* a message with an error, or next message is for another chip
|
||||
*/
|
||||
if (!last_transfer->cs_change)
|
||||
drv_data->cs_control(PXA2XX_CS_DEASSERT);
|
||||
cs_deassert(drv_data);
|
||||
else {
|
||||
struct spi_message *next_msg;
|
||||
|
||||
|
@ -445,12 +469,14 @@ static void giveback(struct driver_data *drv_data)
|
|||
if (next_msg && next_msg->spi != msg->spi)
|
||||
next_msg = NULL;
|
||||
if (!next_msg || msg->state == ERROR_STATE)
|
||||
drv_data->cs_control(PXA2XX_CS_DEASSERT);
|
||||
cs_deassert(drv_data);
|
||||
}
|
||||
|
||||
msg->state = NULL;
|
||||
if (msg->complete)
|
||||
msg->complete(msg->context);
|
||||
|
||||
drv_data->cur_chip = NULL;
|
||||
}
|
||||
|
||||
static int wait_ssp_rx_stall(void const __iomem *ioaddr)
|
||||
|
@ -887,7 +913,7 @@ static void pump_transfers(unsigned long data)
|
|||
|
||||
/* Drop chip select only if cs_change is requested */
|
||||
if (previous->cs_change)
|
||||
drv_data->cs_control(PXA2XX_CS_DEASSERT);
|
||||
cs_deassert(drv_data);
|
||||
}
|
||||
|
||||
/* Check for transfers that need multiple DMA segments */
|
||||
|
@ -922,7 +948,6 @@ static void pump_transfers(unsigned long data)
|
|||
}
|
||||
drv_data->n_bytes = chip->n_bytes;
|
||||
drv_data->dma_width = chip->dma_width;
|
||||
drv_data->cs_control = chip->cs_control;
|
||||
drv_data->tx = (void *)transfer->tx_buf;
|
||||
drv_data->tx_end = drv_data->tx + transfer->len;
|
||||
drv_data->rx = transfer->rx_buf;
|
||||
|
@ -1084,11 +1109,7 @@ static void pump_transfers(unsigned long data)
|
|||
write_SSTO(chip->timeout, reg);
|
||||
}
|
||||
|
||||
/* FIXME, need to handle cs polarity,
|
||||
* 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);
|
||||
cs_assert(drv_data);
|
||||
|
||||
/* after chip select, release the data by enabling service
|
||||
* requests and interrupts, without changing any mode bits */
|
||||
|
@ -1166,6 +1187,44 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
|
|||
/* the spi->mode bits understood by this driver: */
|
||||
#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)
|
||||
{
|
||||
struct pxa2xx_spi_chip *chip_info = NULL;
|
||||
|
@ -1211,7 +1270,7 @@ static int setup(struct spi_device *spi)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chip->cs_control = null_cs_control;
|
||||
chip->gpio_cs = -1;
|
||||
chip->enable_dma = 0;
|
||||
chip->timeout = TIMOUT_DFLT;
|
||||
chip->dma_burst_size = drv_data->master_info->enable_dma ?
|
||||
|
@ -1225,8 +1284,6 @@ static int setup(struct spi_device *spi)
|
|||
/* chip_info isn't always needed */
|
||||
chip->cr1 = 0;
|
||||
if (chip_info) {
|
||||
if (chip_info->cs_control)
|
||||
chip->cs_control = chip_info->cs_control;
|
||||
if (chip_info->timeout)
|
||||
chip->timeout = chip_info->timeout;
|
||||
if (chip_info->tx_threshold)
|
||||
|
@ -1308,13 +1365,16 @@ static int setup(struct spi_device *spi)
|
|||
|
||||
spi_set_ctldata(spi, chip);
|
||||
|
||||
return 0;
|
||||
return setup_cs(spi, chip, chip_info);
|
||||
}
|
||||
|
||||
static void cleanup(struct spi_device *spi)
|
||||
{
|
||||
struct chip_data *chip = spi_get_ctldata(spi);
|
||||
|
||||
if (gpio_is_valid(chip->gpio_cs))
|
||||
gpio_free(chip->gpio_cs);
|
||||
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue