From 7ed66c6d8841f215c4371b72206fdecfbcd7a396 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 4 Aug 2016 04:30:37 +0000 Subject: [PATCH 01/41] spi: jcore: add J-Core SPI master bindings Signed-off-by: Rich Felker Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/jcore,spi.txt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/jcore,spi.txt diff --git a/Documentation/devicetree/bindings/spi/jcore,spi.txt b/Documentation/devicetree/bindings/spi/jcore,spi.txt new file mode 100644 index 000000000000..93936d16e139 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/jcore,spi.txt @@ -0,0 +1,34 @@ +J-Core SPI master + +Required properties: + +- compatible: Must be "jcore,spi2". + +- reg: Memory region for registers. + +- #address-cells: Must be 1. + +- #size-cells: Must be 0. + +Optional properties: + +- clocks: If a phandle named "ref_clk" is present, SPI clock speed + programming is relative to the frequency of the indicated clock. + Necessary only if the input clock rate is something other than a + fixed 50 MHz. + +- clock-names: Clock names, one for each phandle in clocks. + +See spi-bus.txt for additional properties not specific to this device. + +Example: + +spi@40 { + compatible = "jcore,spi2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40 0x8>; + spi-max-frequency = <25000000>; + clocks = <&bus_clk>; + clock-names = "ref_clk"; +} From 2cb1b3b3ac0ac86b70eb1ecd65585c0d024fe273 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 4 Aug 2016 04:30:37 +0000 Subject: [PATCH 02/41] spi: add driver for J-Core SPI controller The J-Core "spi2" device is a PIO-based SPI master controller. It differs from "bitbang" devices in that that it's clocked in hardware rather than via soft clock modulation over gpio, and performs byte-at-a-time transfers between the cpu and SPI controller. This driver will be extended to support future versions of the J-Core SPI controller with DMA transfers when they become available. Signed-off-by: Rich Felker Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 7 ++ drivers/spi/Makefile | 1 + drivers/spi/spi-jcore.c | 232 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 drivers/spi/spi-jcore.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d6fb8d4b7786..1abb3d767390 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -285,6 +285,13 @@ config SPI_IMX This enables using the Freescale i.MX SPI controllers in master mode. +config SPI_JCORE + tristate "J-Core SPI Master" + depends on OF && (SUPERH || COMPILE_TEST) + help + This enables support for the SPI master controller in the J-Core + synthesizable, open source SoC. + config SPI_LM70_LLP tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" depends on PARPORT diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 185367ef6576..8715fec8cffa 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o obj-$(CONFIG_SPI_IMX) += spi-imx.o +obj-$(CONFIG_SPI_JCORE) += spi-jcore.o obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c new file mode 100644 index 000000000000..7d2044a106a2 --- /dev/null +++ b/drivers/spi/spi-jcore.c @@ -0,0 +1,232 @@ +/* + * J-Core SPI controller driver + * + * Copyright (C) 2012-2016 Smart Energy Instruments, Inc. + * + * Current version by Rich Felker + * Based loosely on initial version by Oleksandr G Zhadan + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "jcore_spi" + +#define CTRL_REG 0x0 +#define DATA_REG 0x4 + +#define JCORE_SPI_CTRL_XMIT 0x02 +#define JCORE_SPI_STAT_BUSY 0x02 +#define JCORE_SPI_CTRL_LOOP 0x08 +#define JCORE_SPI_CTRL_CS_BITS 0x15 + +#define JCORE_SPI_WAIT_RDY_MAX_LOOP 2000000 + +struct jcore_spi { + struct spi_master *master; + void __iomem *base; + unsigned int cs_reg; + unsigned int speed_reg; + unsigned int speed_hz; + unsigned int clock_freq; +}; + +static int jcore_spi_wait(void __iomem *ctrl_reg) +{ + unsigned timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP; + + do { + if (!(readl(ctrl_reg) & JCORE_SPI_STAT_BUSY)) + return 0; + cpu_relax(); + } while (--timeout); + + return -EBUSY; +} + +static void jcore_spi_program(struct jcore_spi *hw) +{ + void __iomem *ctrl_reg = hw->base + CTRL_REG; + + if (jcore_spi_wait(ctrl_reg)) + dev_err(hw->master->dev.parent, + "timeout waiting to program ctrl reg.\n"); + + writel(hw->cs_reg | hw->speed_reg, ctrl_reg); +} + +static void jcore_spi_chipsel(struct spi_device *spi, bool value) +{ + struct jcore_spi *hw = spi_master_get_devdata(spi->master); + u32 csbit = 1U << (2 * spi->chip_select); + + dev_dbg(hw->master->dev.parent, "chipselect %d\n", spi->chip_select); + + if (value) + hw->cs_reg |= csbit; + else + hw->cs_reg &= ~csbit; + + jcore_spi_program(hw); +} + +static void jcore_spi_baudrate(struct jcore_spi *hw, int speed) +{ + if (speed == hw->speed_hz) return; + hw->speed_hz = speed; + if (speed >= hw->clock_freq / 2) + hw->speed_reg = 0; + else + hw->speed_reg = ((hw->clock_freq / 2 / speed) - 1) << 27; + jcore_spi_program(hw); + dev_dbg(hw->master->dev.parent, "speed=%d reg=0x%x\n", + speed, hw->speed_reg); +} + +static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *t) +{ + struct jcore_spi *hw = spi_master_get_devdata(master); + + void __iomem *ctrl_reg = hw->base + CTRL_REG; + void __iomem *data_reg = hw->base + DATA_REG; + u32 xmit; + + /* data buffers */ + const unsigned char *tx; + unsigned char *rx; + unsigned int len; + unsigned int count; + + jcore_spi_baudrate(hw, t->speed_hz); + + xmit = hw->cs_reg | hw->speed_reg | JCORE_SPI_CTRL_XMIT; + tx = t->tx_buf; + rx = t->rx_buf; + len = t->len; + + for (count = 0; count < len; count++) { + if (jcore_spi_wait(ctrl_reg)) + break; + + writel(tx ? *tx++ : 0, data_reg); + writel(xmit, ctrl_reg); + + if (jcore_spi_wait(ctrl_reg)) + break; + + if (rx) + *rx++ = readl(data_reg); + } + + spi_finalize_current_transfer(master); + + if (count < len) + return -EREMOTEIO; + + return 0; +} + +static int jcore_spi_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct jcore_spi *hw; + struct spi_master *master; + struct resource *res; + u32 clock_freq; + struct clk *clk; + int err = -ENODEV; + + master = spi_alloc_master(&pdev->dev, sizeof(struct jcore_spi)); + if (!master) + return err; + + /* Setup the master state. */ + master->num_chipselect = 3; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->transfer_one = jcore_spi_txrx; + master->set_cs = jcore_spi_chipsel; + master->dev.of_node = node; + master->bus_num = pdev->id; + + hw = spi_master_get_devdata(master); + hw->master = master; + platform_set_drvdata(pdev, hw); + + /* Find and map our resources */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + goto exit_busy; + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), pdev->name)) + goto exit_busy; + hw->base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!hw->base) + goto exit_busy; + + /* + * The SPI clock rate controlled via a configurable clock divider + * which is applied to the reference clock. A 50 MHz reference is + * most suitable for obtaining standard SPI clock rates, but some + * designs may have a different reference clock, and the DT must + * make the driver aware so that it can properly program the + * requested rate. If the clock is omitted, 50 MHz is assumed. + */ + clock_freq = 50000000; + clk = devm_clk_get(&pdev->dev, "ref_clk"); + if (!IS_ERR_OR_NULL(clk)) { + if (clk_enable(clk) == 0) + clock_freq = clk_get_rate(clk); + else + dev_warn(&pdev->dev, "could not enable ref_clk\n"); + } + hw->clock_freq = clock_freq; + + /* Initialize all CS bits to high. */ + hw->cs_reg = JCORE_SPI_CTRL_CS_BITS; + jcore_spi_baudrate(hw, 400000); + + /* Register our spi controller */ + err = devm_spi_register_master(&pdev->dev, master); + if (err) + goto exit; + + return 0; + +exit_busy: + err = -EBUSY; +exit: + platform_set_drvdata(pdev, NULL); + spi_master_put(master); + return err; +} + +static const struct of_device_id jcore_spi_of_match[] = { + { .compatible = "jcore,spi2" }, + {}, +}; + +static struct platform_driver jcore_spi_driver = { + .probe = jcore_spi_probe, + .driver = { + .name = DRV_NAME, + .of_match_table = jcore_spi_of_match, + }, +}; + +module_platform_driver(jcore_spi_driver); + +MODULE_DESCRIPTION("J-Core SPI driver"); +MODULE_AUTHOR("Rich Felker "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); From f75529fd712cb147a81925c58cf260346eae5da3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 8 Aug 2016 13:53:23 +0000 Subject: [PATCH 03/41] spi: jcore: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-jcore.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c index 7d2044a106a2..f8117b80fa22 100644 --- a/drivers/spi/spi-jcore.c +++ b/drivers/spi/spi-jcore.c @@ -206,7 +206,6 @@ static int jcore_spi_probe(struct platform_device *pdev) exit_busy: err = -EBUSY; exit: - platform_set_drvdata(pdev, NULL); spi_master_put(master); return err; } From 5090cc6ae2f79ee779e5faf7c8a28edf42b7d738 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 17 Aug 2016 21:08:01 +0200 Subject: [PATCH 04/41] spi: introduce max_message_size hook in spi_master Recently a maximum transfer size was was introduced in struct spi_master. However there are also spi controllers with a maximum message size, e.g. fsl-espi has a max message size of 64KB. Introduce a hook max_message_size to deal with such limitations. Also make sure that spi_max_transfer_size doesn't return greater values than spi_max_message_size, even if hook max_transfer_size is not set. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 072cb2aa2413..f2d3960cc3c3 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -312,6 +312,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @flags: other constraints relevant to this driver * @max_transfer_size: function that returns the max transfer size for * a &spi_device; may be %NULL, so the default %SIZE_MAX will be used. + * @max_message_size: function that returns the max message size for + * a &spi_device; may be %NULL, so the default %SIZE_MAX will be used. * @io_mutex: mutex for physical bus access * @bus_lock_spinlock: spinlock for SPI bus locking * @bus_lock_mutex: mutex for exclusion of multiple callers @@ -442,10 +444,11 @@ struct spi_master { #define SPI_MASTER_MUST_TX BIT(4) /* requires tx */ /* - * on some hardware transfer size may be constrained + * on some hardware transfer / message size may be constrained * the limit may depend on device transfer settings */ size_t (*max_transfer_size)(struct spi_device *spi); + size_t (*max_message_size)(struct spi_device *spi); /* I/O mutex */ struct mutex io_mutex; @@ -904,13 +907,27 @@ extern int spi_async(struct spi_device *spi, struct spi_message *message); extern int spi_async_locked(struct spi_device *spi, struct spi_message *message); +static inline size_t +spi_max_message_size(struct spi_device *spi) +{ + struct spi_master *master = spi->master; + if (!master->max_message_size) + return SIZE_MAX; + return master->max_message_size(spi); +} + static inline size_t spi_max_transfer_size(struct spi_device *spi) { struct spi_master *master = spi->master; - if (!master->max_transfer_size) - return SIZE_MAX; - return master->max_transfer_size(spi); + size_t tr_max = SIZE_MAX; + size_t msg_max = spi_max_message_size(spi); + + if (master->max_transfer_size) + tr_max = master->max_transfer_size(spi); + + /* transfer size limit must not be greater than messsage size limit */ + return min(tr_max, msg_max); } /*---------------------------------------------------------------------------*/ From 02a595d5d6e4ecc0564ec31afb76202035a7591c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 17 Aug 2016 21:11:01 +0200 Subject: [PATCH 05/41] spi: fsl-espi: eliminate spi nor flash read loop The fsl-espi driver contains a read loop that implicitely assumes that the device to read from is a m25p80 SPI NOR flash (bytes 2 - 4 of the first write transfer are interpreted as 3 byte flash address). Now that we have such a read loop in the spi-nor driver and are able to correctly indicate the message size limit of the controller, the read loop can be removed from the fsl-espi driver. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 91 +++++++++----------------------------- 1 file changed, 21 insertions(+), 70 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 8d85a3c343da..96a2442c1623 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -258,23 +258,6 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) return mpc8xxx_spi->count; } -static inline void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd) -{ - if (cmd) { - cmd[1] = (u8)(addr >> 16); - cmd[2] = (u8)(addr >> 8); - cmd[3] = (u8)(addr >> 0); - } -} - -static inline unsigned int fsl_espi_cmd2addr(u8 *cmd) -{ - if (cmd) - return cmd[1] << 16 | cmd[2] << 8 | cmd[3] << 0; - - return 0; -} - static void fsl_espi_do_trans(struct spi_message *m, struct fsl_espi_transfer *tr) { @@ -366,68 +349,36 @@ static void fsl_espi_cmd_trans(struct spi_message *m, static void fsl_espi_rw_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { - struct fsl_espi_transfer *espi_trans = trans; - unsigned int total_len = espi_trans->len; struct spi_transfer *t; u8 *local_buf; - u8 *rx_buf = rx_buff; - unsigned int trans_len; - unsigned int addr; - unsigned int tx_only; - unsigned int rx_pos = 0; - unsigned int pos; - int i, loop; + unsigned int tx_only = 0; + int i = 0; local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); if (!local_buf) { - espi_trans->status = -ENOMEM; + trans->status = -ENOMEM; return; } - for (pos = 0, loop = 0; pos < total_len; pos += trans_len, loop++) { - trans_len = total_len - pos; - - i = 0; - tx_only = 0; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf) { - memcpy(local_buf + i, t->tx_buf, t->len); - i += t->len; - if (!t->rx_buf) - tx_only += t->len; - } + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf) { + memcpy(local_buf + i, t->tx_buf, t->len); + i += t->len; + if (!t->rx_buf) + tx_only += t->len; } + } - /* Add additional TX bytes to compensate SPCOM_TRANLEN_MAX */ - if (loop > 0) - trans_len += tx_only; + trans->tx_buf = local_buf; + trans->rx_buf = local_buf; + fsl_espi_do_trans(m, trans); - if (trans_len > SPCOM_TRANLEN_MAX) - trans_len = SPCOM_TRANLEN_MAX; - - /* Update device offset */ - if (pos > 0) { - addr = fsl_espi_cmd2addr(local_buf); - addr += rx_pos; - fsl_espi_addr2cmd(addr, local_buf); - } - - espi_trans->len = trans_len; - espi_trans->tx_buf = local_buf; - espi_trans->rx_buf = local_buf; - fsl_espi_do_trans(m, espi_trans); - - /* If there is at least one RX byte then copy it to rx_buf */ - if (tx_only < SPCOM_TRANLEN_MAX) - memcpy(rx_buf + rx_pos, espi_trans->rx_buf + tx_only, - trans_len - tx_only); - - rx_pos += trans_len - tx_only; - - if (loop > 0) - espi_trans->actual_length += espi_trans->len - tx_only; - else - espi_trans->actual_length += espi_trans->len; + if (!trans->status) { + /* If there is at least one RX byte then copy it to rx_buff */ + if (trans->len > tx_only) + memcpy(rx_buff, trans->rx_buf + tx_only, + trans->len - tx_only); + trans->actual_length += trans->len; } kfree(local_buf); @@ -663,7 +614,7 @@ static int fsl_espi_runtime_resume(struct device *dev) } #endif -static size_t fsl_espi_max_transfer_size(struct spi_device *spi) +static size_t fsl_espi_max_message_size(struct spi_device *spi) { return SPCOM_TRANLEN_MAX; } @@ -695,7 +646,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev, master->cleanup = fsl_espi_cleanup; master->transfer_one_message = fsl_espi_do_one_msg; master->auto_runtime_pm = true; - master->max_transfer_size = fsl_espi_max_transfer_size; + master->max_message_size = fsl_espi_max_message_size; mpc8xxx_spi = spi_master_get_devdata(master); From dc34b89a8c611946bfa18ddc322d355e97811f01 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Wed, 31 Aug 2016 17:21:47 +0800 Subject: [PATCH 06/41] spi: loopback-test: mark rx_ranges_cmp() static We get 1 warning when building kernel with W=1: drivers/spi/spi-loopback-test.c:408:5: warning: no previous prototype for 'rx_ranges_cmp' [-Wmissing-prototypes] In fact, this function is only used in the file in which it is declared and don't need a declaration, but can be made static. So this patch marks it 'static'. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Signed-off-by: Mark Brown --- drivers/spi/spi-loopback-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index faa1b133b0f1..50e620f4e8fe 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -405,7 +405,7 @@ struct rx_ranges { u8 *end; }; -int rx_ranges_cmp(void *priv, struct list_head *a, struct list_head *b) +static int rx_ranges_cmp(void *priv, struct list_head *a, struct list_head *b) { struct rx_ranges *rx_a = list_entry(a, struct rx_ranges, list); struct rx_ranges *rx_b = list_entry(b, struct rx_ranges, list); From 6bdf03b30ed0ac72d309fe22aed8101f4cc6a2df Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 25 Aug 2016 06:43:17 +0200 Subject: [PATCH 07/41] spi: fsl-espi: dont include irq.h irq.h isn't needed and it even shouldn't be included, see comment at the beginning of this header file. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 96a2442c1623..d95fdd0632e4 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include From ea616ee220e70308cf33fa32496ae9c5ad18e190 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 25 Aug 2016 06:44:42 +0200 Subject: [PATCH 08/41] spi: fsl-espi: change return type of fsl_espi_setup_transfer to void fsl_espi_setup_transfer always returns 0, so change the return type to void. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d95fdd0632e4..02a55f50f03f 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -130,7 +130,7 @@ static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi) return data; } -static int fsl_espi_setup_transfer(struct spi_device *spi, +static void fsl_espi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); @@ -195,7 +195,6 @@ static int fsl_espi_setup_transfer(struct spi_device *spi, cs->hw_mode |= CSMODE_PM(pm); fsl_espi_change_mode(spi); - return 0; } static int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, @@ -292,13 +291,8 @@ static void fsl_espi_do_trans(struct spi_message *m, spi_message_add_tail(&trans, &message); list_for_each_entry(t, &message.transfers, transfer_list) { - if (t->bits_per_word || t->speed_hz) { - status = -EINVAL; - - status = fsl_espi_setup_transfer(spi, t); - if (status < 0) - break; - } + if (t->bits_per_word || t->speed_hz) + fsl_espi_setup_transfer(spi, t); if (t->len) status = fsl_espi_bufs(spi, t); @@ -425,7 +419,6 @@ static int fsl_espi_setup(struct spi_device *spi) { struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_espi_reg *reg_base; - int retval; u32 hw_mode; u32 loop_mode; struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); @@ -466,15 +459,11 @@ static int fsl_espi_setup(struct spi_device *spi) loop_mode |= SPMODE_LOOP; mpc8xxx_spi_write_reg(®_base->mode, loop_mode); - retval = fsl_espi_setup_transfer(spi, NULL); + fsl_espi_setup_transfer(spi, NULL); pm_runtime_mark_last_busy(mpc8xxx_spi->dev); pm_runtime_put_autosuspend(mpc8xxx_spi->dev); - if (retval < 0) { - cs->hw_mode = hw_mode; /* Restore settings */ - return retval; - } return 0; } From bbb55f6d6276b39a96b7bcd79f1159a1365bb318 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 25 Aug 2016 06:44:58 +0200 Subject: [PATCH 09/41] spi: fsl-espi: change return type of fsl_espi_cpu_bufs to void fsl_espi_cpu_bufs always returns 0, so change the return type to void. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 02a55f50f03f..2c4714abdde7 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -197,7 +197,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, fsl_espi_change_mode(spi); } -static int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, +static void fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, unsigned int len) { u32 word; @@ -211,8 +211,6 @@ static int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, /* transmit word */ word = mspi->get_tx(mspi); mpc8xxx_spi_write_reg(®_base->transmit, word); - - return 0; } static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) @@ -239,9 +237,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) mpc8xxx_spi_write_reg(®_base->command, (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1))); - ret = fsl_espi_cpu_bufs(mpc8xxx_spi, t, len); - if (ret) - return ret; + fsl_espi_cpu_bufs(mpc8xxx_spi, t, len); /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ); From 10ed1e6d320ca01deef3bc36df91e04ecd69a60e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 25 Aug 2016 06:45:16 +0200 Subject: [PATCH 10/41] spi: fsl-espi: add missing static declaration to fsl_espi_cpu_irq Add missing static declaration to fsl_espi_cpu_irq. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 2c4714abdde7..029017818685 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -471,7 +471,7 @@ static void fsl_espi_cleanup(struct spi_device *spi) spi_set_ctldata(spi, NULL); } -void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) +static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) { struct fsl_espi_reg *reg_base = mspi->reg_base; From dbd4fefb5b7cba19e3f89c097d93ad02049e38e3 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 25 Aug 2016 06:45:55 +0200 Subject: [PATCH 11/41] spi: fsl-espi: remove unneeded variable in fsl_espi_do_trans Creating a message, adding one transfer, and then iterating over all transfers in the message doesn't make sense. We can simply use the original transfer directly. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 029017818685..f9ef50444447 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -258,11 +258,9 @@ static void fsl_espi_do_trans(struct spi_message *m, struct spi_device *spi = m->spi; struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct fsl_espi_transfer *espi_trans = tr; - struct spi_message message; struct spi_transfer *t, *first, trans; int status = 0; - spi_message_init(&message); memset(&trans, 0, sizeof(trans)); first = list_first_entry(&m->transfers, struct spi_transfer, @@ -284,23 +282,18 @@ static void fsl_espi_do_trans(struct spi_message *m, trans.len = espi_trans->len; trans.tx_buf = espi_trans->tx_buf; trans.rx_buf = espi_trans->rx_buf; - spi_message_add_tail(&trans, &message); - list_for_each_entry(t, &message.transfers, transfer_list) { - if (t->bits_per_word || t->speed_hz) - fsl_espi_setup_transfer(spi, t); + if (trans.bits_per_word || trans.speed_hz) + fsl_espi_setup_transfer(spi, &trans); - if (t->len) - status = fsl_espi_bufs(spi, t); + if (trans.len) + status = fsl_espi_bufs(spi, &trans); - if (status) { - status = -EMSGSIZE; - break; - } + if (status) + status = -EMSGSIZE; - if (t->delay_usecs) - udelay(t->delay_usecs); - } + if (trans.delay_usecs) + udelay(trans.delay_usecs); espi_trans->status = status; fsl_espi_setup_transfer(spi, NULL); From daae020ce9fe4324322c6ed18a840234a05d76b3 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 4 Sep 2016 09:53:01 +0200 Subject: [PATCH 12/41] spi: fsl-espi: remove unused elements n_rx and n_tx in struct fsl_espi_transfer Both elements are not used, so remove them. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index f9ef50444447..a9004fe5a5ed 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -41,8 +41,6 @@ struct fsl_espi_transfer { const void *tx_buf; void *rx_buf; unsigned len; - unsigned n_tx; - unsigned n_rx; unsigned actual_length; int status; }; @@ -371,24 +369,16 @@ static int fsl_espi_do_one_msg(struct spi_master *master, { struct spi_transfer *t; u8 *rx_buf = NULL; - unsigned int n_tx = 0; - unsigned int n_rx = 0; unsigned int xfer_len = 0; struct fsl_espi_transfer espi_trans; list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf) - n_tx += t->len; - if (t->rx_buf) { - n_rx += t->len; + if (t->rx_buf) rx_buf = t->rx_buf; - } if ((t->tx_buf) || (t->rx_buf)) xfer_len += t->len; } - espi_trans.n_tx = n_tx; - espi_trans.n_rx = n_rx; espi_trans.len = xfer_len; espi_trans.actual_length = 0; espi_trans.status = 0; From a755af52f8ef278985d1475070c0647f2e6e47a7 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 4 Sep 2016 09:56:57 +0200 Subject: [PATCH 13/41] spi: fsl-espi: simplify fsl_espi_setup_transfer Simplify fsl_espi_setup_transfer a little. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index a9004fe5a5ed..b00313bed7e9 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -166,12 +166,10 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_tx = cs->get_tx; - bits_per_word = bits_per_word - 1; - /* mask out bits we are going to set */ cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF)); - cs->hw_mode |= CSMODE_LEN(bits_per_word); + cs->hw_mode |= CSMODE_LEN(bits_per_word - 1); if ((mpc8xxx_spi->spibrg / hz) > 64) { cs->hw_mode |= CSMODE_DIV16; From 71581a1507e642bbc6f698a3f43355552ee8056f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 4 Sep 2016 09:57:18 +0200 Subject: [PATCH 14/41] spi: fsl-espi: remove unneeded check in fsl_espi_do_trans SPI core takes care that both values are always populated. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index b00313bed7e9..16fff7237ab2 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -279,8 +279,7 @@ static void fsl_espi_do_trans(struct spi_message *m, trans.tx_buf = espi_trans->tx_buf; trans.rx_buf = espi_trans->rx_buf; - if (trans.bits_per_word || trans.speed_hz) - fsl_espi_setup_transfer(spi, &trans); + fsl_espi_setup_transfer(spi, &trans); if (trans.len) status = fsl_espi_bufs(spi, &trans); From 1423877b73ed5f4982eaba8bed359605b9918a2b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:50:22 +0200 Subject: [PATCH 15/41] spi: fsl-espi: pre-allocate message buffer Currently the driver allocates a 64kb buffer for each single message. On systems with little and fragmented memory this can result in memory allocation errors. Solve this by pre-allocating a buffer. This patch was developed in OpenWRT long ago, however it never made it upstream. I slightly modified the original patch to re-initialize the buffer at the beginning of each transfer. Signed-off-by: Gabor Juhos Signed-off-by: Felix Fietkau Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 41 +++++++++++++++++--------------------- drivers/spi/spi-fsl-lib.h | 1 + 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 16fff7237ab2..81d7416668b8 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -297,57 +297,44 @@ static void fsl_espi_do_trans(struct spi_message *m, static void fsl_espi_cmd_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { + struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); struct spi_transfer *t; - u8 *local_buf; int i = 0; struct fsl_espi_transfer *espi_trans = trans; - local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); - if (!local_buf) { - espi_trans->status = -ENOMEM; - return; - } - list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf) { - memcpy(local_buf + i, t->tx_buf, t->len); + memcpy(mspi->local_buf + i, t->tx_buf, t->len); i += t->len; } } - espi_trans->tx_buf = local_buf; - espi_trans->rx_buf = local_buf; + espi_trans->tx_buf = mspi->local_buf; + espi_trans->rx_buf = mspi->local_buf; fsl_espi_do_trans(m, espi_trans); espi_trans->actual_length = espi_trans->len; - kfree(local_buf); } static void fsl_espi_rw_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { + struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); struct spi_transfer *t; - u8 *local_buf; unsigned int tx_only = 0; int i = 0; - local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL); - if (!local_buf) { - trans->status = -ENOMEM; - return; - } - list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf) { - memcpy(local_buf + i, t->tx_buf, t->len); + memcpy(mspi->local_buf + i, t->tx_buf, t->len); i += t->len; if (!t->rx_buf) tx_only += t->len; } } - trans->tx_buf = local_buf; - trans->rx_buf = local_buf; + trans->tx_buf = mspi->local_buf; + trans->rx_buf = mspi->local_buf; fsl_espi_do_trans(m, trans); if (!trans->status) { @@ -357,18 +344,19 @@ static void fsl_espi_rw_trans(struct spi_message *m, trans->len - tx_only); trans->actual_length += trans->len; } - - kfree(local_buf); } static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { + struct mpc8xxx_spi *mspi = spi_master_get_devdata(master); struct spi_transfer *t; u8 *rx_buf = NULL; unsigned int xfer_len = 0; struct fsl_espi_transfer espi_trans; + memset(mspi->local_buf, 0, SPCOM_TRANLEN_MAX); + list_for_each_entry(t, &m->transfers, transfer_list) { if (t->rx_buf) rx_buf = t->rx_buf; @@ -614,6 +602,13 @@ static struct spi_master * fsl_espi_probe(struct device *dev, mpc8xxx_spi = spi_master_get_devdata(master); + mpc8xxx_spi->local_buf = + devm_kmalloc(dev, SPCOM_TRANLEN_MAX, GFP_KERNEL); + if (!mpc8xxx_spi->local_buf) { + ret = -ENOMEM; + goto err_probe; + } + mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); if (IS_ERR(mpc8xxx_spi->reg_base)) { ret = PTR_ERR(mpc8xxx_spi->reg_base); diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index 84f5dcb7a897..065b9db212cf 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -30,6 +30,7 @@ struct mpc8xxx_spi { void *rx; #if IS_ENABLED(CONFIG_SPI_FSL_ESPI) int len; + u8 *local_buf; #endif int subblock; From 7c159aa8c103b02a8434ae18b22048952c796e6f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:50:53 +0200 Subject: [PATCH 16/41] spi: fsl-espi: factor out filling the local buffer Better structure the code by factoring out filling the local buffer. In addition don't initialize the complete local buffer at the beginning of fsl_espi_do_one_msg. Instead move initialization of those parts of the local buffer to be used for transfers w/o tx_buf to fsl_espi_copy_to_buf. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 46 ++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 81d7416668b8..8e6ef9b153d7 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -85,6 +85,27 @@ struct fsl_espi_transfer { #define AUTOSUSPEND_TIMEOUT 2000 +static unsigned int fsl_espi_copy_to_buf(struct spi_message *m, + struct mpc8xxx_spi *mspi) +{ + unsigned int tx_only = 0; + struct spi_transfer *t; + u8 *buf = mspi->local_buf; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf) { + memcpy(buf, t->tx_buf, t->len); + if (!t->rx_buf) + tx_only += t->len; + } else { + memset(buf, 0, t->len); + } + buf += t->len; + } + + return tx_only; +} + static void fsl_espi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); @@ -298,16 +319,9 @@ static void fsl_espi_cmd_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - struct spi_transfer *t; - int i = 0; struct fsl_espi_transfer *espi_trans = trans; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf) { - memcpy(mspi->local_buf + i, t->tx_buf, t->len); - i += t->len; - } - } + fsl_espi_copy_to_buf(m, mspi); espi_trans->tx_buf = mspi->local_buf; espi_trans->rx_buf = mspi->local_buf; @@ -320,18 +334,9 @@ static void fsl_espi_rw_trans(struct spi_message *m, struct fsl_espi_transfer *trans, u8 *rx_buff) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - struct spi_transfer *t; - unsigned int tx_only = 0; - int i = 0; + unsigned int tx_only; - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf) { - memcpy(mspi->local_buf + i, t->tx_buf, t->len); - i += t->len; - if (!t->rx_buf) - tx_only += t->len; - } - } + tx_only = fsl_espi_copy_to_buf(m, mspi); trans->tx_buf = mspi->local_buf; trans->rx_buf = mspi->local_buf; @@ -349,14 +354,11 @@ static void fsl_espi_rw_trans(struct spi_message *m, static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { - struct mpc8xxx_spi *mspi = spi_master_get_devdata(master); struct spi_transfer *t; u8 *rx_buf = NULL; unsigned int xfer_len = 0; struct fsl_espi_transfer espi_trans; - memset(mspi->local_buf, 0, SPCOM_TRANLEN_MAX); - list_for_each_entry(t, &m->transfers, transfer_list) { if (t->rx_buf) rx_buf = t->rx_buf; From e33a3ade909194ec2ca633a53b428d4dac853f8a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:51:10 +0200 Subject: [PATCH 17/41] spi: fsl-espi: remove element status from struct fsl_espi_transfer Use the return values of the functions in the call chain to transport status information instead of using an element in struct fsl_espi_transfer for this. This is more in line with the general approach how to handle status information and is one step further to eventually get rid of struct fsl_espi_transfer completely. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 47 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 8e6ef9b153d7..5f01b6595442 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -42,7 +42,6 @@ struct fsl_espi_transfer { void *rx_buf; unsigned len; unsigned actual_length; - int status; }; /* eSPI Controller mode register definitions */ @@ -269,14 +268,14 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) return mpc8xxx_spi->count; } -static void fsl_espi_do_trans(struct spi_message *m, - struct fsl_espi_transfer *tr) +static int fsl_espi_do_trans(struct spi_message *m, + struct fsl_espi_transfer *tr) { struct spi_device *spi = m->spi; struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct fsl_espi_transfer *espi_trans = tr; struct spi_transfer *t, *first, trans; - int status = 0; + int ret = 0; memset(&trans, 0, sizeof(trans)); @@ -285,10 +284,9 @@ static void fsl_espi_do_trans(struct spi_message *m, list_for_each_entry(t, &m->transfers, transfer_list) { if ((first->bits_per_word != t->bits_per_word) || (first->speed_hz != t->speed_hz)) { - espi_trans->status = -EINVAL; dev_err(mspi->dev, "bits_per_word/speed_hz should be same for the same SPI transfer\n"); - return; + return -EINVAL; } trans.speed_hz = t->speed_hz; @@ -303,52 +301,59 @@ static void fsl_espi_do_trans(struct spi_message *m, fsl_espi_setup_transfer(spi, &trans); if (trans.len) - status = fsl_espi_bufs(spi, &trans); + ret = fsl_espi_bufs(spi, &trans); - if (status) - status = -EMSGSIZE; + if (ret) + ret = -EMSGSIZE; if (trans.delay_usecs) udelay(trans.delay_usecs); - espi_trans->status = status; fsl_espi_setup_transfer(spi, NULL); + + return ret; } -static void fsl_espi_cmd_trans(struct spi_message *m, - struct fsl_espi_transfer *trans, u8 *rx_buff) +static int fsl_espi_cmd_trans(struct spi_message *m, + struct fsl_espi_transfer *trans, u8 *rx_buff) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); struct fsl_espi_transfer *espi_trans = trans; + int ret; fsl_espi_copy_to_buf(m, mspi); espi_trans->tx_buf = mspi->local_buf; espi_trans->rx_buf = mspi->local_buf; - fsl_espi_do_trans(m, espi_trans); + ret = fsl_espi_do_trans(m, espi_trans); espi_trans->actual_length = espi_trans->len; + + return ret; } -static void fsl_espi_rw_trans(struct spi_message *m, - struct fsl_espi_transfer *trans, u8 *rx_buff) +static int fsl_espi_rw_trans(struct spi_message *m, + struct fsl_espi_transfer *trans, u8 *rx_buff) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); unsigned int tx_only; + int ret; tx_only = fsl_espi_copy_to_buf(m, mspi); trans->tx_buf = mspi->local_buf; trans->rx_buf = mspi->local_buf; - fsl_espi_do_trans(m, trans); + ret = fsl_espi_do_trans(m, trans); - if (!trans->status) { + if (!ret) { /* If there is at least one RX byte then copy it to rx_buff */ if (trans->len > tx_only) memcpy(rx_buff, trans->rx_buf + tx_only, trans->len - tx_only); trans->actual_length += trans->len; } + + return ret; } static int fsl_espi_do_one_msg(struct spi_master *master, @@ -358,6 +363,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, u8 *rx_buf = NULL; unsigned int xfer_len = 0; struct fsl_espi_transfer espi_trans; + int ret; list_for_each_entry(t, &m->transfers, transfer_list) { if (t->rx_buf) @@ -368,15 +374,14 @@ static int fsl_espi_do_one_msg(struct spi_master *master, espi_trans.len = xfer_len; espi_trans.actual_length = 0; - espi_trans.status = 0; if (!rx_buf) - fsl_espi_cmd_trans(m, &espi_trans, NULL); + ret = fsl_espi_cmd_trans(m, &espi_trans, NULL); else - fsl_espi_rw_trans(m, &espi_trans, rx_buf); + ret = fsl_espi_rw_trans(m, &espi_trans, rx_buf); m->actual_length = espi_trans.actual_length; - m->status = espi_trans.status; + m->status = ret; spi_finalize_current_message(master); return 0; } From 0319d4991ea6e7594f32843e1b47868737056799 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:51:29 +0200 Subject: [PATCH 18/41] spi: fsl-espi: fix status handling in fsl_espi_do_one_msg If an error occurred during message handling return this error instead of always returning 0 and align the code with the generic implementation in spi_transfer_one_message. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 5f01b6595442..6b60f7b29869 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -381,9 +381,12 @@ static int fsl_espi_do_one_msg(struct spi_master *master, ret = fsl_espi_rw_trans(m, &espi_trans, rx_buf); m->actual_length = espi_trans.actual_length; - m->status = ret; + if (m->status == -EINPROGRESS) + m->status = ret; + spi_finalize_current_message(master); - return 0; + + return ret; } static int fsl_espi_setup(struct spi_device *spi) From 5cd7b8be6b7b4c4fb9e2bfbfba596d27357cc359 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:51:48 +0200 Subject: [PATCH 19/41] spi: fsl-espi: remove element actual_length from struct fsl_espi_trans If an error occurs during processing the message, then we don't have to populate the actual_length element of struct message. So we can get rid of element actual_length in struct fsl_espi_transfer. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 6b60f7b29869..726d5fdca3b6 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -41,7 +41,6 @@ struct fsl_espi_transfer { const void *tx_buf; void *rx_buf; unsigned len; - unsigned actual_length; }; /* eSPI Controller mode register definitions */ @@ -327,8 +326,6 @@ static int fsl_espi_cmd_trans(struct spi_message *m, espi_trans->rx_buf = mspi->local_buf; ret = fsl_espi_do_trans(m, espi_trans); - espi_trans->actual_length = espi_trans->len; - return ret; } @@ -350,7 +347,6 @@ static int fsl_espi_rw_trans(struct spi_message *m, if (trans->len > tx_only) memcpy(rx_buff, trans->rx_buf + tx_only, trans->len - tx_only); - trans->actual_length += trans->len; } return ret; @@ -373,14 +369,14 @@ static int fsl_espi_do_one_msg(struct spi_master *master, } espi_trans.len = xfer_len; - espi_trans.actual_length = 0; if (!rx_buf) ret = fsl_espi_cmd_trans(m, &espi_trans, NULL); else ret = fsl_espi_rw_trans(m, &espi_trans, rx_buf); - m->actual_length = espi_trans.actual_length; + m->actual_length = ret ? 0 : espi_trans.len; + if (m->status == -EINPROGRESS) m->status = ret; From faceef390702bad8bdf9c93554a3364253d9d943 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:52:06 +0200 Subject: [PATCH 20/41] spi: fsl-espi: eliminate struct fsl_espi_transfer The remaining elements of struct fsl_espi_transfer are part of struct spi_transfer anyway. So we can get rid of struct fsl_espi_transfer and use a struct spi_transfer only. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 56 ++++++++++++++------------------------ 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 726d5fdca3b6..8554f18e4cf6 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -37,12 +37,6 @@ struct fsl_espi_reg { __be32 csmode[4]; /* 0x020 - 0x02c eSPI cs mode register */ }; -struct fsl_espi_transfer { - const void *tx_buf; - void *rx_buf; - unsigned len; -}; - /* eSPI Controller mode register definitions */ #define SPMODE_ENABLE (1 << 31) #define SPMODE_LOOP (1 << 30) @@ -267,17 +261,13 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) return mpc8xxx_spi->count; } -static int fsl_espi_do_trans(struct spi_message *m, - struct fsl_espi_transfer *tr) +static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) { struct spi_device *spi = m->spi; struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); - struct fsl_espi_transfer *espi_trans = tr; - struct spi_transfer *t, *first, trans; + struct spi_transfer *t, *first; int ret = 0; - memset(&trans, 0, sizeof(trans)); - first = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); list_for_each_entry(t, &m->transfers, transfer_list) { @@ -288,25 +278,21 @@ static int fsl_espi_do_trans(struct spi_message *m, return -EINVAL; } - trans.speed_hz = t->speed_hz; - trans.bits_per_word = t->bits_per_word; - trans.delay_usecs = max(first->delay_usecs, t->delay_usecs); + trans->speed_hz = t->speed_hz; + trans->bits_per_word = t->bits_per_word; + trans->delay_usecs = max(first->delay_usecs, t->delay_usecs); } - trans.len = espi_trans->len; - trans.tx_buf = espi_trans->tx_buf; - trans.rx_buf = espi_trans->rx_buf; + fsl_espi_setup_transfer(spi, trans); - fsl_espi_setup_transfer(spi, &trans); - - if (trans.len) - ret = fsl_espi_bufs(spi, &trans); + if (trans->len) + ret = fsl_espi_bufs(spi, trans); if (ret) ret = -EMSGSIZE; - if (trans.delay_usecs) - udelay(trans.delay_usecs); + if (trans->delay_usecs) + udelay(trans->delay_usecs); fsl_espi_setup_transfer(spi, NULL); @@ -314,23 +300,22 @@ static int fsl_espi_do_trans(struct spi_message *m, } static int fsl_espi_cmd_trans(struct spi_message *m, - struct fsl_espi_transfer *trans, u8 *rx_buff) + struct spi_transfer *trans, u8 *rx_buff) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - struct fsl_espi_transfer *espi_trans = trans; int ret; fsl_espi_copy_to_buf(m, mspi); - espi_trans->tx_buf = mspi->local_buf; - espi_trans->rx_buf = mspi->local_buf; - ret = fsl_espi_do_trans(m, espi_trans); + trans->tx_buf = mspi->local_buf; + trans->rx_buf = mspi->local_buf; + ret = fsl_espi_do_trans(m, trans); return ret; } static int fsl_espi_rw_trans(struct spi_message *m, - struct fsl_espi_transfer *trans, u8 *rx_buff) + struct spi_transfer *trans, u8 *rx_buff) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); unsigned int tx_only; @@ -355,10 +340,9 @@ static int fsl_espi_rw_trans(struct spi_message *m, static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { - struct spi_transfer *t; u8 *rx_buf = NULL; unsigned int xfer_len = 0; - struct fsl_espi_transfer espi_trans; + struct spi_transfer *t, trans = {}; int ret; list_for_each_entry(t, &m->transfers, transfer_list) { @@ -368,14 +352,14 @@ static int fsl_espi_do_one_msg(struct spi_master *master, xfer_len += t->len; } - espi_trans.len = xfer_len; + trans.len = xfer_len; if (!rx_buf) - ret = fsl_espi_cmd_trans(m, &espi_trans, NULL); + ret = fsl_espi_cmd_trans(m, &trans, NULL); else - ret = fsl_espi_rw_trans(m, &espi_trans, rx_buf); + ret = fsl_espi_rw_trans(m, &trans, rx_buf); - m->actual_length = ret ? 0 : espi_trans.len; + m->actual_length = ret ? 0 : trans.len; if (m->status == -EINPROGRESS) m->status = ret; From 809b1e017bbdaf40d35619e41c1dbc542a5449d2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:52:25 +0200 Subject: [PATCH 21/41] spi: fsl-espi: merge fsl_espi_cmd_trans and fsl_espi_rw_trans fsl_espi_cmd_trans and fsl_espi_rw_trans share most of the code so we can merge them. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 8554f18e4cf6..f8a6dd13ee02 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -299,23 +299,8 @@ static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) return ret; } -static int fsl_espi_cmd_trans(struct spi_message *m, - struct spi_transfer *trans, u8 *rx_buff) -{ - struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - int ret; - - fsl_espi_copy_to_buf(m, mspi); - - trans->tx_buf = mspi->local_buf; - trans->rx_buf = mspi->local_buf; - ret = fsl_espi_do_trans(m, trans); - - return ret; -} - -static int fsl_espi_rw_trans(struct spi_message *m, - struct spi_transfer *trans, u8 *rx_buff) +static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans, + u8 *rx_buff) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); unsigned int tx_only; @@ -327,12 +312,9 @@ static int fsl_espi_rw_trans(struct spi_message *m, trans->rx_buf = mspi->local_buf; ret = fsl_espi_do_trans(m, trans); - if (!ret) { - /* If there is at least one RX byte then copy it to rx_buff */ - if (trans->len > tx_only) - memcpy(rx_buff, trans->rx_buf + tx_only, - trans->len - tx_only); - } + /* If there is at least one RX byte then copy it to rx_buff */ + if (!ret && rx_buff && trans->len > tx_only) + memcpy(rx_buff, trans->rx_buf + tx_only, trans->len - tx_only); return ret; } @@ -354,10 +336,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, trans.len = xfer_len; - if (!rx_buf) - ret = fsl_espi_cmd_trans(m, &trans, NULL); - else - ret = fsl_espi_rw_trans(m, &trans, rx_buf); + ret = fsl_espi_trans(m, &trans, rx_buf); m->actual_length = ret ? 0 : trans.len; From 84ccfc371f4a8d1ff86efd7ca7914e33b90325c2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:52:43 +0200 Subject: [PATCH 22/41] spi: fsl-espi: improve return value handling in fsl_espi_bufs Return a proper status code from fsl_espi_bufs instead of returning the number of remaining words and let the caller evaluate it. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index f8a6dd13ee02..8d6a570ac704 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -258,7 +258,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) /* disable rx ints */ mpc8xxx_spi_write_reg(®_base->mask, 0); - return mpc8xxx_spi->count; + return mpc8xxx_spi->count > 0 ? -EMSGSIZE : 0; } static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) @@ -288,9 +288,6 @@ static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) if (trans->len) ret = fsl_espi_bufs(spi, trans); - if (ret) - ret = -EMSGSIZE; - if (trans->delay_usecs) udelay(trans->delay_usecs); From 5bcc6a2f061266060e0b144302e83e614f683cd7 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:53:01 +0200 Subject: [PATCH 23/41] spi: fsl-espi: merge fsl_espi_bufs and fsl_espi_cpu_bufs fsl_espi_bufs and fsl_espi_cpu_bufs are very small that we can merge them. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 8d6a570ac704..190ca5ccf834 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -206,31 +206,15 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, fsl_espi_change_mode(spi); } -static void fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t, - unsigned int len) -{ - u32 word; - struct fsl_espi_reg *reg_base = mspi->reg_base; - - mspi->count = len; - - /* enable rx ints */ - mpc8xxx_spi_write_reg(®_base->mask, SPIM_NE); - - /* transmit word */ - word = mspi->get_tx(mspi); - mpc8xxx_spi_write_reg(®_base->transmit, word); -} - static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; - unsigned int len = t->len; + u32 word; int ret; mpc8xxx_spi->len = t->len; - len = roundup(len, 4) / 4; + mpc8xxx_spi->count = roundup(t->len, 4) / 4; mpc8xxx_spi->tx = t->tx_buf; mpc8xxx_spi->rx = t->rx_buf; @@ -246,7 +230,12 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) mpc8xxx_spi_write_reg(®_base->command, (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1))); - fsl_espi_cpu_bufs(mpc8xxx_spi, t, len); + /* enable rx ints */ + mpc8xxx_spi_write_reg(®_base->mask, SPIM_NE); + + /* transmit word */ + word = mpc8xxx_spi->get_tx(mpc8xxx_spi); + mpc8xxx_spi_write_reg(®_base->transmit, word); /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ); From d3152cf1c8cf3f75d8eb82ae399ea4b35a0df8d4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:53:38 +0200 Subject: [PATCH 24/41] spi: fsl-espi: factor out initial message checking Checking the message is currently done at diffrent places in the driver. Factor it out to fsl_espi_check_message. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 43 +++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 190ca5ccf834..2bfaff64beb8 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -98,6 +98,30 @@ static unsigned int fsl_espi_copy_to_buf(struct spi_message *m, return tx_only; } +static int fsl_espi_check_message(struct spi_message *m) +{ + struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); + struct spi_transfer *t, *first; + + if (m->frame_length > SPCOM_TRANLEN_MAX) { + dev_err(mspi->dev, "message too long, size is %u bytes\n", + m->frame_length); + return -EMSGSIZE; + } + + first = list_first_entry(&m->transfers, struct spi_transfer, + transfer_list); + list_for_each_entry(t, &m->transfers, transfer_list) { + if (first->bits_per_word != t->bits_per_word || + first->speed_hz != t->speed_hz) { + dev_err(mspi->dev, "bits_per_word/speed_hz should be the same for all transfers\n"); + return -EINVAL; + } + } + + return 0; +} + static void fsl_espi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); @@ -222,11 +246,6 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) reinit_completion(&mpc8xxx_spi->done); /* Set SPCOM[CS] and SPCOM[TRANLEN] field */ - if (t->len > SPCOM_TRANLEN_MAX) { - dev_err(mpc8xxx_spi->dev, "Transaction length (%d)" - " beyond the SPCOM[TRANLEN] field\n", t->len); - return -EINVAL; - } mpc8xxx_spi_write_reg(®_base->command, (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1))); @@ -253,20 +272,12 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) { struct spi_device *spi = m->spi; - struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct spi_transfer *t, *first; int ret = 0; first = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); list_for_each_entry(t, &m->transfers, transfer_list) { - if ((first->bits_per_word != t->bits_per_word) || - (first->speed_hz != t->speed_hz)) { - dev_err(mspi->dev, - "bits_per_word/speed_hz should be same for the same SPI transfer\n"); - return -EINVAL; - } - trans->speed_hz = t->speed_hz; trans->bits_per_word = t->bits_per_word; trans->delay_usecs = max(first->delay_usecs, t->delay_usecs); @@ -313,6 +324,10 @@ static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_transfer *t, trans = {}; int ret; + ret = fsl_espi_check_message(m); + if (ret) + goto out; + list_for_each_entry(t, &m->transfers, transfer_list) { if (t->rx_buf) rx_buf = t->rx_buf; @@ -325,7 +340,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, ret = fsl_espi_trans(m, &trans, rx_buf); m->actual_length = ret ? 0 : trans.len; - +out: if (m->status == -EINPROGRESS) m->status = ret; From 96361fafbbfc8a07b4c7ec09d96d742ef68bfbad Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:54:00 +0200 Subject: [PATCH 25/41] spi: fsl-espi: centralize populating struct spi_transfer Better structure the code by population all elements of struct spi_transfer in one place. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 2bfaff64beb8..7fc9a2c66396 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -272,17 +272,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) { struct spi_device *spi = m->spi; - struct spi_transfer *t, *first; int ret = 0; - first = list_first_entry(&m->transfers, struct spi_transfer, - transfer_list); - list_for_each_entry(t, &m->transfers, transfer_list) { - trans->speed_hz = t->speed_hz; - trans->bits_per_word = t->bits_per_word; - trans->delay_usecs = max(first->delay_usecs, t->delay_usecs); - } - fsl_espi_setup_transfer(spi, trans); if (trans->len) @@ -305,8 +296,6 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans, tx_only = fsl_espi_copy_to_buf(m, mspi); - trans->tx_buf = mspi->local_buf; - trans->rx_buf = mspi->local_buf; ret = fsl_espi_do_trans(m, trans); /* If there is at least one RX byte then copy it to rx_buff */ @@ -319,8 +308,9 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans, static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { + struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); u8 *rx_buf = NULL; - unsigned int xfer_len = 0; + unsigned int delay_usecs = 0, xfer_len = 0; struct spi_transfer *t, trans = {}; int ret; @@ -333,9 +323,19 @@ static int fsl_espi_do_one_msg(struct spi_master *master, rx_buf = t->rx_buf; if ((t->tx_buf) || (t->rx_buf)) xfer_len += t->len; + if (t->delay_usecs > delay_usecs) + delay_usecs = t->delay_usecs; } + t = list_first_entry(&m->transfers, struct spi_transfer, + transfer_list); + trans.len = xfer_len; + trans.speed_hz = t->speed_hz; + trans.bits_per_word = t->bits_per_word; + trans.delay_usecs = delay_usecs; + trans.tx_buf = mspi->local_buf; + trans.rx_buf = mspi->local_buf; ret = fsl_espi_trans(m, &trans, rx_buf); From cce7e3a2fe39a5b66162a3dc1463a1af598d0803 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:54:18 +0200 Subject: [PATCH 26/41] spi: fsl-espi: factor out handling of read data Factor out copying read data to the read buffers in the original message to a new function fsl_espi_copy_from_buf. This also allows to simplify fsl_espi_copy_to_buf. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 7fc9a2c66396..2af7463aea8d 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -77,25 +77,32 @@ struct fsl_espi_reg { #define AUTOSUSPEND_TIMEOUT 2000 -static unsigned int fsl_espi_copy_to_buf(struct spi_message *m, - struct mpc8xxx_spi *mspi) +static void fsl_espi_copy_to_buf(struct spi_message *m, + struct mpc8xxx_spi *mspi) { - unsigned int tx_only = 0; struct spi_transfer *t; u8 *buf = mspi->local_buf; list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf) { + if (t->tx_buf) memcpy(buf, t->tx_buf, t->len); - if (!t->rx_buf) - tx_only += t->len; - } else { + else memset(buf, 0, t->len); - } buf += t->len; } +} - return tx_only; +static void fsl_espi_copy_from_buf(struct spi_message *m, + struct mpc8xxx_spi *mspi) +{ + struct spi_transfer *t; + u8 *buf = mspi->local_buf; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->rx_buf) + memcpy(t->rx_buf, buf, t->len); + buf += t->len; + } } static int fsl_espi_check_message(struct spi_message *m) @@ -287,20 +294,17 @@ static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) return ret; } -static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans, - u8 *rx_buff) +static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - unsigned int tx_only; int ret; - tx_only = fsl_espi_copy_to_buf(m, mspi); + fsl_espi_copy_to_buf(m, mspi); ret = fsl_espi_do_trans(m, trans); - /* If there is at least one RX byte then copy it to rx_buff */ - if (!ret && rx_buff && trans->len > tx_only) - memcpy(rx_buff, trans->rx_buf + tx_only, trans->len - tx_only); + if (!ret) + fsl_espi_copy_from_buf(m, mspi); return ret; } @@ -309,7 +313,6 @@ static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - u8 *rx_buf = NULL; unsigned int delay_usecs = 0, xfer_len = 0; struct spi_transfer *t, trans = {}; int ret; @@ -319,8 +322,6 @@ static int fsl_espi_do_one_msg(struct spi_master *master, goto out; list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->rx_buf) - rx_buf = t->rx_buf; if ((t->tx_buf) || (t->rx_buf)) xfer_len += t->len; if (t->delay_usecs > delay_usecs) @@ -337,7 +338,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, trans.tx_buf = mspi->local_buf; trans.rx_buf = mspi->local_buf; - ret = fsl_espi_trans(m, &trans, rx_buf); + ret = fsl_espi_trans(m, &trans); m->actual_length = ret ? 0 : trans.len; out: From 06af115d6c6d8b3d7b6cbc8a46f0603e70b1be58 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:54:35 +0200 Subject: [PATCH 27/41] spi: fsl-espi: improve message length handling Move checking for a zero-length message up in the call chain and use m->frame_length instead of re-calculating the overall length of all transfers in the message. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 2af7463aea8d..7b2f997b061f 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -283,8 +283,7 @@ static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) fsl_espi_setup_transfer(spi, trans); - if (trans->len) - ret = fsl_espi_bufs(spi, trans); + ret = fsl_espi_bufs(spi, trans); if (trans->delay_usecs) udelay(trans->delay_usecs); @@ -313,7 +312,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master, struct spi_message *m) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - unsigned int delay_usecs = 0, xfer_len = 0; + unsigned int delay_usecs = 0; struct spi_transfer *t, trans = {}; int ret; @@ -322,8 +321,6 @@ static int fsl_espi_do_one_msg(struct spi_master *master, goto out; list_for_each_entry(t, &m->transfers, transfer_list) { - if ((t->tx_buf) || (t->rx_buf)) - xfer_len += t->len; if (t->delay_usecs > delay_usecs) delay_usecs = t->delay_usecs; } @@ -331,14 +328,15 @@ static int fsl_espi_do_one_msg(struct spi_master *master, t = list_first_entry(&m->transfers, struct spi_transfer, transfer_list); - trans.len = xfer_len; + trans.len = m->frame_length; trans.speed_hz = t->speed_hz; trans.bits_per_word = t->bits_per_word; trans.delay_usecs = delay_usecs; trans.tx_buf = mspi->local_buf; trans.rx_buf = mspi->local_buf; - ret = fsl_espi_trans(m, &trans); + if (trans.len) + ret = fsl_espi_trans(m, &trans); m->actual_length = ret ? 0 : trans.len; out: From 38d003f1a43f3afd6b5e0da728f06dad07a85687 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Sep 2016 22:54:51 +0200 Subject: [PATCH 28/41] spi: fsl-espi: merge fsl_espi_trans and fsl_espi_do_trans Merge both functions to reduce source code size and improve readability. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 7b2f997b061f..bef06762a770 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -276,11 +276,13 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) return mpc8xxx_spi->count > 0 ? -EMSGSIZE : 0; } -static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) +static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) { + struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); struct spi_device *spi = m->spi; - int ret = 0; + int ret; + fsl_espi_copy_to_buf(m, mspi); fsl_espi_setup_transfer(spi, trans); ret = fsl_espi_bufs(spi, trans); @@ -290,18 +292,6 @@ static int fsl_espi_do_trans(struct spi_message *m, struct spi_transfer *trans) fsl_espi_setup_transfer(spi, NULL); - return ret; -} - -static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) -{ - struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master); - int ret; - - fsl_espi_copy_to_buf(m, mspi); - - ret = fsl_espi_do_trans(m, trans); - if (!ret) fsl_espi_copy_from_buf(m, mspi); From 164c5cd5ffabfa7a060999f8184927017287c39b Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 8 Sep 2016 09:53:25 +0200 Subject: [PATCH 29/41] spi: meson: Add GXBB Compatible string Signed-off-by: Neil Armstrong Acked-by: Kevin Hilman Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-meson.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi-meson.txt b/Documentation/devicetree/bindings/spi/spi-meson.txt index bb52a86f3365..dc6d0313324a 100644 --- a/Documentation/devicetree/bindings/spi/spi-meson.txt +++ b/Documentation/devicetree/bindings/spi/spi-meson.txt @@ -7,7 +7,7 @@ NOR memories, without DMA support and a 64-byte unified transmit / receive buffer. Required properties: - - compatible: should be "amlogic,meson6-spifc" + - compatible: should be "amlogic,meson6-spifc" or "amlogic,meson-gxbb-spifc" - reg: physical base address and length of the controller registers - clocks: phandle of the input clock for the baud rate generator - #address-cells: should be 1 From 2f58ea64bd8931bd7709732fe0a96e0bfb44a00b Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 8 Sep 2016 09:53:26 +0200 Subject: [PATCH 30/41] spi: meson: Add GXBB compatible Signed-off-by: Neil Armstrong Acked-by: Kevin Hilman Signed-off-by: Mark Brown --- drivers/spi/spi-meson-spifc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c index 2465259f6241..616566e793c6 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -442,6 +442,7 @@ static const struct dev_pm_ops meson_spifc_pm_ops = { static const struct of_device_id meson_spifc_dt_match[] = { { .compatible = "amlogic,meson6-spifc", }, + { .compatible = "amlogic,meson-gxbb-spifc", }, { }, }; MODULE_DEVICE_TABLE(of, meson_spifc_dt_match); From 2636ba8fa39915c7b8d73166961ebbb4c14251cd Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 1 Sep 2016 22:38:40 +0200 Subject: [PATCH 31/41] spi: imx: set spi_bus_clk for mx1, mx31 and mx35 Modify spi_imx_clkdiv_2() to return the resulting bus clock frequency when the selected clock divider is applied. Set spi_imx->spi_bus_clk to this frequency. If spi_bus_clk is unset, spi_imx_calculate_timeout() causes a division by 0. Signed-off-by: Martin Kaiser Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index f63cb30f9010..5cc72be30744 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -186,17 +186,19 @@ static unsigned int spi_imx_clkdiv_1(unsigned int fin, /* MX1, MX31, MX35, MX51 CSPI */ static unsigned int spi_imx_clkdiv_2(unsigned int fin, - unsigned int fspi) + unsigned int fspi, unsigned int *fres) { int i, div = 4; for (i = 0; i < 7; i++) { if (fspi * div >= fin) - return i; + goto out; div <<= 1; } - return 7; +out: + *fres = fin / div; + return i; } static int spi_imx_bytes_per_word(const int bpw) @@ -482,9 +484,11 @@ static int mx31_config(struct spi_device *spi, struct spi_imx_config *config) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER; + unsigned int clk; - reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << + reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz, &clk) << MX31_CSPICTRL_DR_SHIFT; + spi_imx->spi_bus_clk = clk; if (is_imx35_cspi(spi_imx)) { reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT; @@ -625,9 +629,12 @@ static int mx1_config(struct spi_device *spi, struct spi_imx_config *config) { struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER; + unsigned int clk; - reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) << + reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz, &clk) << MX1_CSPICTRL_DR_SHIFT; + spi_imx->spi_bus_clk = clk; + reg |= config->bpw - 1; if (spi->mode & SPI_CPHA) From 15ca92156e6242060dff91c8d8e7fe7ae82d424a Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 1 Sep 2016 22:39:58 +0200 Subject: [PATCH 32/41] spi: imx: support loopback mode on imx35 imx35 and compatible chipsets support loopback mode by setting a loopback control bit in the test register. Make this setting available for data transfers, similar to what we do for imx51. Signed-off-by: Martin Kaiser Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 5cc72be30744..53e7a326c213 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -455,6 +455,9 @@ static void mx51_ecspi_reset(struct spi_imx_data *spi_imx) #define MX31_CSPISTATUS 0x14 #define MX31_STATUS_RR (1 << 3) +#define MX31_CSPI_TESTREG 0x1C +#define MX31_TEST_LBC (1 << 14) + /* These functions also work for the i.MX35, but be aware that * the i.MX35 has a slightly different register layout for bits * we do not use here. @@ -510,6 +513,13 @@ static int mx31_config(struct spi_device *spi, struct spi_imx_config *config) writel(reg, spi_imx->base + MXC_CSPICTRL); + reg = readl(spi_imx->base + MX31_CSPI_TESTREG); + if (spi->mode & SPI_LOOP) + reg |= MX31_TEST_LBC; + else + reg &= ~MX31_TEST_LBC; + writel(reg, spi_imx->base + MX31_CSPI_TESTREG); + return 0; } @@ -1186,7 +1196,7 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message; spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message; spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - if (is_imx51_ecspi(spi_imx)) + if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) spi_imx->bitbang.master->mode_bits |= SPI_LOOP; init_completion(&spi_imx->xfer_done); From d198ebfb75adec5156b07b96dc21b6b9e5144018 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 13 Sep 2016 23:15:45 +0200 Subject: [PATCH 33/41] spi: fsl-espi: simplify fsl_espi_setup_transfer If t is not null then the SPI core takes care that bits_per_word and speed_hz are populated. This allows to simplify fsl_espi_setup_transfer. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index bef06762a770..060624f45ce0 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -176,23 +176,11 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - int bits_per_word = 0; + int bits_per_word = t ? t->bits_per_word : spi->bits_per_word; + u32 hz = t ? t->speed_hz : spi->max_speed_hz; u8 pm; - u32 hz = 0; struct spi_mpc8xxx_cs *cs = spi->controller_state; - if (t) { - bits_per_word = t->bits_per_word; - hz = t->speed_hz; - } - - /* spi_transfer level calls that work per-word */ - if (!bits_per_word) - bits_per_word = spi->bits_per_word; - - if (!hz) - hz = spi->max_speed_hz; - cs->rx_shift = 0; cs->tx_shift = 0; cs->get_rx = mpc8xxx_spi_rx_buf_u32; From 35f5d71e38f2c0a9e7fdfbe0e9527efc712cfbcf Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 13 Sep 2016 23:15:57 +0200 Subject: [PATCH 34/41] spi: fsl-espi: improve and simplify interrupt handler Simplify the interrupt handler a little. In addition don't call fsl_espi_cpu_irq() if no event bit is set. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 060624f45ce0..032bf3af8388 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -443,17 +443,11 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) ®_base->event)) & SPIE_NF), 1000, 0); if (!ret) { dev_err(mspi->dev, "tired waiting for SPIE_NF\n"); - - /* Clear the SPIE bits */ - mpc8xxx_spi_write_reg(®_base->event, events); complete(&mspi->done); return; } } - /* Clear the events */ - mpc8xxx_spi_write_reg(®_base->event, events); - mspi->count -= 1; if (mspi->count) { u32 word = mspi->get_tx(mspi); @@ -468,19 +462,21 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) { struct mpc8xxx_spi *mspi = context_data; struct fsl_espi_reg *reg_base = mspi->reg_base; - irqreturn_t ret = IRQ_NONE; u32 events; /* Get interrupt events(tx/rx) */ events = mpc8xxx_spi_read_reg(®_base->event); - if (events) - ret = IRQ_HANDLED; + if (!events) + return IRQ_NONE; dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events); fsl_espi_cpu_irq(mspi, events); - return ret; + /* Clear the events */ + mpc8xxx_spi_write_reg(®_base->event, events); + + return IRQ_HANDLED; } #ifdef CONFIG_PM From 46afd38b7de347fd329767957886901ee9912d7a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 13 Sep 2016 23:16:02 +0200 Subject: [PATCH 35/41] spi: fsl-espi: align register access with other drivers Change register access to the method used in other drivers too. - use register names as in the chip spec for constants - avoid hard to read statements like __be32 __iomem *espi_mode = ®_base->mode - get rid of old powerpc-specific functions like in_8 In addition annotate reg_base in struct mpc8xxx_spi as __iomem. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 135 ++++++++++++++++++++----------------- drivers/spi/spi-fsl-lib.h | 2 +- 2 files changed, 73 insertions(+), 64 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 032bf3af8388..328b04a36328 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -26,16 +26,15 @@ #include "spi-fsl-lib.h" /* eSPI Controller registers */ -struct fsl_espi_reg { - __be32 mode; /* 0x000 - eSPI mode register */ - __be32 event; /* 0x004 - eSPI event register */ - __be32 mask; /* 0x008 - eSPI mask register */ - __be32 command; /* 0x00c - eSPI command register */ - __be32 transmit; /* 0x010 - eSPI transmit FIFO access register*/ - __be32 receive; /* 0x014 - eSPI receive FIFO access register*/ - u8 res[8]; /* 0x018 - 0x01c reserved */ - __be32 csmode[4]; /* 0x020 - 0x02c eSPI cs mode register */ -}; +#define ESPI_SPMODE 0x00 /* eSPI mode register */ +#define ESPI_SPIE 0x04 /* eSPI event register */ +#define ESPI_SPIM 0x08 /* eSPI mask register */ +#define ESPI_SPCOM 0x0c /* eSPI command register */ +#define ESPI_SPITF 0x10 /* eSPI transmit FIFO access register*/ +#define ESPI_SPIRF 0x14 /* eSPI receive FIFO access register*/ +#define ESPI_SPMODE0 0x20 /* eSPI cs0 mode register */ + +#define ESPI_SPMODEx(x) (ESPI_SPMODE0 + (x) * 4) /* eSPI Controller mode register definitions */ #define SPMODE_ENABLE (1 << 31) @@ -77,6 +76,28 @@ struct fsl_espi_reg { #define AUTOSUSPEND_TIMEOUT 2000 +static inline u32 fsl_espi_read_reg(struct mpc8xxx_spi *mspi, int offset) +{ + return ioread32be(mspi->reg_base + offset); +} + +static inline u8 fsl_espi_read_reg8(struct mpc8xxx_spi *mspi, int offset) +{ + return ioread8(mspi->reg_base + offset); +} + +static inline void fsl_espi_write_reg(struct mpc8xxx_spi *mspi, int offset, + u32 val) +{ + iowrite32be(val, mspi->reg_base + offset); +} + +static inline void fsl_espi_write_reg8(struct mpc8xxx_spi *mspi, int offset, + u8 val) +{ + iowrite8(val, mspi->reg_base + offset); +} + static void fsl_espi_copy_to_buf(struct spi_message *m, struct mpc8xxx_spi *mspi) { @@ -133,9 +154,6 @@ static void fsl_espi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); struct spi_mpc8xxx_cs *cs = spi->controller_state; - struct fsl_espi_reg *reg_base = mspi->reg_base; - __be32 __iomem *mode = ®_base->csmode[spi->chip_select]; - __be32 __iomem *espi_mode = ®_base->mode; u32 tmp; unsigned long flags; @@ -143,10 +161,11 @@ static void fsl_espi_change_mode(struct spi_device *spi) local_irq_save(flags); /* Turn off SPI unit prior changing mode */ - tmp = mpc8xxx_spi_read_reg(espi_mode); - mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE); - mpc8xxx_spi_write_reg(mode, cs->hw_mode); - mpc8xxx_spi_write_reg(espi_mode, tmp); + tmp = fsl_espi_read_reg(mspi, ESPI_SPMODE); + fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp & ~SPMODE_ENABLE); + fsl_espi_write_reg(mspi, ESPI_SPMODEx(spi->chip_select), + cs->hw_mode); + fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp); local_irq_restore(flags); } @@ -228,7 +247,6 @@ static void fsl_espi_setup_transfer(struct spi_device *spi, static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; u32 word; int ret; @@ -241,15 +259,15 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) reinit_completion(&mpc8xxx_spi->done); /* Set SPCOM[CS] and SPCOM[TRANLEN] field */ - mpc8xxx_spi_write_reg(®_base->command, + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1))); /* enable rx ints */ - mpc8xxx_spi_write_reg(®_base->mask, SPIM_NE); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_NE); /* transmit word */ word = mpc8xxx_spi->get_tx(mpc8xxx_spi); - mpc8xxx_spi_write_reg(®_base->transmit, word); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, word); /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ); @@ -259,7 +277,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) mpc8xxx_spi->count); /* disable rx ints */ - mpc8xxx_spi_write_reg(®_base->mask, 0); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0); return mpc8xxx_spi->count > 0 ? -EMSGSIZE : 0; } @@ -329,7 +347,6 @@ out: static int fsl_espi_setup(struct spi_device *spi) { struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_espi_reg *reg_base; u32 hw_mode; u32 loop_mode; struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); @@ -345,13 +362,12 @@ static int fsl_espi_setup(struct spi_device *spi) } mpc8xxx_spi = spi_master_get_devdata(spi->master); - reg_base = mpc8xxx_spi->reg_base; pm_runtime_get_sync(mpc8xxx_spi->dev); hw_mode = cs->hw_mode; /* Save original settings */ - cs->hw_mode = mpc8xxx_spi_read_reg( - ®_base->csmode[spi->chip_select]); + cs->hw_mode = fsl_espi_read_reg(mpc8xxx_spi, + ESPI_SPMODEx(spi->chip_select)); /* mask out bits we are going to set */ cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH | CSMODE_REV); @@ -364,11 +380,11 @@ static int fsl_espi_setup(struct spi_device *spi) cs->hw_mode |= CSMODE_REV; /* Handle the loop mode */ - loop_mode = mpc8xxx_spi_read_reg(®_base->mode); + loop_mode = fsl_espi_read_reg(mpc8xxx_spi, ESPI_SPMODE); loop_mode &= ~SPMODE_LOOP; if (spi->mode & SPI_LOOP) loop_mode |= SPMODE_LOOP; - mpc8xxx_spi_write_reg(®_base->mode, loop_mode); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, loop_mode); fsl_espi_setup_transfer(spi, NULL); @@ -388,8 +404,6 @@ static void fsl_espi_cleanup(struct spi_device *spi) static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) { - struct fsl_espi_reg *reg_base = mspi->reg_base; - /* We need handle RX first */ if (events & SPIE_NE) { u32 rx_data, tmp; @@ -401,7 +415,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) if (SPIE_RXCNT(events) < min(4, mspi->len)) { ret = spin_event_timeout( !(SPIE_RXCNT(events = - mpc8xxx_spi_read_reg(®_base->event)) < + fsl_espi_read_reg(mspi, ESPI_SPIE)) < min(4, mspi->len)), 10000, 0); /* 10 msec */ if (!ret) @@ -410,7 +424,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) } if (mspi->len >= 4) { - rx_data = mpc8xxx_spi_read_reg(®_base->receive); + rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF); } else if (mspi->len <= 0) { dev_err(mspi->dev, "unexpected RX(SPIE_NE) interrupt occurred,\n" @@ -422,7 +436,8 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) tmp = mspi->len; rx_data = 0; while (tmp--) { - rx_data_8 = in_8((u8 *)®_base->receive); + rx_data_8 = fsl_espi_read_reg8(mspi, + ESPI_SPIRF); rx_data |= (rx_data_8 << (tmp * 8)); } @@ -439,8 +454,8 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) int ret; /* spin until TX is done */ - ret = spin_event_timeout(((events = mpc8xxx_spi_read_reg( - ®_base->event)) & SPIE_NF), 1000, 0); + ret = spin_event_timeout(((events = fsl_espi_read_reg( + mspi, ESPI_SPIE)) & SPIE_NF), 1000, 0); if (!ret) { dev_err(mspi->dev, "tired waiting for SPIE_NF\n"); complete(&mspi->done); @@ -452,7 +467,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) if (mspi->count) { u32 word = mspi->get_tx(mspi); - mpc8xxx_spi_write_reg(®_base->transmit, word); + fsl_espi_write_reg(mspi, ESPI_SPITF, word); } else { complete(&mspi->done); } @@ -461,11 +476,10 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) { struct mpc8xxx_spi *mspi = context_data; - struct fsl_espi_reg *reg_base = mspi->reg_base; u32 events; /* Get interrupt events(tx/rx) */ - events = mpc8xxx_spi_read_reg(®_base->event); + events = fsl_espi_read_reg(mspi, ESPI_SPIE); if (!events) return IRQ_NONE; @@ -474,7 +488,7 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) fsl_espi_cpu_irq(mspi, events); /* Clear the events */ - mpc8xxx_spi_write_reg(®_base->event, events); + fsl_espi_write_reg(mspi, ESPI_SPIE, events); return IRQ_HANDLED; } @@ -484,12 +498,11 @@ static int fsl_espi_runtime_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); - struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; u32 regval; - regval = mpc8xxx_spi_read_reg(®_base->mode); + regval = fsl_espi_read_reg(mpc8xxx_spi, ESPI_SPMODE); regval &= ~SPMODE_ENABLE; - mpc8xxx_spi_write_reg(®_base->mode, regval); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval); return 0; } @@ -498,12 +511,11 @@ static int fsl_espi_runtime_resume(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); - struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; u32 regval; - regval = mpc8xxx_spi_read_reg(®_base->mode); + regval = fsl_espi_read_reg(mpc8xxx_spi, ESPI_SPMODE); regval |= SPMODE_ENABLE; - mpc8xxx_spi_write_reg(®_base->mode, regval); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval); return 0; } @@ -520,7 +532,6 @@ static struct spi_master * fsl_espi_probe(struct device *dev, struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_espi_reg *reg_base; struct device_node *nc; const __be32 *prop; u32 regval, csmode; @@ -558,8 +569,6 @@ static struct spi_master * fsl_espi_probe(struct device *dev, goto err_probe; } - reg_base = mpc8xxx_spi->reg_base; - /* Register for SPI Interrupt */ ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_espi_irq, 0, "fsl_espi", mpc8xxx_spi); @@ -572,10 +581,10 @@ static struct spi_master * fsl_espi_probe(struct device *dev, } /* SPI controller initializations */ - mpc8xxx_spi_write_reg(®_base->mode, 0); - mpc8xxx_spi_write_reg(®_base->mask, 0); - mpc8xxx_spi_write_reg(®_base->command, 0); - mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, 0); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, 0); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIE, 0xffffffff); /* Init eSPI CS mode register */ for_each_available_child_of_node(master->dev.of_node, nc) { @@ -600,7 +609,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev, csmode &= ~(CSMODE_AFT(0xf)); csmode |= CSMODE_AFT(be32_to_cpup(prop)); } - mpc8xxx_spi_write_reg(®_base->csmode[i], csmode); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(i), csmode); dev_info(dev, "cs=%d, init_csmode=0x%x\n", i, csmode); } @@ -608,7 +617,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev, /* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; - mpc8xxx_spi_write_reg(®_base->mode, regval); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval); pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT); pm_runtime_use_autosuspend(dev); @@ -620,7 +629,8 @@ static struct spi_master * fsl_espi_probe(struct device *dev, if (ret < 0) goto err_pm; - dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); + dev_info(dev, "at 0x%p (irq = %d)\n", mpc8xxx_spi->reg_base, + mpc8xxx_spi->irq); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -726,27 +736,26 @@ static int of_fsl_espi_resume(struct device *dev) struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master = dev_get_drvdata(dev); struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_espi_reg *reg_base; u32 regval; int i, ret; mpc8xxx_spi = spi_master_get_devdata(master); - reg_base = mpc8xxx_spi->reg_base; /* SPI controller initializations */ - mpc8xxx_spi_write_reg(®_base->mode, 0); - mpc8xxx_spi_write_reg(®_base->mask, 0); - mpc8xxx_spi_write_reg(®_base->command, 0); - mpc8xxx_spi_write_reg(®_base->event, 0xffffffff); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, 0); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, 0); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIE, 0xffffffff); /* Init eSPI CS mode register */ for (i = 0; i < pdata->max_chipselect; i++) - mpc8xxx_spi_write_reg(®_base->csmode[i], CSMODE_INIT_VAL); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(i), + CSMODE_INIT_VAL); /* Enable SPI interface */ regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE; - mpc8xxx_spi_write_reg(®_base->mode, regval); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, regval); ret = pm_runtime_force_resume(dev); if (ret < 0) diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index 065b9db212cf..2925c8089fd9 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -23,7 +23,7 @@ /* SPI/eSPI Controller driver's private data. */ struct mpc8xxx_spi { struct device *dev; - void *reg_base; + void __iomem *reg_base; /* rx & tx bufs from the spi_transfer */ const void *tx; From 81abc2ecac838da89076fe9e0e5892ed83bf1ab2 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 13 Sep 2016 23:16:06 +0200 Subject: [PATCH 36/41] spi: fsl-espi: improve and extend register bit definitions Add definition of further register bits for use in upcoming driver extensions and improve current bit definitions: - use BIT macro - use bit names as in the chip spec Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 52 ++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 328b04a36328..a7984aeede6b 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -37,18 +37,18 @@ #define ESPI_SPMODEx(x) (ESPI_SPMODE0 + (x) * 4) /* eSPI Controller mode register definitions */ -#define SPMODE_ENABLE (1 << 31) -#define SPMODE_LOOP (1 << 30) +#define SPMODE_ENABLE BIT(31) +#define SPMODE_LOOP BIT(30) #define SPMODE_TXTHR(x) ((x) << 8) #define SPMODE_RXTHR(x) ((x) << 0) /* eSPI Controller CS mode register definitions */ -#define CSMODE_CI_INACTIVEHIGH (1 << 31) -#define CSMODE_CP_BEGIN_EDGECLK (1 << 30) -#define CSMODE_REV (1 << 29) -#define CSMODE_DIV16 (1 << 28) +#define CSMODE_CI_INACTIVEHIGH BIT(31) +#define CSMODE_CP_BEGIN_EDGECLK BIT(30) +#define CSMODE_REV BIT(29) +#define CSMODE_DIV16 BIT(28) #define CSMODE_PM(x) ((x) << 24) -#define CSMODE_POL_1 (1 << 20) +#define CSMODE_POL_1 BIT(20) #define CSMODE_LEN(x) ((x) << 16) #define CSMODE_BEF(x) ((x) << 12) #define CSMODE_AFT(x) ((x) << 8) @@ -60,18 +60,32 @@ | CSMODE_AFT(0) | CSMODE_CG(1)) /* SPIE register values */ -#define SPIE_NE 0x00000200 /* Not empty */ -#define SPIE_NF 0x00000100 /* Not full */ - -/* SPIM register values */ -#define SPIM_NE 0x00000200 /* Not empty */ -#define SPIM_NF 0x00000100 /* Not full */ #define SPIE_RXCNT(reg) ((reg >> 24) & 0x3F) #define SPIE_TXCNT(reg) ((reg >> 16) & 0x3F) +#define SPIE_TXE BIT(15) /* TX FIFO empty */ +#define SPIE_DON BIT(14) /* TX done */ +#define SPIE_RXT BIT(13) /* RX FIFO threshold */ +#define SPIE_RXF BIT(12) /* RX FIFO full */ +#define SPIE_TXT BIT(11) /* TX FIFO threshold*/ +#define SPIE_RNE BIT(9) /* RX FIFO not empty */ +#define SPIE_TNF BIT(8) /* TX FIFO not full */ + +/* SPIM register values */ +#define SPIM_TXE BIT(15) /* TX FIFO empty */ +#define SPIM_DON BIT(14) /* TX done */ +#define SPIM_RXT BIT(13) /* RX FIFO threshold */ +#define SPIM_RXF BIT(12) /* RX FIFO full */ +#define SPIM_TXT BIT(11) /* TX FIFO threshold*/ +#define SPIM_RNE BIT(9) /* RX FIFO not empty */ +#define SPIM_TNF BIT(8) /* TX FIFO not full */ /* SPCOM register values */ #define SPCOM_CS(x) ((x) << 30) +#define SPCOM_DO BIT(28) /* Dual output */ +#define SPCOM_TO BIT(27) /* TX only */ +#define SPCOM_RXSKIP(x) ((x) << 16) #define SPCOM_TRANLEN(x) ((x) << 0) + #define SPCOM_TRANLEN_MAX 0x10000 /* Max transaction length */ #define AUTOSUSPEND_TIMEOUT 2000 @@ -263,7 +277,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1))); /* enable rx ints */ - fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_NE); + fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE); /* transmit word */ word = mpc8xxx_spi->get_tx(mpc8xxx_spi); @@ -405,7 +419,7 @@ static void fsl_espi_cleanup(struct spi_device *spi) static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) { /* We need handle RX first */ - if (events & SPIE_NE) { + if (events & SPIE_RNE) { u32 rx_data, tmp; u8 rx_data_8; int rx_nr_bytes = 4; @@ -427,7 +441,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF); } else if (mspi->len <= 0) { dev_err(mspi->dev, - "unexpected RX(SPIE_NE) interrupt occurred,\n" + "unexpected RX(SPIE_RNE) interrupt occurred,\n" "(local rxlen %d bytes, reg rxlen %d bytes)\n", min(4, mspi->len), SPIE_RXCNT(events)); rx_nr_bytes = 0; @@ -450,14 +464,14 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) mspi->get_rx(rx_data, mspi); } - if (!(events & SPIE_NF)) { + if (!(events & SPIE_TNF)) { int ret; /* spin until TX is done */ ret = spin_event_timeout(((events = fsl_espi_read_reg( - mspi, ESPI_SPIE)) & SPIE_NF), 1000, 0); + mspi, ESPI_SPIE)) & SPIE_TNF), 1000, 0); if (!ret) { - dev_err(mspi->dev, "tired waiting for SPIE_NF\n"); + dev_err(mspi->dev, "tired waiting for SPIE_TNF\n"); complete(&mspi->done); return; } From fb8ac912df93ea4edc549992d7c9d173e5413164 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 17 Sep 2016 15:42:42 +0200 Subject: [PATCH 37/41] spi: fsl-espi: remove unused variable in fsl_espi_setup Remove an unused variable. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index a7984aeede6b..4f9d9ec6880a 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -361,7 +361,6 @@ out: static int fsl_espi_setup(struct spi_device *spi) { struct mpc8xxx_spi *mpc8xxx_spi; - u32 hw_mode; u32 loop_mode; struct spi_mpc8xxx_cs *cs = spi_get_ctldata(spi); @@ -379,7 +378,6 @@ static int fsl_espi_setup(struct spi_device *spi) pm_runtime_get_sync(mpc8xxx_spi->dev); - hw_mode = cs->hw_mode; /* Save original settings */ cs->hw_mode = fsl_espi_read_reg(mpc8xxx_spi, ESPI_SPMODEx(spi->chip_select)); /* mask out bits we are going to set */ From acf692190f972ee2ed6578f30278f21c244d6148 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 17 Sep 2016 15:43:00 +0200 Subject: [PATCH 38/41] spi: fsl-espi: simplify of_fsl_espi_probe Simplify of_fsl_espi_probe. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 4f9d9ec6880a..dee3f822cea8 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -685,7 +685,7 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) struct spi_master *master; struct resource mem; unsigned int irq; - int ret = -ENOMEM; + int ret; ret = of_mpc8xxx_spi_probe(ofdev); if (ret) @@ -693,28 +693,21 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) ret = of_fsl_espi_get_chipselects(dev); if (ret) - goto err; + return ret; ret = of_address_to_resource(np, 0, &mem); if (ret) - goto err; + return ret; irq = irq_of_parse_and_map(np, 0); - if (!irq) { - ret = -EINVAL; - goto err; - } + if (!irq) + return -EINVAL; master = fsl_espi_probe(dev, &mem, irq); - if (IS_ERR(master)) { - ret = PTR_ERR(master); - goto err; - } + if (IS_ERR(master)) + return PTR_ERR(master); return 0; - -err: - return ret; } static int of_fsl_espi_remove(struct platform_device *dev) From 604042af7697314fffb16e266fd7d5ad488439cc Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 17 Sep 2016 15:43:31 +0200 Subject: [PATCH 39/41] spi: fsl-espi: improve return value handling in fsl_espi_probe The return value of fsl_espi_probe (currently struct spi_master *) is just used for checking whether an error occurred. Change the return value type to int and simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index dee3f822cea8..7451585a080e 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -538,8 +538,8 @@ static size_t fsl_espi_max_message_size(struct spi_device *spi) return SPCOM_TRANLEN_MAX; } -static struct spi_master * fsl_espi_probe(struct device *dev, - struct resource *mem, unsigned int irq) +static int fsl_espi_probe(struct device *dev, struct resource *mem, + unsigned int irq) { struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master; @@ -547,13 +547,11 @@ static struct spi_master * fsl_espi_probe(struct device *dev, struct device_node *nc; const __be32 *prop; u32 regval, csmode; - int i, len, ret = 0; + int i, len, ret; master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi)); - if (!master) { - ret = -ENOMEM; - goto err; - } + if (!master) + return -ENOMEM; dev_set_drvdata(dev, master); @@ -647,7 +645,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev, pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); - return master; + return 0; err_pm: pm_runtime_put_noidle(dev); @@ -655,8 +653,7 @@ err_pm: pm_runtime_set_suspended(dev); err_probe: spi_master_put(master); -err: - return ERR_PTR(ret); + return ret; } static int of_fsl_espi_get_chipselects(struct device *dev) @@ -682,7 +679,6 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; struct device_node *np = ofdev->dev.of_node; - struct spi_master *master; struct resource mem; unsigned int irq; int ret; @@ -703,11 +699,7 @@ static int of_fsl_espi_probe(struct platform_device *ofdev) if (!irq) return -EINVAL; - master = fsl_espi_probe(dev, &mem, irq); - if (IS_ERR(master)) - return PTR_ERR(master); - - return 0; + return fsl_espi_probe(dev, &mem, irq); } static int of_fsl_espi_remove(struct platform_device *dev) From f13d4e189d209af0f552e9900acd06ee4a35e601 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 26 Sep 2016 14:14:53 +0200 Subject: [PATCH 40/41] spi: imx: Gracefully handle NULL master->cs_gpios It is possible that master->cs_gpios is NULL after spi_bitbang_start(), this happens if the master has no CS GPIOs specified in DT. Check for this case after spi_bitbang_start() to prevent NULL pointer dereference in the subsequent for loop, which accesses the master->cs_gpios field. Signed-off-by: Marek Vasut Cc: Martin Kaiser Cc: Mark Brown Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 53e7a326c213..1ef5429afcb6 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1268,6 +1268,11 @@ static int spi_imx_probe(struct platform_device *pdev) goto out_clk_put; } + if (!master->cs_gpios) { + dev_err(&pdev->dev, "No CS GPIOs available\n"); + goto out_clk_put; + } + for (i = 0; i < master->num_chipselect; i++) { if (!gpio_is_valid(master->cs_gpios[i])) continue; From 446576f9ea5308c671eafb1cdc2a977b406c1dc5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 28 Sep 2016 14:50:18 +0000 Subject: [PATCH 41/41] spi: imx: fix error return code in spi_imx_probe() Fix to return error code -EINVAL if no CS GPIOs available instead of 0, as done elsewhere in this function. Fixes: f13d4e189d20 ("spi: imx: Gracefully handle NULL master->cs_gpios") Signed-off-by: Wei Yongjun Acked-by: Marek Vasut Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 1ef5429afcb6..deb782f6556c 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1270,6 +1270,7 @@ static int spi_imx_probe(struct platform_device *pdev) if (!master->cs_gpios) { dev_err(&pdev->dev, "No CS GPIOs available\n"); + ret = -EINVAL; goto out_clk_put; }