From 93e3a9e9993ef018522b7005d97d8124b7e73385 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 18 Jun 2015 13:27:12 +0100 Subject: spi: img-spfi: check for max speed supported by the spfi block Maximum speed supported by spfi is limited to 1/4 of the spfi clock. But in some SoCs the maximum speed supported by the spfi block can be limited to less than 1/4 of the spfi clock. In such cases we have to define the limit in the device tree so that the driver can pick it up. Signed-off-by: Sifan Naeem Signed-off-by: Mark Brown --- drivers/spi/spi-img-spfi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 788e2b176a4f..f31d792a4662 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -546,6 +546,7 @@ static int img_spfi_probe(struct platform_device *pdev) struct img_spfi *spfi; struct resource *res; int ret; + u32 max_speed_hz; master = spi_alloc_master(&pdev->dev, sizeof(*spfi)); if (!master) @@ -610,6 +611,19 @@ static int img_spfi_probe(struct platform_device *pdev) master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; + /* + * Maximum speed supported by spfi is limited to the lower value + * between 1/4 of the SPFI clock or to "spfi-max-frequency" + * defined in the device tree. + * If no value is defined in the device tree assume the maximum + * speed supported to be 1/4 of the SPFI clock. + */ + if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency", + &max_speed_hz)) { + if (master->max_speed_hz > max_speed_hz) + master->max_speed_hz = max_speed_hz; + } + master->setup = img_spfi_setup; master->cleanup = img_spfi_cleanup; master->transfer_one = img_spfi_transfer_one; -- cgit v1.2.3 From 8bf960985dfc9fcb231a07dc3102ed828f66fe81 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 14 Jul 2015 11:19:56 +0200 Subject: spi: mpc512x-psc: add support for Freescale MPC5125 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The register layout of the PSC devices differ between MPC5121 and MPC5125, but the registers are named nearly identical and their purpose is similar enough ("freescale identical") such that substituting mpc52xx_psc by mpc5125_psc is nearly enough to make the driver work on MPC5125. To keep supporting MPC5121 this patch introduces a cpp macro to select the right struct that defines the register layout. Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- arch/powerpc/include/asm/mpc52xx_psc.h | 5 ++- drivers/spi/spi-mpc512x-psc.c | 70 +++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h index d0ece257d310..04c7e8fc24c2 100644 --- a/arch/powerpc/include/asm/mpc52xx_psc.h +++ b/arch/powerpc/include/asm/mpc52xx_psc.h @@ -150,7 +150,10 @@ /* Structure of the hardware registers */ struct mpc52xx_psc { - u8 mode; /* PSC + 0x00 */ + union { + u8 mode; /* PSC + 0x00 */ + u8 mr2; + }; u8 reserved0[3]; union { /* PSC + 0x04 */ u16 status; diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 965d2bdcfdcc..280794dd248a 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -30,11 +30,37 @@ #include #include +enum { + TYPE_MPC5121, + TYPE_MPC5125, +}; + +/* + * This macro abstracts the differences in the PSC register layout between + * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc). + */ +#define psc_addr(mps, regname) ({ \ + void *__ret; \ + switch(mps->type) { \ + case TYPE_MPC5121: { \ + struct mpc52xx_psc __iomem *psc = mps->psc; \ + __ret = &psc->regname; \ + }; \ + break; \ + case TYPE_MPC5125: { \ + struct mpc5125_psc __iomem *psc = mps->psc; \ + __ret = &psc->regname; \ + }; \ + break; \ + } \ + __ret; }) + struct mpc512x_psc_spi { void (*cs_control)(struct spi_device *spi, bool on); /* driver internal data */ - struct mpc52xx_psc __iomem *psc; + int type; + void __iomem *psc; struct mpc512x_psc_fifo __iomem *fifo; unsigned int irq; u8 bits_per_word; @@ -71,13 +97,12 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) { struct mpc512x_psc_spi_cs *cs = spi->controller_state; struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); - struct mpc52xx_psc __iomem *psc = mps->psc; u32 sicr; u32 ccr; int speed; u16 bclkdiv; - sicr = in_be32(&psc->sicr); + sicr = in_be32(psc_addr(mps, sicr)); /* Set clock phase and polarity */ if (spi->mode & SPI_CPHA) @@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) sicr |= 0x10000000; else sicr &= ~0x10000000; - out_be32(&psc->sicr, sicr); + out_be32(psc_addr(mps, sicr), sicr); - ccr = in_be32(&psc->ccr); + ccr = in_be32(psc_addr(mps, ccr)); ccr &= 0xFF000000; speed = cs->speed_hz; if (!speed) @@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); - out_be32(&psc->ccr, ccr); + out_be32(psc_addr(mps, ccr), ccr); mps->bits_per_word = cs->bits_per_word; if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) @@ -315,16 +340,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master, static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) { struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); - struct mpc52xx_psc __iomem *psc = mps->psc; dev_dbg(&master->dev, "%s()\n", __func__); /* Zero MR2 */ - in_8(&psc->mode); - out_8(&psc->mode, 0x0); + in_8(psc_addr(mps, mr2)); + out_8(psc_addr(mps, mr2), 0x0); /* enable transmitter/receiver */ - out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); return 0; } @@ -332,13 +356,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master) { struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); - struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; dev_dbg(&master->dev, "%s()\n", __func__); /* disable transmitter/receiver and fifo interrupt */ - out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); out_be32(&fifo->tximr, 0); return 0; @@ -388,7 +411,6 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi) static int mpc512x_psc_spi_port_config(struct spi_master *master, struct mpc512x_psc_spi *mps) { - struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; u32 sicr; u32 ccr; @@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, u16 bclkdiv; /* Reset the PSC into a known state */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - out_8(&psc->command, MPC52xx_PSC_RST_TX); - out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); + out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX); + out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX); + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); /* Disable psc interrupts all useful interrupts are in fifo */ - out_be16(&psc->isr_imr.imr, 0); + out_be16(psc_addr(mps, isr_imr.imr), 0); /* Disable fifo interrupts, will be enabled later */ out_be32(&fifo->tximr, 0); @@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, 0x00004000 | /* MSTR = 1 -- SPI master */ 0x00000800; /* UseEOF = 1 -- SS low until EOF */ - out_be32(&psc->sicr, sicr); + out_be32(psc_addr(mps, sicr), sicr); - ccr = in_be32(&psc->ccr); + ccr = in_be32(psc_addr(mps, ccr)); ccr &= 0xFF000000; speed = 1000000; /* default 1MHz */ bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); - out_be32(&psc->ccr, ccr); + out_be32(psc_addr(mps, ccr), ccr); /* Set 2ms DTL delay */ - out_8(&psc->ctur, 0x00); - out_8(&psc->ctlr, 0x82); + out_8(psc_addr(mps, ctur), 0x00); + out_8(psc_addr(mps, ctlr), 0x82); /* we don't use the alarms */ out_be32(&fifo->rxalarm, 0xfff); @@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, dev_set_drvdata(dev, master); mps = spi_master_get_devdata(master); + mps->type = (int)of_device_get_match_data(dev); mps->irq = irq; if (pdata == NULL) { @@ -589,7 +612,8 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op) } static const struct of_device_id mpc512x_psc_spi_of_match[] = { - { .compatible = "fsl,mpc5121-psc-spi", }, + { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 }, + { .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 }, {}, }; -- cgit v1.2.3 From 1f2112af11e4c330cd070464e95ba9f546b8959b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2015 10:30:42 +0200 Subject: spi: mpc512x-psc: fix compiler warning about uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes several warnings like: drivers/spi/spi-mpc512x-psc.c: In function 'mpc512x_psc_spi_prep_xfer_hw': arch/powerpc/include/asm/io.h:163:2: warning: '__ret' may be used uninitialized in this function [-Wmaybe-uninitialized] introduced in commit 8bf960985dfc for some build configurations. Fixes: 8bf960985dfc ("spi: mpc512x-psc: add support for Freescale MPC5125") Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- drivers/spi/spi-mpc512x-psc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 280794dd248a..1e75341689a6 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -40,8 +40,8 @@ enum { * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc). */ #define psc_addr(mps, regname) ({ \ - void *__ret; \ - switch(mps->type) { \ + void *__ret = NULL; \ + switch (mps->type) { \ case TYPE_MPC5121: { \ struct mpc52xx_psc __iomem *psc = mps->psc; \ __ret = &psc->regname; \ -- cgit v1.2.3 From c4fe57f76269dbb2af135071513f260ca40229a3 Mon Sep 17 00:00:00 2001 From: Michael van der Westhuizen Date: Tue, 18 Aug 2015 22:21:53 +0200 Subject: spi: dw: Allow interface drivers to limit data I/O to word sizes The commit dd11444327ce ("spi: dw-spi: Convert 16bit accesses to 32bit accesses") changed all 16bit accesses in the DW_apb_ssi driver to 32bit. This, unfortunately, breaks data register access on picoXcell, where the DW IP needs data register accesses to be word accesses (all other accesses appear to be OK). This change introduces a new master variable to allow interface drivers to specify that 16bit data transfer I/O is required. This change also introduces the ability to set this variable via device tree bindings in the MMIO interface driver. Both the core and the MMIO interface driver default to the current 32bit behaviour. Before this change, on a picoXcell pc3x3: spi_master spi32766: interrupt_transfer: fifo overrun/underrun m25p80 spi32766.0: error -5 reading 9f m25p80: probe of spi32766.0 failed with error -5 After this change: m25p80 spi32766.0: m25p40 (512 Kbytes) Fixes: dd11444327ce ("spi: dw-spi: Convert 16bit accesses to 32bit accesses") Signed-off-by: Michael van der Westhuizen Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mmio.c | 3 +++ drivers/spi/spi-dw.c | 4 ++-- drivers/spi/spi-dw.h | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index eb03e1215195..7edede6e024b 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -74,6 +74,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) dws->max_freq = clk_get_rate(dwsmmio->clk); + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &dws->reg_io_width); + num_cs = 4; if (pdev->dev.of_node) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 8d67d03c71eb..4fbfcdc5cb24 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -194,7 +194,7 @@ static void dw_writer(struct dw_spi *dws) else txw = *(u16 *)(dws->tx); } - dw_writel(dws, DW_SPI_DR, txw); + dw_write_io_reg(dws, DW_SPI_DR, txw); dws->tx += dws->n_bytes; } } @@ -205,7 +205,7 @@ static void dw_reader(struct dw_spi *dws) u16 rxw; while (max--) { - rxw = dw_readl(dws, DW_SPI_DR); + rxw = dw_read_io_reg(dws, DW_SPI_DR); /* Care rx only if the transfer's original "rx" is not null */ if (dws->rx_end - dws->len) { if (dws->n_bytes == 1) diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 6c91391c1a4f..b75ed327d5a2 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -109,6 +109,7 @@ struct dw_spi { u32 fifo_len; /* depth of the FIFO buffer */ u32 max_freq; /* max bus freq supported */ + u32 reg_io_width; /* DR I/O width in bytes */ u16 bus_num; u16 num_cs; /* supported slave numbers */ @@ -145,11 +146,45 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset) return __raw_readl(dws->regs + offset); } +static inline u16 dw_readw(struct dw_spi *dws, u32 offset) +{ + return __raw_readw(dws->regs + offset); +} + static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val) { __raw_writel(val, dws->regs + offset); } +static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val) +{ + __raw_writew(val, dws->regs + offset); +} + +static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset) +{ + switch (dws->reg_io_width) { + case 2: + return dw_readw(dws, offset); + case 4: + default: + return dw_readl(dws, offset); + } +} + +static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val) +{ + switch (dws->reg_io_width) { + case 2: + dw_writew(dws, offset, val); + break; + case 4: + default: + dw_writel(dws, offset, val); + break; + } +} + static inline void spi_enable_chip(struct dw_spi *dws, int enable) { dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0)); -- cgit v1.2.3 From 4178b6b1b595003cd6e04711b449797a582e44f5 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 26 Aug 2015 21:21:50 +0200 Subject: spi: fsl-(e)spi: migrate to using devm_ functions to simplify cleanup Migrate fsl-espi and fsl-spi to using the managed devm_ functions for resource handling. This simplifies the cleanup. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 20 +++++--------------- drivers/spi/spi-fsl-lib.c | 4 ---- drivers/spi/spi-fsl-spi.c | 21 ++++++++------------- 3 files changed, 13 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d3f05a0525a4..f35eb2c46782 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -604,11 +604,6 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) return ret; } -static void fsl_espi_remove(struct mpc8xxx_spi *mspi) -{ - iounmap(mspi->reg_base); -} - static int fsl_espi_suspend(struct spi_master *master) { struct mpc8xxx_spi *mpc8xxx_spi; @@ -671,9 +666,8 @@ static struct spi_master * fsl_espi_probe(struct device *dev, master->unprepare_transfer_hardware = fsl_espi_suspend; mpc8xxx_spi = spi_master_get_devdata(master); - mpc8xxx_spi->spi_remove = fsl_espi_remove; - mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); + mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); if (!mpc8xxx_spi->reg_base) { ret = -ENOMEM; goto err_probe; @@ -682,10 +676,10 @@ static struct spi_master * fsl_espi_probe(struct device *dev, reg_base = mpc8xxx_spi->reg_base; /* Register for SPI Interrupt */ - ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq, + ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_espi_irq, 0, "fsl_espi", mpc8xxx_spi); if (ret) - goto free_irq; + goto err_probe; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { mpc8xxx_spi->rx_shift = 16; @@ -731,18 +725,14 @@ static struct spi_master * fsl_espi_probe(struct device *dev, mpc8xxx_spi_write_reg(®_base->mode, regval); - ret = spi_register_master(master); + ret = devm_spi_register_master(dev, master); if (ret < 0) - goto unreg_master; + goto err_probe; dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); return master; -unreg_master: - free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); -free_irq: - iounmap(mpc8xxx_spi->reg_base); err_probe: spi_master_put(master); err: diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index cb35d2f0d0e6..e50fd066af06 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -122,10 +122,6 @@ int mpc8xxx_spi_remove(struct device *dev) master = dev_get_drvdata(dev); mpc8xxx_spi = spi_master_get_devdata(master); - spi_unregister_master(master); - - free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); - if (mpc8xxx_spi->spi_remove) mpc8xxx_spi->spi_remove(mpc8xxx_spi); diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 60c590790854..8bfbe9e04bfd 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -561,7 +561,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) static void fsl_spi_remove(struct mpc8xxx_spi *mspi) { - iounmap(mspi->reg_base); fsl_spi_cpm_free(mspi); } @@ -639,10 +638,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev, if (ret) goto err_cpm_init; - mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); + mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); if (mpc8xxx_spi->reg_base == NULL) { ret = -ENOMEM; - goto err_ioremap; + goto err_probe; } if (mpc8xxx_spi->type == TYPE_GRLIB) @@ -661,11 +660,11 @@ static struct spi_master * fsl_spi_probe(struct device *dev, &mpc8xxx_spi->tx_shift, 8, 1); /* Register for SPI Interrupt */ - ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq, - 0, "fsl_spi", mpc8xxx_spi); + ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_spi_irq, + 0, "fsl_spi", mpc8xxx_spi); if (ret != 0) - goto free_irq; + goto err_probe; reg_base = mpc8xxx_spi->reg_base; @@ -686,20 +685,16 @@ static struct spi_master * fsl_spi_probe(struct device *dev, mpc8xxx_spi_write_reg(®_base->mode, regval); - ret = spi_register_master(master); + ret = devm_spi_register_master(dev, master); if (ret < 0) - goto unreg_master; + goto err_probe; dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base, mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags)); return master; -unreg_master: - free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); -free_irq: - iounmap(mpc8xxx_spi->reg_base); -err_ioremap: +err_probe: fsl_spi_cpm_free(mpc8xxx_spi); err_cpm_init: spi_master_put(master); -- cgit v1.2.3 From 3c5395b66ff69d8d568d0b9ff8b1077e044def5b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 26 Aug 2015 21:21:53 +0200 Subject: spi: fsl-(e)spi: simplify cleanup code Now that most cleanup is done automatically the remove functions can be significantly simplified. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 6 ------ drivers/spi/spi-fsl-lib.c | 15 --------------- drivers/spi/spi-fsl-lib.h | 3 --- drivers/spi/spi-fsl-spi.c | 18 +++++++----------- 4 files changed, 7 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index f35eb2c46782..fe54e5788245 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -797,11 +797,6 @@ err: return ret; } -static int of_fsl_espi_remove(struct platform_device *dev) -{ - return mpc8xxx_spi_remove(&dev->dev); -} - #ifdef CONFIG_PM_SLEEP static int of_fsl_espi_suspend(struct device *dev) { @@ -865,7 +860,6 @@ static struct platform_driver fsl_espi_driver = { .pm = &espi_pm, }, .probe = of_fsl_espi_probe, - .remove = of_fsl_espi_remove, }; module_platform_driver(fsl_espi_driver); diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index e50fd066af06..1e43412cd9f8 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -114,21 +114,6 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem, } EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe); -int mpc8xxx_spi_remove(struct device *dev) -{ - struct mpc8xxx_spi *mpc8xxx_spi; - struct spi_master *master; - - master = dev_get_drvdata(dev); - mpc8xxx_spi = spi_master_get_devdata(master); - - if (mpc8xxx_spi->spi_remove) - mpc8xxx_spi->spi_remove(mpc8xxx_spi); - - return 0; -} -EXPORT_SYMBOL_GPL(mpc8xxx_spi_remove); - int of_mpc8xxx_spi_probe(struct platform_device *ofdev) { struct device *dev = &ofdev->dev; diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h index 1326a392adca..84f5dcb7a897 100644 --- a/drivers/spi/spi-fsl-lib.h +++ b/drivers/spi/spi-fsl-lib.h @@ -54,9 +54,6 @@ struct mpc8xxx_spi { void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *); u32(*get_tx) (struct mpc8xxx_spi *); - /* hooks for different controller driver */ - void (*spi_remove) (struct mpc8xxx_spi *mspi); - unsigned int count; unsigned int irq; diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 8bfbe9e04bfd..17a9a879dcce 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -559,11 +559,6 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data) return ret; } -static void fsl_spi_remove(struct mpc8xxx_spi *mspi) -{ - fsl_spi_cpm_free(mspi); -} - static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); @@ -630,7 +625,6 @@ static struct spi_master * fsl_spi_probe(struct device *dev, master->transfer_one_message = fsl_spi_do_one_msg; mpc8xxx_spi = spi_master_get_devdata(master); - mpc8xxx_spi->spi_remove = fsl_spi_remove; mpc8xxx_spi->max_bits_per_word = 32; mpc8xxx_spi->type = fsl_spi_get_type(dev); @@ -861,11 +855,8 @@ static int of_fsl_spi_remove(struct platform_device *ofdev) { struct spi_master *master = platform_get_drvdata(ofdev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); - int ret; - ret = mpc8xxx_spi_remove(&ofdev->dev); - if (ret) - return ret; + fsl_spi_cpm_free(mpc8xxx_spi); if (mpc8xxx_spi->type == TYPE_FSL) of_fsl_spi_free_chipselects(&ofdev->dev); return 0; @@ -911,7 +902,12 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev) static int plat_mpc8xxx_spi_remove(struct platform_device *pdev) { - return mpc8xxx_spi_remove(&pdev->dev); + struct spi_master *master = platform_get_drvdata(pdev); + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); + + fsl_spi_cpm_free(mpc8xxx_spi); + + return 0; } MODULE_ALIAS("platform:mpc8xxx_spi"); -- cgit v1.2.3 From e9abb4db8d108624c293f06dce06b2978e626a13 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 26 Aug 2015 21:21:55 +0200 Subject: spi: fsl-espi: add runtime PM Add runtime PM and use autosuspend instead of suspending the SPI controller after each transfer. Signed-off-by: Heiner Kallweit Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 71 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index fe54e5788245..db82c872c0f9 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "spi-fsl-lib.h" @@ -85,6 +86,8 @@ struct fsl_espi_transfer { #define SPCOM_TRANLEN(x) ((x) << 0) #define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */ +#define AUTOSUSPEND_TIMEOUT 2000 + static void fsl_espi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); @@ -485,6 +488,8 @@ 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]); @@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi) mpc8xxx_spi_write_reg(®_base->mode, loop_mode); retval = 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; @@ -604,15 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) return ret; } -static int fsl_espi_suspend(struct spi_master *master) +#ifdef CONFIG_PM +static int fsl_espi_runtime_suspend(struct device *dev) { - struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_espi_reg *reg_base; + 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; - mpc8xxx_spi = spi_master_get_devdata(master); - reg_base = mpc8xxx_spi->reg_base; - regval = mpc8xxx_spi_read_reg(®_base->mode); regval &= ~SPMODE_ENABLE; mpc8xxx_spi_write_reg(®_base->mode, regval); @@ -620,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master) return 0; } -static int fsl_espi_resume(struct spi_master *master) +static int fsl_espi_runtime_resume(struct device *dev) { - struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_espi_reg *reg_base; + 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; - mpc8xxx_spi = spi_master_get_devdata(master); - reg_base = mpc8xxx_spi->reg_base; - regval = mpc8xxx_spi_read_reg(®_base->mode); regval |= SPMODE_ENABLE; mpc8xxx_spi_write_reg(®_base->mode, regval); return 0; } +#endif static struct spi_master * fsl_espi_probe(struct device *dev, struct resource *mem, unsigned int irq) @@ -662,8 +669,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev, master->setup = fsl_espi_setup; master->cleanup = fsl_espi_cleanup; master->transfer_one_message = fsl_espi_do_one_msg; - master->prepare_transfer_hardware = fsl_espi_resume; - master->unprepare_transfer_hardware = fsl_espi_suspend; + master->auto_runtime_pm = true; mpc8xxx_spi = spi_master_get_devdata(master); @@ -725,14 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev, mpc8xxx_spi_write_reg(®_base->mode, regval); + pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + ret = devm_spi_register_master(dev, master); if (ret < 0) - goto err_probe; + goto err_pm; dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return master; +err_pm: + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); err_probe: spi_master_put(master); err: @@ -797,6 +816,13 @@ err: return ret; } +static int of_fsl_espi_remove(struct platform_device *dev) +{ + pm_runtime_disable(&dev->dev); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int of_fsl_espi_suspend(struct device *dev) { @@ -809,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev) return ret; } - return fsl_espi_suspend(master); + ret = pm_runtime_force_suspend(dev); + if (ret < 0) + return ret; + + return 0; } static int of_fsl_espi_resume(struct device *dev) @@ -819,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev) struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_espi_reg *reg_base; u32 regval; - int i; + int i, ret; mpc8xxx_spi = spi_master_get_devdata(master); reg_base = mpc8xxx_spi->reg_base; @@ -839,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev) mpc8xxx_spi_write_reg(®_base->mode, regval); + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops espi_pm = { + SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend, + fsl_espi_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) }; @@ -860,6 +896,7 @@ static struct platform_driver fsl_espi_driver = { .pm = &espi_pm, }, .probe = of_fsl_espi_probe, + .remove = of_fsl_espi_remove, }; module_platform_driver(fsl_espi_driver); -- cgit v1.2.3 From 37c5db7938093cada165146ee99bd57c97baf6a3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 18:35:51 +0800 Subject: spi: fsl-(e)spi: Fix checking return value of devm_ioremap_resource devm_ioremap_resource() returns ERR_PTR on error. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 4 ++-- drivers/spi/spi-fsl-spi.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index db82c872c0f9..c27124a5ec8e 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -674,8 +674,8 @@ static struct spi_master * fsl_espi_probe(struct device *dev, mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); - if (!mpc8xxx_spi->reg_base) { - ret = -ENOMEM; + if (IS_ERR(mpc8xxx_spi->reg_base)) { + ret = PTR_ERR(mpc8xxx_spi->reg_base); goto err_probe; } diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 17a9a879dcce..8b290d9d7935 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -633,8 +633,8 @@ static struct spi_master * fsl_spi_probe(struct device *dev, goto err_cpm_init; mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); - if (mpc8xxx_spi->reg_base == NULL) { - ret = -ENOMEM; + if (IS_ERR(mpc8xxx_spi->reg_base)) { + ret = PTR_ERR(mpc8xxx_spi->reg_base); goto err_probe; } -- cgit v1.2.3