summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-ath79.c13
-rw-r--r--drivers/spi/spi-bcm-qspi.c89
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c10
-rw-r--r--drivers/spi/spi-bcm63xx.c4
-rw-r--r--drivers/spi/spi.c83
5 files changed, 105 insertions, 94 deletions
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index b89cee11f418..0719bd484891 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -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);
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index b19722ba908c..6ef6c44f39f5 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -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);
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index 4da2d4a524ca..cbcba614b253 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -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);
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 84c7356ce5b4..bfe5754768f9 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -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");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 4fcbb0aa71d3..f47d1ccdf292 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -40,9 +40,13 @@
#include <linux/ioport.h>
#include <linux/acpi.h>
#include <linux/highmem.h>
+#include <linux/idr.h>
#define CREATE_TRACE_POINTS
#include <trace/events/spi.h>
+#define SPI_DYN_FIRST_BUS_NUM 0
+
+static DEFINE_IDR(spi_master_idr);
static void spidev_release(struct device *dev)
{
@@ -321,8 +325,7 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
if (rc != -ENODEV)
return rc;
- add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
- return 0;
+ return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
}
struct bus_type spi_bus_type = {
@@ -421,6 +424,7 @@ static LIST_HEAD(spi_controller_list);
/*
* Used to protect add/del opertion for board_info list and
* spi_controller list, and their matching process
+ * also used to protect object of type struct idr
*/
static DEFINE_MUTEX(board_lock);
@@ -1533,15 +1537,15 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
int rc;
/* Mode (clock phase/polarity/etc.) */
- if (of_find_property(nc, "spi-cpha", NULL))
+ if (of_property_read_bool(nc, "spi-cpha"))
spi->mode |= SPI_CPHA;
- if (of_find_property(nc, "spi-cpol", NULL))
+ if (of_property_read_bool(nc, "spi-cpol"))
spi->mode |= SPI_CPOL;
- if (of_find_property(nc, "spi-cs-high", NULL))
+ if (of_property_read_bool(nc, "spi-cs-high"))
spi->mode |= SPI_CS_HIGH;
- if (of_find_property(nc, "spi-3wire", NULL))
+ if (of_property_read_bool(nc, "spi-3wire"))
spi->mode |= SPI_3WIRE;
- if (of_find_property(nc, "spi-lsb-first", NULL))
+ if (of_property_read_bool(nc, "spi-lsb-first"))
spi->mode |= SPI_LSB_FIRST;
/* Device DUAL/QUAD mode */
@@ -2052,11 +2056,10 @@ static int of_spi_register_master(struct spi_controller *ctlr)
*/
int spi_register_controller(struct spi_controller *ctlr)
{
- static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
struct device *dev = ctlr->dev.parent;
struct boardinfo *bi;
int status = -ENODEV;
- int dynamic = 0;
+ int id;
if (!dev)
return -ENODEV;
@@ -2072,19 +2075,28 @@ int spi_register_controller(struct spi_controller *ctlr)
*/
if (ctlr->num_chipselect == 0)
return -EINVAL;
-
- if ((ctlr->bus_num < 0) && ctlr->dev.of_node)
- ctlr->bus_num = of_alias_get_id(ctlr->dev.of_node, "spi");
-
- /* convention: dynamically assigned bus IDs count down from the max */
+ /* allocate dynamic bus number using Linux idr */
+ if ((ctlr->bus_num < 0) && ctlr->dev.of_node) {
+ id = of_alias_get_id(ctlr->dev.of_node, "spi");
+ if (id >= 0) {
+ ctlr->bus_num = id;
+ mutex_lock(&board_lock);
+ id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
+ ctlr->bus_num + 1, GFP_KERNEL);
+ mutex_unlock(&board_lock);
+ if (WARN(id < 0, "couldn't get idr"))
+ return id == -ENOSPC ? -EBUSY : id;
+ }
+ }
if (ctlr->bus_num < 0) {
- /* FIXME switch to an IDR based scheme, something like
- * I2C now uses, so we can't run out of "dynamic" IDs
- */
- ctlr->bus_num = atomic_dec_return(&dyn_bus_id);
- dynamic = 1;
+ mutex_lock(&board_lock);
+ id = idr_alloc(&spi_master_idr, ctlr, SPI_DYN_FIRST_BUS_NUM, 0,
+ GFP_KERNEL);
+ mutex_unlock(&board_lock);
+ if (WARN(id < 0, "couldn't get idr"))
+ return id;
+ ctlr->bus_num = id;
}
-
INIT_LIST_HEAD(&ctlr->queue);
spin_lock_init(&ctlr->queue_lock);
spin_lock_init(&ctlr->bus_lock_spinlock);
@@ -2100,11 +2112,16 @@ int spi_register_controller(struct spi_controller *ctlr)
*/
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
status = device_add(&ctlr->dev);
- if (status < 0)
+ if (status < 0) {
+ /* free bus id */
+ mutex_lock(&board_lock);
+ idr_remove(&spi_master_idr, ctlr->bus_num);
+ mutex_unlock(&board_lock);
goto done;
- dev_dbg(dev, "registered %s %s%s\n",
+ }
+ dev_dbg(dev, "registered %s %s\n",
spi_controller_is_slave(ctlr) ? "slave" : "master",
- dev_name(&ctlr->dev), dynamic ? " (dynamic)" : "");
+ dev_name(&ctlr->dev));
/* If we're using a queued driver, start the queue */
if (ctlr->transfer)
@@ -2113,6 +2130,10 @@ int spi_register_controller(struct spi_controller *ctlr)
status = spi_controller_initialize_queue(ctlr);
if (status) {
device_del(&ctlr->dev);
+ /* free bus id */
+ mutex_lock(&board_lock);
+ idr_remove(&spi_master_idr, ctlr->bus_num);
+ mutex_unlock(&board_lock);
goto done;
}
}
@@ -2191,19 +2212,33 @@ static int __unregister(struct device *dev, void *null)
*/
void spi_unregister_controller(struct spi_controller *ctlr)
{
+ struct spi_controller *found;
int dummy;
+ /* First make sure that this controller was ever added */
+ mutex_lock(&board_lock);
+ found = idr_find(&spi_master_idr, ctlr->bus_num);
+ mutex_unlock(&board_lock);
+ if (found != ctlr) {
+ dev_dbg(&ctlr->dev,
+ "attempting to delete unregistered controller [%s]\n",
+ dev_name(&ctlr->dev));
+ return;
+ }
if (ctlr->queued) {
if (spi_destroy_queue(ctlr))
dev_err(&ctlr->dev, "queue remove failed\n");
}
-
mutex_lock(&board_lock);
list_del(&ctlr->list);
mutex_unlock(&board_lock);
dummy = device_for_each_child(&ctlr->dev, NULL, __unregister);
device_unregister(&ctlr->dev);
+ /* free bus id */
+ mutex_lock(&board_lock);
+ idr_remove(&spi_master_idr, ctlr->bus_num);
+ mutex_unlock(&board_lock);
}
EXPORT_SYMBOL_GPL(spi_unregister_controller);