|
@@ -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 {
|
|
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 {
|
|
|
|
|
|
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)
|
|
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)
|
|
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)
|
|
* 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)
|
|
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)
|
|
|
|
|
|
/* 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)
|
|
}
|
|
}
|
|
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)
|
|
write_SSTO(chip->timeout, reg);
|
|
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
|
|
/* 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)
|
|
/* 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)
|
|
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)
|
|
/* 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)
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|