diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-ath79.c | 13 | ||||
-rw-r--r-- | drivers/spi/spi-bcm-qspi.c | 89 | ||||
-rw-r--r-- | drivers/spi/spi-bcm63xx-hsspi.c | 10 | ||||
-rw-r--r-- | drivers/spi/spi-bcm63xx.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi.c | 83 |
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); |