Merge remote-tracking branches 'spi/topic/altera', 'spi/topic/at79', 'spi/topic/bcm-qspi', 'spi/topic/bcm63xx' and 'spi/topic/bcm63xx-hspi' into spi-next

This commit is contained in:
Mark Brown 2017-09-04 15:51:14 +01:00
6 changed files with 119 additions and 189 deletions

View File

@ -55,7 +55,6 @@ comment "SPI Master Controller Drivers"
config SPI_ALTERA
tristate "Altera SPI Controller"
select SPI_BITBANG
help
This is the driver for the Altera SPI Controller.

View File

@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/io.h>
#include <linux/of.h>
@ -45,10 +44,6 @@
#define ALTERA_SPI_CONTROL_SSO_MSK 0x400
struct altera_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
void __iomem *base;
int irq;
int len;
@ -66,112 +61,42 @@ static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
return spi_master_get_devdata(sdev->master);
}
static void altera_spi_chipsel(struct spi_device *spi, int value)
static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
{
struct altera_spi *hw = altera_spi_to_hw(spi);
if (spi->mode & SPI_CS_HIGH) {
switch (value) {
case BITBANG_CS_INACTIVE:
writel(1 << spi->chip_select,
hw->base + ALTERA_SPI_SLAVE_SEL);
hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
break;
case BITBANG_CS_ACTIVE:
hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
writel(0, hw->base + ALTERA_SPI_SLAVE_SEL);
break;
}
if (is_high) {
hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
writel(0, hw->base + ALTERA_SPI_SLAVE_SEL);
} else {
switch (value) {
case BITBANG_CS_INACTIVE:
hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
break;
case BITBANG_CS_ACTIVE:
writel(1 << spi->chip_select,
hw->base + ALTERA_SPI_SLAVE_SEL);
hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
break;
}
writel(BIT(spi->chip_select), hw->base + ALTERA_SPI_SLAVE_SEL);
hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
}
}
static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
static void altera_spi_tx_word(struct altera_spi *hw)
{
unsigned int txd = 0;
if (hw->tx) {
switch (hw->bytes_per_word) {
case 1:
return hw->tx[count];
txd = hw->tx[hw->count];
break;
case 2:
return (hw->tx[count * 2]
| (hw->tx[count * 2 + 1] << 8));
}
}
return 0;
}
static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct altera_spi *hw = altera_spi_to_hw(spi);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->count = 0;
hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
hw->len = t->len / hw->bytes_per_word;
if (hw->irq >= 0) {
/* enable receive interrupt */
hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
/* send the first byte */
writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA);
wait_for_completion(&hw->done);
/* disable receive interrupt */
hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
} else {
while (hw->count < hw->len) {
unsigned int rxd;
writel(hw_txbyte(hw, hw->count),
hw->base + ALTERA_SPI_TXDATA);
while (!(readl(hw->base + ALTERA_SPI_STATUS) &
ALTERA_SPI_STATUS_RRDY_MSK))
cpu_relax();
rxd = readl(hw->base + ALTERA_SPI_RXDATA);
if (hw->rx) {
switch (hw->bytes_per_word) {
case 1:
hw->rx[hw->count] = rxd;
break;
case 2:
hw->rx[hw->count * 2] = rxd;
hw->rx[hw->count * 2 + 1] = rxd >> 8;
break;
}
}
hw->count++;
txd = (hw->tx[hw->count * 2]
| (hw->tx[hw->count * 2 + 1] << 8));
break;
}
}
return hw->count * hw->bytes_per_word;
writel(txd, hw->base + ALTERA_SPI_TXDATA);
}
static irqreturn_t altera_spi_irq(int irq, void *dev)
static void altera_spi_rx_word(struct altera_spi *hw)
{
struct altera_spi *hw = dev;
unsigned int rxd;
rxd = readl(hw->base + ALTERA_SPI_RXDATA);
@ -188,11 +113,58 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
}
hw->count++;
}
if (hw->count < hw->len)
writel(hw_txbyte(hw, hw->count), hw->base + ALTERA_SPI_TXDATA);
else
complete(&hw->done);
static int altera_spi_txrx(struct spi_master *master,
struct spi_device *spi, struct spi_transfer *t)
{
struct altera_spi *hw = spi_master_get_devdata(master);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->count = 0;
hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8);
hw->len = t->len / hw->bytes_per_word;
if (hw->irq >= 0) {
/* enable receive interrupt */
hw->imr |= ALTERA_SPI_CONTROL_IRRDY_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
/* send the first byte */
altera_spi_tx_word(hw);
} else {
while (hw->count < hw->len) {
altera_spi_tx_word(hw);
while (!(readl(hw->base + ALTERA_SPI_STATUS) &
ALTERA_SPI_STATUS_RRDY_MSK))
cpu_relax();
altera_spi_rx_word(hw);
}
spi_finalize_current_transfer(master);
}
return t->len;
}
static irqreturn_t altera_spi_irq(int irq, void *dev)
{
struct spi_master *master = dev;
struct altera_spi *hw = spi_master_get_devdata(master);
altera_spi_rx_word(hw);
if (hw->count < hw->len) {
altera_spi_tx_word(hw);
} else {
/* disable receive interrupt */
hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
writel(hw->imr, hw->base + ALTERA_SPI_CONTROL);
spi_finalize_current_transfer(master);
}
return IRQ_HANDLED;
}
@ -214,14 +186,10 @@ static int altera_spi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->dev.of_node = pdev->dev.of_node;
master->transfer_one = altera_spi_txrx;
master->set_cs = altera_spi_set_cs;
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
/* setup the state for the bitbang driver */
hw->bitbang.master = master;
hw->bitbang.chipselect = altera_spi_chipsel;
hw->bitbang.txrx_bufs = altera_spi_txrx;
/* find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -239,15 +207,13 @@ static int altera_spi_probe(struct platform_device *pdev)
/* irq is optional */
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq >= 0) {
init_completion(&hw->done);
err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
pdev->name, hw);
pdev->name, master);
if (err)
goto exit;
}
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);
err = devm_spi_register_master(&pdev->dev, master);
if (err)
goto exit;
dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq);
@ -258,16 +224,6 @@ static int altera_spi_probe(struct platform_device *pdev)
return err;
}
static int altera_spi_remove(struct platform_device *dev)
{
struct altera_spi *hw = platform_get_drvdata(dev);
struct spi_master *master = hw->bitbang.master;
spi_bitbang_stop(&hw->bitbang);
spi_master_put(master);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id altera_spi_match[] = {
{ .compatible = "ALTR,spi-1.0", },
@ -279,7 +235,6 @@ MODULE_DEVICE_TABLE(of, altera_spi_match);
static struct platform_driver altera_spi_driver = {
.probe = altera_spi_probe,
.remove = altera_spi_remove,
.driver = {
.name = DRV_NAME,
.pm = NULL,

View File

@ -39,15 +39,15 @@ struct ath79_spi {
u32 reg_ctrl;
void __iomem *base;
struct clk *clk;
unsigned rrw_delay;
unsigned int rrw_delay;
};
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned int reg)
{
return ioread32(sp->base + reg);
}
static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned reg, u32 val)
static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned int reg, u32 val)
{
iowrite32(val, sp->base + reg);
}
@ -57,7 +57,7 @@ static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
return spi_master_get_devdata(spi->master);
}
static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs)
static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned int nsecs)
{
if (nsecs > sp->rrw_delay)
ndelay(nsecs - sp->rrw_delay);
@ -148,9 +148,8 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
static void ath79_spi_cleanup_cs(struct spi_device *spi)
{
if (gpio_is_valid(spi->cs_gpio)) {
if (gpio_is_valid(spi->cs_gpio))
gpio_free(spi->cs_gpio);
}
}
static int ath79_spi_setup(struct spi_device *spi)
@ -176,7 +175,7 @@ static void ath79_spi_cleanup(struct spi_device *spi)
spi_bitbang_cleanup(spi);
}
static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs,
u32 word, u8 bits)
{
struct ath79_spi *sp = ath79_spidev_to_sp(spi);

View File

@ -25,7 +25,6 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/spi-nor.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
@ -349,76 +348,60 @@ static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte,
bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, flex_mode);
}
static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width,
int addrlen, int hp)
static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
struct spi_flash_read_message *msg,
int hp)
{
int bpc = 0, bpp = 0;
u8 command = SPINOR_OP_READ_FAST;
int flex_mode = 1, rv = 0;
bool spans_4byte = false;
u8 command = msg->read_opcode;
int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
int addrlen = msg->addr_width;
int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE;
int flex_mode = 1;
dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
width, addrlen, hp);
if (addrlen == BSPI_ADDRLEN_4BYTES) {
if (addrlen == BSPI_ADDRLEN_4BYTES)
bpp = BSPI_BPP_ADDR_SELECT_MASK;
spans_4byte = true;
}
bpp |= 8;
bpp |= msg->dummy_bytes * (8/addr_nbits);
switch (width) {
case SPI_NBITS_SINGLE:
if (addrlen == BSPI_ADDRLEN_3BYTES)
/* default mode, does not need flex_cmd */
flex_mode = 0;
else
command = SPINOR_OP_READ_FAST_4B;
break;
case SPI_NBITS_DUAL:
bpc = 0x00000001;
if (hp) {
bpc |= 0x00010100; /* address and mode are 2-bit */
bpp = BSPI_BPP_MODE_SELECT_MASK;
command = OPCODE_DIOR;
if (spans_4byte)
command = OPCODE_DIOR_4B;
} else {
command = SPINOR_OP_READ_1_1_2;
if (spans_4byte)
command = SPINOR_OP_READ_1_1_2_4B;
}
break;
case SPI_NBITS_QUAD:
bpc = 0x00000002;
if (hp) {
bpc |= 0x00020200; /* address and mode are 4-bit */
bpp = 4; /* dummy cycles */
bpp |= BSPI_BPP_ADDR_SELECT_MASK;
command = OPCODE_QIOR;
if (spans_4byte)
command = OPCODE_QIOR_4B;
} else {
command = SPINOR_OP_READ_1_1_4;
if (spans_4byte)
command = SPINOR_OP_READ_1_1_4_4B;
bpp |= BSPI_BPP_MODE_SELECT_MASK;
}
break;
default:
rv = -EINVAL;
break;
return -EINVAL;
}
if (rv == 0)
bcm_qspi_bspi_set_xfer_params(qspi, command, bpp, bpc,
flex_mode);
bcm_qspi_bspi_set_xfer_params(qspi, command, bpp, bpc, flex_mode);
return rv;
return 0;
}
static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, int width,
int addrlen, int hp)
static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
struct spi_flash_read_message *msg,
int hp)
{
int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
int addrlen = msg->addr_width;
u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n",
@ -430,7 +413,6 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, int width,
data &= ~(BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD |
BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL);
break;
case SPI_NBITS_QUAD:
/* clear dual mode and set quad mode */
data &= ~BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL;
@ -455,15 +437,17 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi, int width,
/* set the override mode */
data |= BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data);
bcm_qspi_bspi_set_xfer_params(qspi, SPINOR_OP_READ_FAST, 0, 0, 0);
bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0);
return 0;
}
static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
int width, int addrlen, int hp)
struct spi_flash_read_message *msg, int hp)
{
int error = 0;
int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
int addrlen = msg->addr_width;
/* default mode */
qspi->xfer_mode.flex_mode = true;
@ -475,23 +459,13 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
mask = BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
if (val & mask || qspi->s3_strap_override_ctrl & mask) {
qspi->xfer_mode.flex_mode = false;
bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE,
0);
if ((val | qspi->s3_strap_override_ctrl) &
BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL)
width = SPI_NBITS_DUAL;
else if ((val | qspi->s3_strap_override_ctrl) &
BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD)
width = SPI_NBITS_QUAD;
error = bcm_qspi_bspi_set_override(qspi, width, addrlen,
hp);
bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
error = bcm_qspi_bspi_set_override(qspi, msg, hp);
}
}
if (qspi->xfer_mode.flex_mode)
error = bcm_qspi_bspi_set_flex_mode(qspi, width, addrlen, hp);
error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp);
if (error) {
dev_warn(&qspi->pdev->dev,
@ -981,7 +955,7 @@ static int bcm_qspi_flash_read(struct spi_device *spi,
struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
int ret = 0;
bool mspi_read = false;
u32 io_width, addrlen, addr, len;
u32 addr, len;
u_char *buf;
buf = msg->buf;
@ -1010,9 +984,7 @@ static int bcm_qspi_flash_read(struct spi_device *spi,
if (mspi_read)
return bcm_qspi_mspi_flash_read(spi, msg);
io_width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
addrlen = msg->addr_width;
ret = bcm_qspi_bspi_set_mode(qspi, io_width, addrlen, -1);
ret = bcm_qspi_bspi_set_mode(qspi, msg, -1);
if (!ret)
ret = bcm_qspi_bspi_flash_read(spi, msg);
@ -1422,6 +1394,11 @@ static int __maybe_unused bcm_qspi_suspend(struct device *dev)
{
struct bcm_qspi *qspi = dev_get_drvdata(dev);
/* store the override strap value */
if (!bcm_qspi_bspi_ver_three(qspi))
qspi->s3_strap_override_ctrl =
bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
spi_master_suspend(qspi->master);
clk_disable(qspi->clk);
bcm_qspi_hw_uninit(qspi);

View File

@ -108,7 +108,7 @@ struct bcm63xx_hsspi {
u8 cs_polarity;
};
static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned cs,
static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned int cs,
bool active)
{
u32 reg;
@ -127,7 +127,7 @@ static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned cs,
static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
struct spi_device *spi, int hz)
{
unsigned profile = spi->chip_select;
unsigned int profile = spi->chip_select;
u32 reg;
reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
@ -154,7 +154,7 @@ static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
unsigned chip_select = spi->chip_select;
unsigned int chip_select = spi->chip_select;
u16 opcode = 0;
int pending = t->len;
int step_size = HSSPI_BUFFER_LEN;
@ -338,8 +338,8 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "no irq\n");
return -ENXIO;
dev_err(dev, "no irq: %d\n", irq);
return irq;
}
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

View File

@ -530,8 +530,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "no irq\n");
return -ENXIO;
dev_err(dev, "no irq: %d\n", irq);
return irq;
}
clk = devm_clk_get(dev, "spi");