summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-davinci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-davinci.c')
-rw-r--r--drivers/spi/spi-davinci.c95
1 files changed, 80 insertions, 15 deletions
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index c457b550d3ad..21a14e800eed 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -9,6 +9,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/platform_data/edma.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
@@ -19,8 +20,6 @@
#include <linux/spi/spi_bitbang.h>
#include <linux/slab.h>
-#include <linux/platform_data/spi-davinci.h>
-
#define CS_DEFAULT 0xFF
#define SPIFMT_PHASE_MASK BIT(16)
@@ -98,8 +97,69 @@
#define SPIDEF 0x4c
#define SPIFMT0 0x50
+#define SPI_IO_TYPE_POLL 1
+#define SPI_IO_TYPE_DMA 2
+
#define DMA_MIN_BYTES 16
+enum {
+ SPI_VERSION_1, /* For DM355/DM365/DM6467 */
+ SPI_VERSION_2, /* For DA8xx */
+};
+
+/**
+ * struct davinci_spi_platform_data - Platform data for SPI master device on DaVinci
+ *
+ * @version: version of the SPI IP. Different DaVinci devices have slightly
+ * varying versions of the same IP.
+ * @num_chipselect: number of chipselects supported by this SPI master
+ * @intr_line: interrupt line used to connect the SPI IP to the ARM interrupt
+ * controller withn the SoC. Possible values are 0 and 1.
+ * @prescaler_limit: max clock prescaler value
+ * @cshold_bug: set this to true if the SPI controller on your chip requires
+ * a write to CSHOLD bit in between transfers (like in DM355).
+ * @dma_event_q: DMA event queue to use if SPI_IO_TYPE_DMA is used for any
+ * device on the bus.
+ */
+struct davinci_spi_platform_data {
+ u8 version;
+ u8 num_chipselect;
+ u8 intr_line;
+ u8 prescaler_limit;
+ bool cshold_bug;
+ enum dma_event_q dma_event_q;
+};
+
+/**
+ * struct davinci_spi_config - Per-chip-select configuration for SPI slave devices
+ *
+ * @wdelay: amount of delay between transmissions. Measured in number of
+ * SPI module clocks.
+ * @odd_parity: polarity of parity flag at the end of transmit data stream.
+ * 0 - odd parity, 1 - even parity.
+ * @parity_enable: enable transmission of parity at end of each transmit
+ * data stream.
+ * @io_type: type of IO transfer. Choose between polled, interrupt and DMA.
+ * @timer_disable: disable chip-select timers (setup and hold)
+ * @c2tdelay: chip-select setup time. Measured in number of SPI module clocks.
+ * @t2cdelay: chip-select hold time. Measured in number of SPI module clocks.
+ * @t2edelay: transmit data finished to SPI ENAn pin inactive time. Measured
+ * in number of SPI clocks.
+ * @c2edelay: chip-select active to SPI ENAn signal active time. Measured in
+ * number of SPI clocks.
+ */
+struct davinci_spi_config {
+ u8 wdelay;
+ u8 odd_parity;
+ u8 parity_enable;
+ u8 io_type;
+ u8 timer_disable;
+ u8 c2tdelay;
+ u8 t2cdelay;
+ u8 t2edelay;
+ u8 c2edelay;
+};
+
/* SPI Controller driver's private data. */
struct davinci_spi {
struct spi_bitbang bitbang;
@@ -459,7 +519,7 @@ static bool davinci_spi_can_dma(struct spi_controller *host,
static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
{
- struct device *sdev = dspi->bitbang.master->dev.parent;
+ struct device *sdev = dspi->bitbang.ctlr->dev.parent;
if (int_status & SPIFLG_TIMEOUT_MASK) {
dev_err(sdev, "SPI Time-out Error\n");
@@ -570,6 +630,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
u32 errors = 0;
struct davinci_spi_config *spicfg;
struct davinci_spi_platform_data *pdata;
+ unsigned long timeout;
dspi = spi_controller_get_devdata(spi->controller);
pdata = &dspi->pdata;
@@ -661,7 +722,12 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
/* Wait for the transfer to complete */
if (spicfg->io_type != SPI_IO_TYPE_POLL) {
- if (wait_for_completion_timeout(&dspi->done, HZ) == 0)
+ timeout = DIV_ROUND_UP(t->speed_hz, MSEC_PER_SEC);
+ timeout = DIV_ROUND_UP(t->len * 8, timeout);
+ /* Assume we are at most 2x slower than the nominal bus speed */
+ timeout = 2 * msecs_to_jiffies(timeout);
+
+ if (wait_for_completion_timeout(&dspi->done, timeout) == 0)
errors = SPIFLG_TIMEOUT_MASK;
} else {
while (dspi->rcount > 0 || dspi->wcount > 0) {
@@ -742,7 +808,7 @@ static irqreturn_t davinci_spi_irq(s32 irq, void *data)
static int davinci_spi_request_dma(struct davinci_spi *dspi)
{
- struct device *sdev = dspi->bitbang.master->dev.parent;
+ struct device *sdev = dspi->bitbang.ctlr->dev.parent;
dspi->dma_rx = dma_request_chan(sdev, "rx");
if (IS_ERR(dspi->dma_rx))
@@ -913,16 +979,13 @@ static int davinci_spi_probe(struct platform_device *pdev)
if (ret)
goto free_host;
- dspi->bitbang.master = host;
+ dspi->bitbang.ctlr = host;
- dspi->clk = devm_clk_get(&pdev->dev, NULL);
+ dspi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(dspi->clk)) {
ret = -ENODEV;
goto free_host;
}
- ret = clk_prepare_enable(dspi->clk);
- if (ret)
- goto free_host;
host->use_gpio_descriptors = true;
host->dev.of_node = pdev->dev.of_node;
@@ -947,7 +1010,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
ret = davinci_spi_request_dma(dspi);
if (ret == -EPROBE_DEFER) {
- goto free_clk;
+ goto free_host;
} else if (ret) {
dev_info(&pdev->dev, "DMA is not supported (%d)\n", ret);
dspi->dma_rx = NULL;
@@ -987,12 +1050,13 @@ static int davinci_spi_probe(struct platform_device *pdev)
return ret;
free_dma:
+ /* This bit needs to be cleared to disable dpsi->clk */
+ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
+
if (dspi->dma_rx) {
dma_release_channel(dspi->dma_rx);
dma_release_channel(dspi->dma_tx);
}
-free_clk:
- clk_disable_unprepare(dspi->clk);
free_host:
spi_controller_put(host);
err:
@@ -1018,7 +1082,8 @@ static void davinci_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&dspi->bitbang);
- clk_disable_unprepare(dspi->clk);
+ /* This bit needs to be cleared to disable dpsi->clk */
+ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
if (dspi->dma_rx) {
dma_release_channel(dspi->dma_rx);
@@ -1034,7 +1099,7 @@ static struct platform_driver davinci_spi_driver = {
.of_match_table = of_match_ptr(davinci_spi_of_match),
},
.probe = davinci_spi_probe,
- .remove_new = davinci_spi_remove,
+ .remove = davinci_spi_remove,
};
module_platform_driver(davinci_spi_driver);