summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-bcm2835.c28
-rw-r--r--drivers/spi/spi-bitbang-txrx.h4
-rw-r--r--drivers/spi/spi-dw-mmio.c3
-rw-r--r--drivers/spi/spi-dw.c4
-rw-r--r--drivers/spi/spi-dw.h35
-rw-r--r--drivers/spi/spi-img-spfi.c59
-rw-r--r--drivers/spi/spi-omap2-mcspi.c10
-rw-r--r--drivers/spi/spi-orion.c54
-rw-r--r--drivers/spi/spi-sh-msiof.c15
-rw-r--r--drivers/spi/spi-xilinx.c20
10 files changed, 196 insertions, 36 deletions
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 59705ab23..c9357bb39 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -553,13 +553,11 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536);
bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
- /* handle all the modes */
+ /* handle all the 3-wire mode */
if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
cs |= BCM2835_SPI_CS_REN;
- if (spi->mode & SPI_CPOL)
- cs |= BCM2835_SPI_CS_CPOL;
- if (spi->mode & SPI_CPHA)
- cs |= BCM2835_SPI_CS_CPHA;
+ else
+ cs &= ~BCM2835_SPI_CS_REN;
/* for gpio_cs set dummy CS so that no HW-CS get changed
* we can not run this in bcm2835_spi_set_cs, as it does
@@ -592,6 +590,25 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
}
+static int bcm2835_spi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct spi_device *spi = msg->spi;
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+ cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA);
+
+ if (spi->mode & SPI_CPOL)
+ cs |= BCM2835_SPI_CS_CPOL;
+ if (spi->mode & SPI_CPHA)
+ cs |= BCM2835_SPI_CS_CPHA;
+
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+
+ return 0;
+}
+
static void bcm2835_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
@@ -739,6 +756,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
master->set_cs = bcm2835_spi_set_cs;
master->transfer_one = bcm2835_spi_transfer_one;
master->handle_err = bcm2835_spi_handle_err;
+ master->prepare_message = bcm2835_spi_prepare_message;
master->dev.of_node = pdev->dev.of_node;
bs = spi_master_get_devdata(master);
diff --git a/drivers/spi/spi-bitbang-txrx.h b/drivers/spi/spi-bitbang-txrx.h
index 06b34e5bc..47bb9b898 100644
--- a/drivers/spi/spi-bitbang-txrx.h
+++ b/drivers/spi/spi-bitbang-txrx.h
@@ -49,7 +49,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
{
/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
- bool oldbit = !(word & 1);
+ u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
/* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) {
@@ -81,7 +81,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
{
/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
- bool oldbit = !(word & (1 << 31));
+ u32 oldbit = (!(word & (1<<(bits-1)))) << 31;
/* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) {
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index eb03e1215..7edede6e0 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -74,6 +74,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
dws->max_freq = clk_get_rate(dwsmmio->clk);
+ of_property_read_u32(pdev->dev.of_node, "reg-io-width",
+ &dws->reg_io_width);
+
num_cs = 4;
if (pdev->dev.of_node)
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 8d67d03c7..4fbfcdc5c 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -194,7 +194,7 @@ static void dw_writer(struct dw_spi *dws)
else
txw = *(u16 *)(dws->tx);
}
- dw_writel(dws, DW_SPI_DR, txw);
+ dw_write_io_reg(dws, DW_SPI_DR, txw);
dws->tx += dws->n_bytes;
}
}
@@ -205,7 +205,7 @@ static void dw_reader(struct dw_spi *dws)
u16 rxw;
while (max--) {
- rxw = dw_readl(dws, DW_SPI_DR);
+ rxw = dw_read_io_reg(dws, DW_SPI_DR);
/* Care rx only if the transfer's original "rx" is not null */
if (dws->rx_end - dws->len) {
if (dws->n_bytes == 1)
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 6c91391c1..b75ed327d 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -109,6 +109,7 @@ struct dw_spi {
u32 fifo_len; /* depth of the FIFO buffer */
u32 max_freq; /* max bus freq supported */
+ u32 reg_io_width; /* DR I/O width in bytes */
u16 bus_num;
u16 num_cs; /* supported slave numbers */
@@ -145,11 +146,45 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset)
return __raw_readl(dws->regs + offset);
}
+static inline u16 dw_readw(struct dw_spi *dws, u32 offset)
+{
+ return __raw_readw(dws->regs + offset);
+}
+
static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
{
__raw_writel(val, dws->regs + offset);
}
+static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val)
+{
+ __raw_writew(val, dws->regs + offset);
+}
+
+static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset)
+{
+ switch (dws->reg_io_width) {
+ case 2:
+ return dw_readw(dws, offset);
+ case 4:
+ default:
+ return dw_readl(dws, offset);
+ }
+}
+
+static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
+{
+ switch (dws->reg_io_width) {
+ case 2:
+ dw_writew(dws, offset, val);
+ break;
+ case 4:
+ default:
+ dw_writel(dws, offset, val);
+ break;
+ }
+}
+
static inline void spi_enable_chip(struct dw_spi *dws, int enable)
{
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index acce90ac7..bb916c8d4 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -105,6 +105,10 @@ struct img_spfi {
bool rx_dma_busy;
};
+struct img_spfi_device_data {
+ bool gpio_requested;
+};
+
static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
{
return readl(spfi->regs + reg);
@@ -267,15 +271,15 @@ static int img_spfi_start_pio(struct spi_master *master,
cpu_relax();
}
- ret = spfi_wait_all_done(spfi);
- if (ret < 0)
- return ret;
-
if (rx_bytes > 0 || tx_bytes > 0) {
dev_err(spfi->dev, "PIO transfer timed out\n");
return -ETIMEDOUT;
}
+ ret = spfi_wait_all_done(spfi);
+ if (ret < 0)
+ return ret;
+
return 0;
}
@@ -440,21 +444,50 @@ static int img_spfi_unprepare(struct spi_master *master,
static int img_spfi_setup(struct spi_device *spi)
{
- int ret;
-
- ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
- GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
- dev_name(&spi->dev));
- if (ret)
- dev_err(&spi->dev, "can't request chipselect gpio %d\n",
+ int ret = -EINVAL;
+ struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
+
+ if (!spfi_data) {
+ spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL);
+ if (!spfi_data)
+ return -ENOMEM;
+ spfi_data->gpio_requested = false;
+ spi_set_ctldata(spi, spfi_data);
+ }
+ if (!spfi_data->gpio_requested) {
+ ret = gpio_request_one(spi->cs_gpio,
+ (spi->mode & SPI_CS_HIGH) ?
+ GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+ dev_name(&spi->dev));
+ if (ret)
+ dev_err(&spi->dev, "can't request chipselect gpio %d\n",
spi->cs_gpio);
-
+ else
+ spfi_data->gpio_requested = true;
+ } else {
+ if (gpio_is_valid(spi->cs_gpio)) {
+ int mode = ((spi->mode & SPI_CS_HIGH) ?
+ GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
+
+ ret = gpio_direction_output(spi->cs_gpio, mode);
+ if (ret)
+ dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
+ spi->cs_gpio, ret);
+ }
+ }
return ret;
}
static void img_spfi_cleanup(struct spi_device *spi)
{
- gpio_free(spi->cs_gpio);
+ struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi);
+
+ if (spfi_data) {
+ if (spfi_data->gpio_requested)
+ gpio_free(spi->cs_gpio);
+ kfree(spfi_data);
+ spi_set_ctldata(spi, NULL);
+ }
}
static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 586738412..3d09e0b69 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
u32 l;
/* The controller handles the inverted chip selects
@@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
enable = !enable;
if (spi->controller_state) {
+ int err = pm_runtime_get_sync(mcspi->dev);
+ if (err < 0) {
+ dev_err(mcspi->dev, "failed to get sync: %d\n", err);
+ return;
+ }
+
l = mcspi_cached_chconf0(spi);
if (enable)
@@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
l |= OMAP2_MCSPI_CHCONF_FORCE;
mcspi_write_chconf0(spi, l);
+
+ pm_runtime_mark_last_busy(mcspi->dev);
+ pm_runtime_put_autosuspend(mcspi->dev);
}
}
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 8cad107a5..a87cfd4ba 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -41,6 +41,11 @@
#define ORION_SPI_DATA_OUT_REG 0x08
#define ORION_SPI_DATA_IN_REG 0x0c
#define ORION_SPI_INT_CAUSE_REG 0x10
+#define ORION_SPI_TIMING_PARAMS_REG 0x18
+
+#define ORION_SPI_TMISO_SAMPLE_MASK (0x3 << 6)
+#define ORION_SPI_TMISO_SAMPLE_1 (1 << 6)
+#define ORION_SPI_TMISO_SAMPLE_2 (2 << 6)
#define ORION_SPI_MODE_CPOL (1 << 11)
#define ORION_SPI_MODE_CPHA (1 << 12)
@@ -70,6 +75,7 @@ struct orion_spi_dev {
unsigned int min_divisor;
unsigned int max_divisor;
u32 prescale_mask;
+ bool is_errata_50mhz_ac;
};
struct orion_spi {
@@ -195,6 +201,41 @@ orion_spi_mode_set(struct spi_device *spi)
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
}
+static void
+orion_spi_50mhz_ac_timing_erratum(struct spi_device *spi, unsigned int speed)
+{
+ u32 reg;
+ struct orion_spi *orion_spi;
+
+ orion_spi = spi_master_get_devdata(spi->master);
+
+ /*
+ * Erratum description: (Erratum NO. FE-9144572) The device
+ * SPI interface supports frequencies of up to 50 MHz.
+ * However, due to this erratum, when the device core clock is
+ * 250 MHz and the SPI interfaces is configured for 50MHz SPI
+ * clock and CPOL=CPHA=1 there might occur data corruption on
+ * reads from the SPI device.
+ * Erratum Workaround:
+ * Work in one of the following configurations:
+ * 1. Set CPOL=CPHA=0 in "SPI Interface Configuration
+ * Register".
+ * 2. Set TMISO_SAMPLE value to 0x2 in "SPI Timing Parameters 1
+ * Register" before setting the interface.
+ */
+ reg = readl(spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
+ reg &= ~ORION_SPI_TMISO_SAMPLE_MASK;
+
+ if (clk_get_rate(orion_spi->clk) == 250000000 &&
+ speed == 50000000 && spi->mode & SPI_CPOL &&
+ spi->mode & SPI_CPHA)
+ reg |= ORION_SPI_TMISO_SAMPLE_2;
+ else
+ reg |= ORION_SPI_TMISO_SAMPLE_1; /* This is the default value */
+
+ writel(reg, spi_reg(orion_spi, ORION_SPI_TIMING_PARAMS_REG));
+}
+
/*
* called only when no transfer is active on the bus
*/
@@ -216,6 +257,9 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
orion_spi_mode_set(spi);
+ if (orion_spi->devdata->is_errata_50mhz_ac)
+ orion_spi_50mhz_ac_timing_erratum(spi, speed);
+
rc = orion_spi_baudrate_set(spi, speed);
if (rc)
return rc;
@@ -413,6 +457,14 @@ static const struct orion_spi_dev armada_375_spi_dev_data = {
.prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
};
+static const struct orion_spi_dev armada_380_spi_dev_data = {
+ .typ = ARMADA_SPI,
+ .max_hz = 50000000,
+ .max_divisor = 1920,
+ .prescale_mask = ARMADA_SPI_CLK_PRESCALE_MASK,
+ .is_errata_50mhz_ac = true,
+};
+
static const struct of_device_id orion_spi_of_match_table[] = {
{
.compatible = "marvell,orion-spi",
@@ -428,7 +480,7 @@ static const struct of_device_id orion_spi_of_match_table[] = {
},
{
.compatible = "marvell,armada-380-spi",
- .data = &armada_xp_spi_dev_data,
+ .data = &armada_380_spi_dev_data,
},
{
.compatible = "marvell,armada-390-spi",
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index d3370a612..a7629f8ed 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -48,8 +48,8 @@ struct sh_msiof_spi_priv {
const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info;
struct completion done;
- int tx_fifo_size;
- int rx_fifo_size;
+ unsigned int tx_fifo_size;
+ unsigned int rx_fifo_size;
void *tx_dma_page;
void *rx_dma_page;
dma_addr_t tx_dma_addr;
@@ -95,8 +95,6 @@ struct sh_msiof_spi_priv {
#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */
-#define MAX_WDLEN 256U
-
/* TSCR and RSCR */
#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */
#define SCR_BRPS(i) (((i) - 1) << 8)
@@ -850,7 +848,12 @@ static int sh_msiof_transfer_one(struct spi_master *master,
* DMA supports 32-bit words only, hence pack 8-bit and 16-bit
* words, with byte resp. word swapping.
*/
- unsigned int l = min(len, MAX_WDLEN * 4);
+ unsigned int l = 0;
+
+ if (tx_buf)
+ l = min(len, p->tx_fifo_size * 4);
+ if (rx_buf)
+ l = min(len, p->rx_fifo_size * 4);
if (bits <= 8) {
if (l & 3)
@@ -963,7 +966,7 @@ static const struct sh_msiof_chipdata sh_data = {
static const struct sh_msiof_chipdata r8a779x_data = {
.tx_fifo_size = 64,
- .rx_fifo_size = 256,
+ .rx_fifo_size = 64,
.master_flags = SPI_MASTER_MUST_TX,
};
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 133f53a9c..a339c1e99 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -249,19 +249,23 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf;
remaining_words = t->len / xspi->bytes_per_word;
- reinit_completion(&xspi->done);
if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
+ u32 isr;
use_irq = true;
- xspi->write_fn(XSPI_INTR_TX_EMPTY,
- xspi->regs + XIPIF_V123B_IISR_OFFSET);
- /* Enable the global IPIF interrupt */
- xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
- xspi->regs + XIPIF_V123B_DGIER_OFFSET);
/* Inhibit irq to avoid spurious irqs on tx_empty*/
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
xspi->regs + XSPI_CR_OFFSET);
+ /* ACK old irqs (if any) */
+ isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ if (isr)
+ xspi->write_fn(isr,
+ xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ /* Enable the global IPIF interrupt */
+ xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+ xspi->regs + XIPIF_V123B_DGIER_OFFSET);
+ reinit_completion(&xspi->done);
}
while (remaining_words) {
@@ -302,8 +306,10 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
remaining_words -= n_words;
}
- if (use_irq)
+ if (use_irq) {
xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
+ xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
+ }
return t->len;
}