1
0
Fork 0

spi: Updates for v4.14

A fairly quiet release for the SPI subsystem:
 
  - Move to using IDR for allocating bus numbers.
  - Modernisation of the ep93xx driver, removing a lot of open coding and
    using the framework more.
  - The tools have been moved to use the standard tools build system and
    an install target added (there will be a fairly trivial conflict
    with tip resulting from the changes in the main tools Makefile).
  - A refactoring of the Qualcomm QUP driver which enables new variants
    to be supported.
  - Explicit support for the Freescale i.MX53 and i.MX6 SPI, Renesas
    R-Car H3 and Rockchip RV1108 controllers.
 
 There's also a trivial add/add conflict in spi.c with the ACPI tree
 adding a header for some Apple support and the IDR code needing a header
 too.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCAAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAlmtgGYTHGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0IwAB/9U/s75RgZN+w/IZneex3gD2+mnNxTV
 SiWWlR66580vbXsh7lgzTtANrDKfYTsYGP3JS7vjhsegBlzcT4M5OMyJZTcCi40a
 JF0edDFnkqNM96LubJVnrIJj4KHL1Zx+FICIXItOSBZh6ECgI92KAfAbfQhLdB10
 BtNdlsQMzcTygLqf2/N6W7u/6yYBnUuaaNeu+j4QsF1pE9L/5kt3lLXxv2DTL3cA
 vncqu/ndxIjCKLpIGjMOrvAlLCKmZdIxX3Y/d1XJSxyG3vJj30kEvxATZ15sKln8
 gXOnmWF2JgBcxEHxzsTGuVZpXXblu7uiicniglP0geC9dMboJnky993j
 =tbQ9
 -----END PGP SIGNATURE-----

Merge tag 'spi-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "A fairly quiet release for the SPI subsystem:

   - Move to using IDR for allocating bus numbers

   - Modernisation of the ep93xx driver, removing a lot of open coding
     and using the framework more

   - The tools have been moved to use the standard tools build system
     and an install target added (there will be a fairly trivial
     conflict with tip resulting from the changes in the main tools
     Makefile)

   - A refactoring of the Qualcomm QUP driver which enables new variants
     to be supported

   - Explicit support for the Freescale i.MX53 and i.MX6 SPI, Renesas
     R-Car H3 and Rockchip RV1108 controllers"

* tag 'spi-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (71 commits)
  spi: spi-falcon: drop check of boot select
  spi: imx: fix use of native chip-selects with devicetree
  spi: pl022: constify amba_id
  spi: imx: fix little-endian build
  spi: omap: Allocate bus number from spi framework
  spi: Kernel coding style fixes
  spi: imx: dynamic burst length adjust for PIO mode
  spi: Pick spi bus number from Linux idr or spi alias
  spi: rockchip: configure CTRLR1 according to size and data frame
  spi: altera: Consolidate TX/RX data register access
  spi: altera: Switch to SPI core transfer queue management
  spi: rockchip: add compatible string for rv1108 spi
  spi: qup: fix 64-bit build warning
  spi: qup: hide warning for uninitialized variable
  spi: spi-ep93xx: use the default master transfer queueing mechanism
  spi: spi-ep93xx: remove private data 'current_msg'
  spi: spi-ep93xx: pass the spi_master pointer around
  spi: spi-ep93xx: absorb the interrupt enable/disable helpers
  spi: spi-ep93xx: add spi master prepare_transfer_hardware()
  spi: spi-ep93xx: use 32-bit read/write for all registers
  ...
hifive-unleashed-5.1
Linus Torvalds 2017-09-05 11:40:38 -07:00
commit b88f55774f
34 changed files with 1163 additions and 865 deletions

View File

@ -9,6 +9,7 @@ Required properties:
- "fsl,imx31-cspi" for SPI compatible with the one integrated on i.MX31 - "fsl,imx31-cspi" for SPI compatible with the one integrated on i.MX31
- "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35 - "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35
- "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51 - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51
- "fsl,imx53-ecspi" for SPI compatible with the one integrated on i.MX53 and later Soc
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : Should contain CSPI/eCSPI interrupt - interrupts : Should contain CSPI/eCSPI interrupt
- cs-gpios : Specifies the gpio pins to be used for chipselects. - cs-gpios : Specifies the gpio pins to be used for chipselects.

View File

@ -6,6 +6,7 @@ Required properties:
"renesas,msiof-r8a7792" (R-Car V2H) "renesas,msiof-r8a7792" (R-Car V2H)
"renesas,msiof-r8a7793" (R-Car M2-N) "renesas,msiof-r8a7793" (R-Car M2-N)
"renesas,msiof-r8a7794" (R-Car E2) "renesas,msiof-r8a7794" (R-Car E2)
"renesas,msiof-r8a7795" (R-Car H3)
"renesas,msiof-r8a7796" (R-Car M3-W) "renesas,msiof-r8a7796" (R-Car M3-W)
"renesas,msiof-sh73a0" (SH-Mobile AG5) "renesas,msiof-sh73a0" (SH-Mobile AG5)
"renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device) "renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device)

View File

@ -6,6 +6,7 @@ and display controllers using the SPI communication interface.
Required Properties: Required Properties:
- compatible: should be one of the following. - compatible: should be one of the following.
"rockchip,rv1108-spi" for rv1108 SoCs.
"rockchip,rk3036-spi" for rk3036 SoCS. "rockchip,rk3036-spi" for rk3036 SoCS.
"rockchip,rk3066-spi" for rk3066 SoCs. "rockchip,rk3066-spi" for rk3066 SoCs.
"rockchip,rk3188-spi" for rk3188 SoCs. "rockchip,rk3188-spi" for rk3188 SoCs.

View File

@ -55,7 +55,6 @@ comment "SPI Master Controller Drivers"
config SPI_ALTERA config SPI_ALTERA
tristate "Altera SPI Controller" tristate "Altera SPI Controller"
select SPI_BITBANG
help help
This is the driver for the Altera SPI Controller. This is the driver for the Altera SPI Controller.
@ -518,8 +517,8 @@ config SPI_PPC4xx
config SPI_PXA2XX config SPI_PXA2XX
tristate "PXA2xx SSP SPI master" tristate "PXA2xx SSP SPI master"
depends on (ARCH_PXA || PCI || ACPI) depends on (ARCH_PXA || ARCH_MMP || PCI || ACPI)
select PXA_SSP if ARCH_PXA select PXA_SSP if ARCH_PXA || ARCH_MMP
help help
This enables using a PXA2xx or Sodaville SSP port as a SPI master This enables using a PXA2xx or Sodaville SSP port as a SPI master
controller. The driver can be configured to use any SSP port and controller. The driver can be configured to use any SSP port and

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -576,10 +576,10 @@ static int cdns_spi_probe(struct platform_device *pdev)
goto clk_dis_apb; goto clk_dis_apb;
} }
pm_runtime_enable(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
if (ret < 0) if (ret < 0)
@ -704,7 +704,9 @@ static int __maybe_unused cdns_spi_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct spi_master *master = platform_get_drvdata(pdev); struct spi_master *master = platform_get_drvdata(pdev);
struct cdns_spi *xspi = spi_master_get_devdata(master);
cdns_spi_init_hw(xspi);
return spi_master_resume(master); return spi_master_resume(master);
} }

View File

@ -70,12 +70,9 @@
/** /**
* struct ep93xx_spi - EP93xx SPI controller structure * struct ep93xx_spi - EP93xx SPI controller structure
* @pdev: pointer to platform device
* @clk: clock for the controller * @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers * @mmio: pointer to ioremap()'d registers
* @sspdr_phys: physical address of the SSPDR register * @sspdr_phys: physical address of the SSPDR register
* @wait: wait here until given transfer is completed
* @current_msg: message that is currently processed (or %NULL if none)
* @tx: current byte in transfer to transmit * @tx: current byte in transfer to transmit
* @rx: current byte in transfer to receive * @rx: current byte in transfer to receive
* @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one * @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one
@ -90,12 +87,9 @@
* the client * the client
*/ */
struct ep93xx_spi { struct ep93xx_spi {
const struct platform_device *pdev;
struct clk *clk; struct clk *clk;
void __iomem *regs_base; void __iomem *mmio;
unsigned long sspdr_phys; unsigned long sspdr_phys;
struct completion wait;
struct spi_message *current_msg;
size_t tx; size_t tx;
size_t rx; size_t rx;
size_t fifo_level; size_t fifo_level;
@ -111,91 +105,23 @@ struct ep93xx_spi {
/* converts bits per word to CR0.DSS value */ /* converts bits per word to CR0.DSS value */
#define bits_per_word_to_dss(bpw) ((bpw) - 1) #define bits_per_word_to_dss(bpw) ((bpw) - 1)
static void ep93xx_spi_write_u8(const struct ep93xx_spi *espi,
u16 reg, u8 value)
{
writeb(value, espi->regs_base + reg);
}
static u8 ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
{
return readb(spi->regs_base + reg);
}
static void ep93xx_spi_write_u16(const struct ep93xx_spi *espi,
u16 reg, u16 value)
{
writew(value, espi->regs_base + reg);
}
static u16 ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
{
return readw(spi->regs_base + reg);
}
static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
{
u8 regval;
int err;
err = clk_enable(espi->clk);
if (err)
return err;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval |= SSPCR1_SSE;
ep93xx_spi_write_u8(espi, SSPCR1, regval);
return 0;
}
static void ep93xx_spi_disable(const struct ep93xx_spi *espi)
{
u8 regval;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval &= ~SSPCR1_SSE;
ep93xx_spi_write_u8(espi, SSPCR1, regval);
clk_disable(espi->clk);
}
static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi)
{
u8 regval;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
ep93xx_spi_write_u8(espi, SSPCR1, regval);
}
static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
{
u8 regval;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
ep93xx_spi_write_u8(espi, SSPCR1, regval);
}
/** /**
* ep93xx_spi_calc_divisors() - calculates SPI clock divisors * ep93xx_spi_calc_divisors() - calculates SPI clock divisors
* @espi: ep93xx SPI controller struct * @master: SPI master
* @rate: desired SPI output clock rate * @rate: desired SPI output clock rate
* @div_cpsr: pointer to return the cpsr (pre-scaler) divider * @div_cpsr: pointer to return the cpsr (pre-scaler) divider
* @div_scr: pointer to return the scr divider * @div_scr: pointer to return the scr divider
*/ */
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, static int ep93xx_spi_calc_divisors(struct spi_master *master,
u32 rate, u8 *div_cpsr, u8 *div_scr) u32 rate, u8 *div_cpsr, u8 *div_scr)
{ {
struct spi_master *master = platform_get_drvdata(espi->pdev); struct ep93xx_spi *espi = spi_master_get_devdata(master);
unsigned long spi_clk_rate = clk_get_rate(espi->clk); unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr; int cpsr, scr;
/* /*
* Make sure that max value is between values supported by the * Make sure that max value is between values supported by the
* controller. Note that minimum value is already checked in * controller.
* ep93xx_spi_transfer_one_message().
*/ */
rate = clamp(rate, master->min_speed_hz, master->max_speed_hz); rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
@ -220,26 +146,18 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
return -EINVAL; return -EINVAL;
} }
static void ep93xx_spi_cs_control(struct spi_device *spi, bool enable) static int ep93xx_spi_chip_setup(struct spi_master *master,
{
if (spi->mode & SPI_CS_HIGH)
enable = !enable;
if (gpio_is_valid(spi->cs_gpio))
gpio_set_value(spi->cs_gpio, !enable);
}
static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct ep93xx_spi *espi = spi_master_get_devdata(master);
u8 dss = bits_per_word_to_dss(xfer->bits_per_word); u8 dss = bits_per_word_to_dss(xfer->bits_per_word);
u8 div_cpsr = 0; u8 div_cpsr = 0;
u8 div_scr = 0; u8 div_scr = 0;
u16 cr0; u16 cr0;
int err; int err;
err = ep93xx_spi_calc_divisors(espi, xfer->speed_hz, err = ep93xx_spi_calc_divisors(master, xfer->speed_hz,
&div_cpsr, &div_scr); &div_cpsr, &div_scr);
if (err) if (err)
return err; return err;
@ -248,51 +166,49 @@ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
cr0 |= (spi->mode & (SPI_CPHA | SPI_CPOL)) << SSPCR0_MODE_SHIFT; cr0 |= (spi->mode & (SPI_CPHA | SPI_CPOL)) << SSPCR0_MODE_SHIFT;
cr0 |= dss; cr0 |= dss;
dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", dev_dbg(&master->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
spi->mode, div_cpsr, div_scr, dss); spi->mode, div_cpsr, div_scr, dss);
dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0); dev_dbg(&master->dev, "setup: cr0 %#x\n", cr0);
ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr); writel(div_cpsr, espi->mmio + SSPCPSR);
ep93xx_spi_write_u16(espi, SSPCR0, cr0); writel(cr0, espi->mmio + SSPCR0);
return 0; return 0;
} }
static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) static void ep93xx_do_write(struct spi_master *master)
{ {
if (t->bits_per_word > 8) { struct ep93xx_spi *espi = spi_master_get_devdata(master);
u16 tx_val = 0; struct spi_transfer *xfer = master->cur_msg->state;
u32 val = 0;
if (t->tx_buf) if (xfer->bits_per_word > 8) {
tx_val = ((u16 *)t->tx_buf)[espi->tx]; if (xfer->tx_buf)
ep93xx_spi_write_u16(espi, SSPDR, tx_val); val = ((u16 *)xfer->tx_buf)[espi->tx];
espi->tx += sizeof(tx_val); espi->tx += 2;
} else { } else {
u8 tx_val = 0; if (xfer->tx_buf)
val = ((u8 *)xfer->tx_buf)[espi->tx];
if (t->tx_buf) espi->tx += 1;
tx_val = ((u8 *)t->tx_buf)[espi->tx];
ep93xx_spi_write_u8(espi, SSPDR, tx_val);
espi->tx += sizeof(tx_val);
} }
writel(val, espi->mmio + SSPDR);
} }
static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) static void ep93xx_do_read(struct spi_master *master)
{ {
if (t->bits_per_word > 8) { struct ep93xx_spi *espi = spi_master_get_devdata(master);
u16 rx_val; struct spi_transfer *xfer = master->cur_msg->state;
u32 val;
rx_val = ep93xx_spi_read_u16(espi, SSPDR); val = readl(espi->mmio + SSPDR);
if (t->rx_buf) if (xfer->bits_per_word > 8) {
((u16 *)t->rx_buf)[espi->rx] = rx_val; if (xfer->rx_buf)
espi->rx += sizeof(rx_val); ((u16 *)xfer->rx_buf)[espi->rx] = val;
espi->rx += 2;
} else { } else {
u8 rx_val; if (xfer->rx_buf)
((u8 *)xfer->rx_buf)[espi->rx] = val;
rx_val = ep93xx_spi_read_u8(espi, SSPDR); espi->rx += 1;
if (t->rx_buf)
((u8 *)t->rx_buf)[espi->rx] = rx_val;
espi->rx += sizeof(rx_val);
} }
} }
@ -307,44 +223,32 @@ static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
* When this function is finished, RX FIFO should be empty and TX FIFO should be * When this function is finished, RX FIFO should be empty and TX FIFO should be
* full. * full.
*/ */
static int ep93xx_spi_read_write(struct ep93xx_spi *espi) static int ep93xx_spi_read_write(struct spi_master *master)
{ {
struct spi_message *msg = espi->current_msg; struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct spi_transfer *t = msg->state; struct spi_transfer *xfer = master->cur_msg->state;
/* read as long as RX FIFO has frames in it */ /* read as long as RX FIFO has frames in it */
while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) { while ((readl(espi->mmio + SSPSR) & SSPSR_RNE)) {
ep93xx_do_read(espi, t); ep93xx_do_read(master);
espi->fifo_level--; espi->fifo_level--;
} }
/* write as long as TX FIFO has room */ /* write as long as TX FIFO has room */
while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) { while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < xfer->len) {
ep93xx_do_write(espi, t); ep93xx_do_write(master);
espi->fifo_level++; espi->fifo_level++;
} }
if (espi->rx == t->len) if (espi->rx == xfer->len)
return 0; return 0;
return -EINPROGRESS; return -EINPROGRESS;
} }
static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi)
{
/*
* Now everything is set up for the current transfer. We prime the TX
* FIFO, enable interrupts, and wait for the transfer to complete.
*/
if (ep93xx_spi_read_write(espi)) {
ep93xx_spi_enable_interrupts(espi);
wait_for_completion(&espi->wait);
}
}
/** /**
* ep93xx_spi_dma_prepare() - prepares a DMA transfer * ep93xx_spi_dma_prepare() - prepares a DMA transfer
* @espi: ep93xx SPI controller struct * @master: SPI master
* @dir: DMA transfer direction * @dir: DMA transfer direction
* *
* Function configures the DMA, maps the buffer and prepares the DMA * Function configures the DMA, maps the buffer and prepares the DMA
@ -352,9 +256,11 @@ static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi)
* in case of failure. * in case of failure.
*/ */
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) ep93xx_spi_dma_prepare(struct spi_master *master,
enum dma_transfer_direction dir)
{ {
struct spi_transfer *t = espi->current_msg->state; struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct spi_transfer *xfer = master->cur_msg->state;
struct dma_async_tx_descriptor *txd; struct dma_async_tx_descriptor *txd;
enum dma_slave_buswidth buswidth; enum dma_slave_buswidth buswidth;
struct dma_slave_config conf; struct dma_slave_config conf;
@ -362,10 +268,10 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
struct sg_table *sgt; struct sg_table *sgt;
struct dma_chan *chan; struct dma_chan *chan;
const void *buf, *pbuf; const void *buf, *pbuf;
size_t len = t->len; size_t len = xfer->len;
int i, ret, nents; int i, ret, nents;
if (t->bits_per_word > 8) if (xfer->bits_per_word > 8)
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
else else
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
@ -375,14 +281,14 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
if (dir == DMA_DEV_TO_MEM) { if (dir == DMA_DEV_TO_MEM) {
chan = espi->dma_rx; chan = espi->dma_rx;
buf = t->rx_buf; buf = xfer->rx_buf;
sgt = &espi->rx_sgt; sgt = &espi->rx_sgt;
conf.src_addr = espi->sspdr_phys; conf.src_addr = espi->sspdr_phys;
conf.src_addr_width = buswidth; conf.src_addr_width = buswidth;
} else { } else {
chan = espi->dma_tx; chan = espi->dma_tx;
buf = t->tx_buf; buf = xfer->tx_buf;
sgt = &espi->tx_sgt; sgt = &espi->tx_sgt;
conf.dst_addr = espi->sspdr_phys; conf.dst_addr = espi->sspdr_phys;
@ -429,7 +335,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
} }
if (WARN_ON(len)) { if (WARN_ON(len)) {
dev_warn(&espi->pdev->dev, "len = %zu expected 0!\n", len); dev_warn(&master->dev, "len = %zu expected 0!\n", len);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
@ -447,15 +353,16 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
/** /**
* ep93xx_spi_dma_finish() - finishes with a DMA transfer * ep93xx_spi_dma_finish() - finishes with a DMA transfer
* @espi: ep93xx SPI controller struct * @master: SPI master
* @dir: DMA transfer direction * @dir: DMA transfer direction
* *
* Function finishes with the DMA transfer. After this, the DMA buffer is * Function finishes with the DMA transfer. After this, the DMA buffer is
* unmapped. * unmapped.
*/ */
static void ep93xx_spi_dma_finish(struct ep93xx_spi *espi, static void ep93xx_spi_dma_finish(struct spi_master *master,
enum dma_transfer_direction dir) enum dma_transfer_direction dir)
{ {
struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct dma_chan *chan; struct dma_chan *chan;
struct sg_table *sgt; struct sg_table *sgt;
@ -472,223 +379,69 @@ static void ep93xx_spi_dma_finish(struct ep93xx_spi *espi,
static void ep93xx_spi_dma_callback(void *callback_param) static void ep93xx_spi_dma_callback(void *callback_param)
{ {
complete(callback_param); struct spi_master *master = callback_param;
ep93xx_spi_dma_finish(master, DMA_MEM_TO_DEV);
ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM);
spi_finalize_current_transfer(master);
} }
static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi) static int ep93xx_spi_dma_transfer(struct spi_master *master)
{ {
struct spi_message *msg = espi->current_msg; struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct dma_async_tx_descriptor *rxd, *txd; struct dma_async_tx_descriptor *rxd, *txd;
rxd = ep93xx_spi_dma_prepare(espi, DMA_DEV_TO_MEM); rxd = ep93xx_spi_dma_prepare(master, DMA_DEV_TO_MEM);
if (IS_ERR(rxd)) { if (IS_ERR(rxd)) {
dev_err(&espi->pdev->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
msg->status = PTR_ERR(rxd); return PTR_ERR(rxd);
return;
} }
txd = ep93xx_spi_dma_prepare(espi, DMA_MEM_TO_DEV); txd = ep93xx_spi_dma_prepare(master, DMA_MEM_TO_DEV);
if (IS_ERR(txd)) { if (IS_ERR(txd)) {
ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM); ep93xx_spi_dma_finish(master, DMA_DEV_TO_MEM);
dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
msg->status = PTR_ERR(txd); return PTR_ERR(txd);
return;
} }
/* We are ready when RX is done */ /* We are ready when RX is done */
rxd->callback = ep93xx_spi_dma_callback; rxd->callback = ep93xx_spi_dma_callback;
rxd->callback_param = &espi->wait; rxd->callback_param = master;
/* Now submit both descriptors and wait while they finish */ /* Now submit both descriptors and start DMA */
dmaengine_submit(rxd); dmaengine_submit(rxd);
dmaengine_submit(txd); dmaengine_submit(txd);
dma_async_issue_pending(espi->dma_rx); dma_async_issue_pending(espi->dma_rx);
dma_async_issue_pending(espi->dma_tx); dma_async_issue_pending(espi->dma_tx);
wait_for_completion(&espi->wait); /* signal that we need to wait for completion */
return 1;
ep93xx_spi_dma_finish(espi, DMA_MEM_TO_DEV);
ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM);
}
/**
* ep93xx_spi_process_transfer() - processes one SPI transfer
* @espi: ep93xx SPI controller struct
* @msg: current message
* @t: transfer to process
*
* This function processes one SPI transfer given in @t. Function waits until
* transfer is complete (may sleep) and updates @msg->status based on whether
* transfer was successfully processed or not.
*/
static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
struct spi_message *msg,
struct spi_transfer *t)
{
int err;
msg->state = t;
err = ep93xx_spi_chip_setup(espi, msg->spi, t);
if (err) {
dev_err(&espi->pdev->dev,
"failed to setup chip for transfer\n");
msg->status = err;
return;
}
espi->rx = 0;
espi->tx = 0;
/*
* There is no point of setting up DMA for the transfers which will
* fit into the FIFO and can be transferred with a single interrupt.
* So in these cases we will be using PIO and don't bother for DMA.
*/
if (espi->dma_rx && t->len > SPI_FIFO_SIZE)
ep93xx_spi_dma_transfer(espi);
else
ep93xx_spi_pio_transfer(espi);
/*
* In case of error during transmit, we bail out from processing
* the message.
*/
if (msg->status)
return;
msg->actual_length += t->len;
/*
* After this transfer is finished, perform any possible
* post-transfer actions requested by the protocol driver.
*/
if (t->delay_usecs) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(usecs_to_jiffies(t->delay_usecs));
}
if (t->cs_change) {
if (!list_is_last(&t->transfer_list, &msg->transfers)) {
/*
* In case protocol driver is asking us to drop the
* chipselect briefly, we let the scheduler to handle
* any "delay" here.
*/
ep93xx_spi_cs_control(msg->spi, false);
cond_resched();
ep93xx_spi_cs_control(msg->spi, true);
}
}
}
/*
* ep93xx_spi_process_message() - process one SPI message
* @espi: ep93xx SPI controller struct
* @msg: message to process
*
* This function processes a single SPI message. We go through all transfers in
* the message and pass them to ep93xx_spi_process_transfer(). Chipselect is
* asserted during the whole message (unless per transfer cs_change is set).
*
* @msg->status contains %0 in case of success or negative error code in case of
* failure.
*/
static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
struct spi_message *msg)
{
unsigned long timeout;
struct spi_transfer *t;
int err;
/*
* Enable the SPI controller and its clock.
*/
err = ep93xx_spi_enable(espi);
if (err) {
dev_err(&espi->pdev->dev, "failed to enable SPI controller\n");
msg->status = err;
return;
}
/*
* Just to be sure: flush any data from RX FIFO.
*/
timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
while (ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_RNE) {
if (time_after(jiffies, timeout)) {
dev_warn(&espi->pdev->dev,
"timeout while flushing RX FIFO\n");
msg->status = -ETIMEDOUT;
return;
}
ep93xx_spi_read_u16(espi, SSPDR);
}
/*
* We explicitly handle FIFO level. This way we don't have to check TX
* FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns.
*/
espi->fifo_level = 0;
/*
* Assert the chipselect.
*/
ep93xx_spi_cs_control(msg->spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {
ep93xx_spi_process_transfer(espi, msg, t);
if (msg->status)
break;
}
/*
* Now the whole message is transferred (or failed for some reason). We
* deselect the device and disable the SPI controller.
*/
ep93xx_spi_cs_control(msg->spi, false);
ep93xx_spi_disable(espi);
}
static int ep93xx_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
msg->state = NULL;
msg->status = 0;
msg->actual_length = 0;
espi->current_msg = msg;
ep93xx_spi_process_message(espi, msg);
espi->current_msg = NULL;
spi_finalize_current_message(master);
return 0;
} }
static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
{ {
struct ep93xx_spi *espi = dev_id; struct spi_master *master = dev_id;
u8 irq_status = ep93xx_spi_read_u8(espi, SSPIIR); struct ep93xx_spi *espi = spi_master_get_devdata(master);
u32 val;
/* /*
* If we got ROR (receive overrun) interrupt we know that something is * If we got ROR (receive overrun) interrupt we know that something is
* wrong. Just abort the message. * wrong. Just abort the message.
*/ */
if (unlikely(irq_status & SSPIIR_RORIS)) { if (readl(espi->mmio + SSPIIR) & SSPIIR_RORIS) {
/* clear the overrun interrupt */ /* clear the overrun interrupt */
ep93xx_spi_write_u8(espi, SSPICR, 0); writel(0, espi->mmio + SSPICR);
dev_warn(&espi->pdev->dev, dev_warn(&master->dev,
"receive overrun, aborting the message\n"); "receive overrun, aborting the message\n");
espi->current_msg->status = -EIO; master->cur_msg->status = -EIO;
} else { } else {
/* /*
* Interrupt is either RX (RIS) or TX (TIS). For both cases we * Interrupt is either RX (RIS) or TX (TIS). For both cases we
* simply execute next data transfer. * simply execute next data transfer.
*/ */
if (ep93xx_spi_read_write(espi)) { if (ep93xx_spi_read_write(master)) {
/* /*
* In normal case, there still is some processing left * In normal case, there still is some processing left
* for current transfer. Let's wait for the next * for current transfer. Let's wait for the next
@ -703,11 +456,111 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
* any case we disable interrupts and notify the worker to handle * any case we disable interrupts and notify the worker to handle
* any post-processing of the message. * any post-processing of the message.
*/ */
ep93xx_spi_disable_interrupts(espi); val = readl(espi->mmio + SSPCR1);
complete(&espi->wait); val &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
writel(val, espi->mmio + SSPCR1);
spi_finalize_current_transfer(master);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int ep93xx_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
u32 val;
int ret;
ret = ep93xx_spi_chip_setup(master, spi, xfer);
if (ret) {
dev_err(&master->dev, "failed to setup chip for transfer\n");
return ret;
}
master->cur_msg->state = xfer;
espi->rx = 0;
espi->tx = 0;
/*
* There is no point of setting up DMA for the transfers which will
* fit into the FIFO and can be transferred with a single interrupt.
* So in these cases we will be using PIO and don't bother for DMA.
*/
if (espi->dma_rx && xfer->len > SPI_FIFO_SIZE)
return ep93xx_spi_dma_transfer(master);
/* Using PIO so prime the TX FIFO and enable interrupts */
ep93xx_spi_read_write(master);
val = readl(espi->mmio + SSPCR1);
val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
writel(val, espi->mmio + SSPCR1);
/* signal that we need to wait for completion */
return 1;
}
static int ep93xx_spi_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
unsigned long timeout;
/*
* Just to be sure: flush any data from RX FIFO.
*/
timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
while (readl(espi->mmio + SSPSR) & SSPSR_RNE) {
if (time_after(jiffies, timeout)) {
dev_warn(&master->dev,
"timeout while flushing RX FIFO\n");
return -ETIMEDOUT;
}
readl(espi->mmio + SSPDR);
}
/*
* We explicitly handle FIFO level. This way we don't have to check TX
* FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns.
*/
espi->fifo_level = 0;
return 0;
}
static int ep93xx_spi_prepare_hardware(struct spi_master *master)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
u32 val;
int ret;
ret = clk_enable(espi->clk);
if (ret)
return ret;
val = readl(espi->mmio + SSPCR1);
val |= SSPCR1_SSE;
writel(val, espi->mmio + SSPCR1);
return 0;
}
static int ep93xx_spi_unprepare_hardware(struct spi_master *master)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
u32 val;
val = readl(espi->mmio + SSPCR1);
val &= ~SSPCR1_SSE;
writel(val, espi->mmio + SSPCR1);
clk_disable(espi->clk);
return 0;
}
static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param) static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param)
{ {
if (ep93xx_dma_chan_is_m2p(chan)) if (ep93xx_dma_chan_is_m2p(chan))
@ -809,7 +662,10 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
if (!master) if (!master)
return -ENOMEM; return -ENOMEM;
master->transfer_one_message = ep93xx_spi_transfer_one_message; master->prepare_transfer_hardware = ep93xx_spi_prepare_hardware;
master->unprepare_transfer_hardware = ep93xx_spi_unprepare_hardware;
master->prepare_message = ep93xx_spi_prepare_message;
master->transfer_one = ep93xx_spi_transfer_one;
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
@ -850,26 +706,23 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
goto fail_release_master; goto fail_release_master;
} }
init_completion(&espi->wait);
/* /*
* Calculate maximum and minimum supported clock rates * Calculate maximum and minimum supported clock rates
* for the controller. * for the controller.
*/ */
master->max_speed_hz = clk_get_rate(espi->clk) / 2; master->max_speed_hz = clk_get_rate(espi->clk) / 2;
master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256); master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
espi->sspdr_phys = res->start + SSPDR; espi->sspdr_phys = res->start + SSPDR;
espi->regs_base = devm_ioremap_resource(&pdev->dev, res); espi->mmio = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(espi->regs_base)) { if (IS_ERR(espi->mmio)) {
error = PTR_ERR(espi->regs_base); error = PTR_ERR(espi->mmio);
goto fail_release_master; goto fail_release_master;
} }
error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt, error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
0, "ep93xx-spi", espi); 0, "ep93xx-spi", master);
if (error) { if (error) {
dev_err(&pdev->dev, "failed to request irq\n"); dev_err(&pdev->dev, "failed to request irq\n");
goto fail_release_master; goto fail_release_master;
@ -879,7 +732,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n"); dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n");
/* make sure that the hardware is disabled */ /* make sure that the hardware is disabled */
ep93xx_spi_write_u8(espi, SSPCR1, 0); writel(0, espi->mmio + SSPCR1);
error = devm_spi_register_master(&pdev->dev, master); error = devm_spi_register_master(&pdev->dev, master);
if (error) { if (error) {

View File

@ -395,11 +395,6 @@ static int falcon_sflash_probe(struct platform_device *pdev)
struct spi_master *master; struct spi_master *master;
int ret; int ret;
if (ltq_boot_select() != BS_SPI) {
dev_err(&pdev->dev, "invalid bootstrap options\n");
return -ENODEV;
}
master = spi_alloc_master(&pdev->dev, sizeof(*priv)); master = spi_alloc_master(&pdev->dev, sizeof(*priv));
if (!master) if (!master)
return -ENOMEM; return -ENOMEM;

View File

@ -56,6 +56,7 @@
/* The maximum bytes that a sdma BD can transfer.*/ /* The maximum bytes that a sdma BD can transfer.*/
#define MAX_SDMA_BD_BYTES (1 << 15) #define MAX_SDMA_BD_BYTES (1 << 15)
#define MX51_ECSPI_CTRL_MAX_BURST 512
enum spi_imx_devtype { enum spi_imx_devtype {
IMX1_CSPI, IMX1_CSPI,
@ -63,7 +64,8 @@ enum spi_imx_devtype {
IMX27_CSPI, IMX27_CSPI,
IMX31_CSPI, IMX31_CSPI,
IMX35_CSPI, /* CSPI on all i.mx except above */ IMX35_CSPI, /* CSPI on all i.mx except above */
IMX51_ECSPI, /* ECSPI on i.mx51 and later */ IMX51_ECSPI, /* ECSPI on i.mx51 */
IMX53_ECSPI, /* ECSPI on i.mx53 and later */
}; };
struct spi_imx_data; struct spi_imx_data;
@ -74,6 +76,9 @@ struct spi_imx_devtype_data {
void (*trigger)(struct spi_imx_data *); void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *); int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *);
bool has_dmamode;
unsigned int fifo_size;
bool dynamic_burst;
enum spi_imx_devtype devtype; enum spi_imx_devtype devtype;
}; };
@ -94,12 +99,14 @@ struct spi_imx_data {
unsigned int bits_per_word; unsigned int bits_per_word;
unsigned int spi_drctl; unsigned int spi_drctl;
unsigned int count; unsigned int count, remainder;
void (*tx)(struct spi_imx_data *); void (*tx)(struct spi_imx_data *);
void (*rx)(struct spi_imx_data *); void (*rx)(struct spi_imx_data *);
void *rx_buf; void *rx_buf;
const void *tx_buf; const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */ unsigned int txfifo; /* number of words pushed in tx FIFO */
unsigned int dynamic_burst, read_u32;
unsigned int word_mask;
/* DMA */ /* DMA */
bool usedma; bool usedma;
@ -125,9 +132,9 @@ static inline int is_imx51_ecspi(struct spi_imx_data *d)
return d->devtype_data->devtype == IMX51_ECSPI; return d->devtype_data->devtype == IMX51_ECSPI;
} }
static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d) static inline int is_imx53_ecspi(struct spi_imx_data *d)
{ {
return is_imx51_ecspi(d) ? 64 : 8; return d->devtype_data->devtype == IMX53_ECSPI;
} }
#define MXC_SPI_BUF_RX(type) \ #define MXC_SPI_BUF_RX(type) \
@ -219,7 +226,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4) if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
return false; return false;
for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) { for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
if (!(transfer->len % (i * bytes_per_word))) if (!(transfer->len % (i * bytes_per_word)))
break; break;
} }
@ -228,6 +235,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
return false; return false;
spi_imx->wml = i; spi_imx->wml = i;
spi_imx->dynamic_burst = 0;
return true; return true;
} }
@ -242,6 +250,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12 #define MX51_ECSPI_CTRL_PREDIV_OFFSET 12
#define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18) #define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18)
#define MX51_ECSPI_CTRL_BL_OFFSET 20 #define MX51_ECSPI_CTRL_BL_OFFSET 20
#define MX51_ECSPI_CTRL_BL_MASK (0xfff << 20)
#define MX51_ECSPI_CONFIG 0x0c #define MX51_ECSPI_CONFIG 0x0c
#define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0)) #define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0))
@ -269,6 +278,106 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
#define MX51_ECSPI_TESTREG 0x20 #define MX51_ECSPI_TESTREG 0x20
#define MX51_ECSPI_TESTREG_LBC BIT(31) #define MX51_ECSPI_TESTREG_LBC BIT(31)
static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)
{
unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);
#ifdef __LITTLE_ENDIAN
unsigned int bytes_per_word;
#endif
if (spi_imx->rx_buf) {
#ifdef __LITTLE_ENDIAN
bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
if (bytes_per_word == 1)
val = cpu_to_be32(val);
else if (bytes_per_word == 2)
val = (val << 16) | (val >> 16);
#endif
val &= spi_imx->word_mask;
*(u32 *)spi_imx->rx_buf = val;
spi_imx->rx_buf += sizeof(u32);
}
}
static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
{
unsigned int bytes_per_word;
bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
if (spi_imx->read_u32) {
spi_imx_buf_rx_swap_u32(spi_imx);
return;
}
if (bytes_per_word == 1)
spi_imx_buf_rx_u8(spi_imx);
else if (bytes_per_word == 2)
spi_imx_buf_rx_u16(spi_imx);
}
static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
{
u32 val = 0;
#ifdef __LITTLE_ENDIAN
unsigned int bytes_per_word;
#endif
if (spi_imx->tx_buf) {
val = *(u32 *)spi_imx->tx_buf;
val &= spi_imx->word_mask;
spi_imx->tx_buf += sizeof(u32);
}
spi_imx->count -= sizeof(u32);
#ifdef __LITTLE_ENDIAN
bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
if (bytes_per_word == 1)
val = cpu_to_be32(val);
else if (bytes_per_word == 2)
val = (val << 16) | (val >> 16);
#endif
writel(val, spi_imx->base + MXC_CSPITXDATA);
}
static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
{
u32 ctrl, val;
unsigned int bytes_per_word;
if (spi_imx->count == spi_imx->remainder) {
ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) {
spi_imx->remainder = spi_imx->count %
MX51_ECSPI_CTRL_MAX_BURST;
val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1;
} else if (spi_imx->count >= sizeof(u32)) {
spi_imx->remainder = spi_imx->count % sizeof(u32);
val = (spi_imx->count - spi_imx->remainder) * 8 - 1;
} else {
spi_imx->remainder = 0;
val = spi_imx->bits_per_word - 1;
spi_imx->read_u32 = 0;
}
ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET);
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
}
if (spi_imx->count >= sizeof(u32)) {
spi_imx_buf_tx_swap_u32(spi_imx);
return;
}
bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
if (bytes_per_word == 1)
spi_imx_buf_tx_u8(spi_imx);
else if (bytes_per_word == 2)
spi_imx_buf_tx_u16(spi_imx);
}
/* MX51 eCSPI */ /* MX51 eCSPI */
static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx, static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
unsigned int fspi, unsigned int *fres) unsigned int fspi, unsigned int *fres)
@ -513,8 +622,8 @@ static int mx31_config(struct spi_device *spi)
reg |= MX31_CSPICTRL_POL; reg |= MX31_CSPICTRL_POL;
if (spi->mode & SPI_CS_HIGH) if (spi->mode & SPI_CS_HIGH)
reg |= MX31_CSPICTRL_SSPOL; reg |= MX31_CSPICTRL_SSPOL;
if (spi->cs_gpio < 0) if (!gpio_is_valid(spi->cs_gpio))
reg |= (spi->cs_gpio + 32) << reg |= (spi->chip_select) <<
(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT : (is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT :
MX31_CSPICTRL_CS_SHIFT); MX31_CSPICTRL_CS_SHIFT);
@ -605,8 +714,8 @@ static int mx21_config(struct spi_device *spi)
reg |= MX21_CSPICTRL_POL; reg |= MX21_CSPICTRL_POL;
if (spi->mode & SPI_CS_HIGH) if (spi->mode & SPI_CS_HIGH)
reg |= MX21_CSPICTRL_SSPOL; reg |= MX21_CSPICTRL_SSPOL;
if (spi->cs_gpio < 0) if (!gpio_is_valid(spi->cs_gpio))
reg |= (spi->cs_gpio + 32) << MX21_CSPICTRL_CS_SHIFT; reg |= spi->chip_select << MX21_CSPICTRL_CS_SHIFT;
writel(reg, spi_imx->base + MXC_CSPICTRL); writel(reg, spi_imx->base + MXC_CSPICTRL);
@ -693,6 +802,9 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
.trigger = mx1_trigger, .trigger = mx1_trigger,
.rx_available = mx1_rx_available, .rx_available = mx1_rx_available,
.reset = mx1_reset, .reset = mx1_reset,
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.devtype = IMX1_CSPI, .devtype = IMX1_CSPI,
}; };
@ -702,6 +814,9 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
.trigger = mx21_trigger, .trigger = mx21_trigger,
.rx_available = mx21_rx_available, .rx_available = mx21_rx_available,
.reset = mx21_reset, .reset = mx21_reset,
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.devtype = IMX21_CSPI, .devtype = IMX21_CSPI,
}; };
@ -712,6 +827,9 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
.trigger = mx21_trigger, .trigger = mx21_trigger,
.rx_available = mx21_rx_available, .rx_available = mx21_rx_available,
.reset = mx21_reset, .reset = mx21_reset,
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.devtype = IMX27_CSPI, .devtype = IMX27_CSPI,
}; };
@ -721,6 +839,9 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
.trigger = mx31_trigger, .trigger = mx31_trigger,
.rx_available = mx31_rx_available, .rx_available = mx31_rx_available,
.reset = mx31_reset, .reset = mx31_reset,
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
.devtype = IMX31_CSPI, .devtype = IMX31_CSPI,
}; };
@ -731,6 +852,9 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
.trigger = mx31_trigger, .trigger = mx31_trigger,
.rx_available = mx31_rx_available, .rx_available = mx31_rx_available,
.reset = mx31_reset, .reset = mx31_reset,
.fifo_size = 8,
.has_dmamode = true,
.dynamic_burst = false,
.devtype = IMX35_CSPI, .devtype = IMX35_CSPI,
}; };
@ -740,9 +864,23 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.trigger = mx51_ecspi_trigger, .trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available, .rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset, .reset = mx51_ecspi_reset,
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
.devtype = IMX51_ECSPI, .devtype = IMX51_ECSPI,
}; };
static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
.intctrl = mx51_ecspi_intctrl,
.config = mx51_ecspi_config,
.trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset,
.fifo_size = 64,
.has_dmamode = true,
.devtype = IMX53_ECSPI,
};
static const struct platform_device_id spi_imx_devtype[] = { static const struct platform_device_id spi_imx_devtype[] = {
{ {
.name = "imx1-cspi", .name = "imx1-cspi",
@ -762,6 +900,9 @@ static const struct platform_device_id spi_imx_devtype[] = {
}, { }, {
.name = "imx51-ecspi", .name = "imx51-ecspi",
.driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data, .driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data,
}, {
.name = "imx53-ecspi",
.driver_data = (kernel_ulong_t) &imx53_ecspi_devtype_data,
}, { }, {
/* sentinel */ /* sentinel */
} }
@ -774,6 +915,7 @@ static const struct of_device_id spi_imx_dt_ids[] = {
{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, }, { .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, }, { .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, }, { .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
{ .compatible = "fsl,imx53-ecspi", .data = &imx53_ecspi_devtype_data, },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, spi_imx_dt_ids); MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
@ -783,6 +925,9 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
int active = is_active != BITBANG_CS_INACTIVE; int active = is_active != BITBANG_CS_INACTIVE;
int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH); int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
if (spi->mode & SPI_NO_CS)
return;
if (!gpio_is_valid(spi->cs_gpio)) if (!gpio_is_valid(spi->cs_gpio))
return; return;
@ -791,9 +936,11 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
static void spi_imx_push(struct spi_imx_data *spi_imx) static void spi_imx_push(struct spi_imx_data *spi_imx)
{ {
while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) { while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {
if (!spi_imx->count) if (!spi_imx->count)
break; break;
if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder))
break;
spi_imx->tx(spi_imx); spi_imx->tx(spi_imx);
spi_imx->txfifo++; spi_imx->txfifo++;
} }
@ -887,15 +1034,37 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->speed_hz = t->speed_hz; spi_imx->speed_hz = t->speed_hz;
/* Initialize the functions for transfer */ /* Initialize the functions for transfer */
if (spi_imx->bits_per_word <= 8) { if (spi_imx->devtype_data->dynamic_burst) {
spi_imx->rx = spi_imx_buf_rx_u8; u32 mask;
spi_imx->tx = spi_imx_buf_tx_u8;
} else if (spi_imx->bits_per_word <= 16) { spi_imx->dynamic_burst = 0;
spi_imx->rx = spi_imx_buf_rx_u16; spi_imx->remainder = 0;
spi_imx->tx = spi_imx_buf_tx_u16; spi_imx->read_u32 = 1;
mask = (1 << spi_imx->bits_per_word) - 1;
spi_imx->rx = spi_imx_buf_rx_swap;
spi_imx->tx = spi_imx_buf_tx_swap;
spi_imx->dynamic_burst = 1;
spi_imx->remainder = t->len;
if (spi_imx->bits_per_word <= 8)
spi_imx->word_mask = mask << 24 | mask << 16
| mask << 8 | mask;
else if (spi_imx->bits_per_word <= 16)
spi_imx->word_mask = mask << 16 | mask;
else
spi_imx->word_mask = mask;
} else { } else {
spi_imx->rx = spi_imx_buf_rx_u32; if (spi_imx->bits_per_word <= 8) {
spi_imx->tx = spi_imx_buf_tx_u32; spi_imx->rx = spi_imx_buf_rx_u8;
spi_imx->tx = spi_imx_buf_tx_u8;
} else if (spi_imx->bits_per_word <= 16) {
spi_imx->rx = spi_imx_buf_rx_u16;
spi_imx->tx = spi_imx_buf_tx_u16;
} else {
spi_imx->rx = spi_imx_buf_rx_u32;
spi_imx->tx = spi_imx_buf_tx_u32;
}
} }
if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t)) if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
@ -938,7 +1107,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
if (of_machine_is_compatible("fsl,imx6dl")) if (of_machine_is_compatible("fsl,imx6dl"))
return 0; return 0;
spi_imx->wml = spi_imx_get_fifosize(spi_imx) / 2; spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;
/* Prepare for TX DMA: */ /* Prepare for TX DMA: */
master->dma_tx = dma_request_slave_channel_reason(dev, "tx"); master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
@ -1109,6 +1278,9 @@ static int spi_imx_setup(struct spi_device *spi)
dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__, dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
spi->mode, spi->bits_per_word, spi->max_speed_hz); spi->mode, spi->bits_per_word, spi->max_speed_hz);
if (spi->mode & SPI_NO_CS)
return 0;
if (gpio_is_valid(spi->cs_gpio)) if (gpio_is_valid(spi->cs_gpio))
gpio_direction_output(spi->cs_gpio, gpio_direction_output(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 0 : 1); spi->mode & SPI_CS_HIGH ? 0 : 1);
@ -1208,8 +1380,10 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->bitbang.master->cleanup = spi_imx_cleanup; spi_imx->bitbang.master->cleanup = spi_imx_cleanup;
spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message; spi_imx->bitbang.master->prepare_message = spi_imx_prepare_message;
spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message; spi_imx->bitbang.master->unprepare_message = spi_imx_unprepare_message;
spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) | SPI_NO_CS;
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
is_imx53_ecspi(spi_imx))
spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY; spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY;
spi_imx->spi_drctl = spi_drctl; spi_imx->spi_drctl = spi_drctl;
@ -1262,7 +1436,7 @@ static int spi_imx_probe(struct platform_device *pdev)
* Only validated on i.mx35 and i.mx6 now, can remove the constraint * Only validated on i.mx35 and i.mx6 now, can remove the constraint
* if validated on other chips. * if validated on other chips.
*/ */
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx)) { if (spi_imx->devtype_data->has_dmamode) {
ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master); ret = spi_imx_sdma_init(&pdev->dev, spi_imx, master);
if (ret == -EPROBE_DEFER) if (ret == -EPROBE_DEFER)
goto out_clk_put; goto out_clk_put;

View File

@ -32,39 +32,50 @@
#include "spi-test.h" #include "spi-test.h"
/* flag to only simulate transfers */ /* flag to only simulate transfers */
int simulate_only; static int simulate_only;
module_param(simulate_only, int, 0); module_param(simulate_only, int, 0);
MODULE_PARM_DESC(simulate_only, "if not 0 do not execute the spi message"); MODULE_PARM_DESC(simulate_only, "if not 0 do not execute the spi message");
/* dump spi messages */ /* dump spi messages */
int dump_messages; static int dump_messages;
module_param(dump_messages, int, 0); module_param(dump_messages, int, 0);
MODULE_PARM_DESC(dump_messages, MODULE_PARM_DESC(dump_messages,
"=1 dump the basic spi_message_structure, " \ "=1 dump the basic spi_message_structure, " \
"=2 dump the spi_message_structure including data, " \ "=2 dump the spi_message_structure including data, " \
"=3 dump the spi_message structure before and after execution"); "=3 dump the spi_message structure before and after execution");
/* the device is jumpered for loopback - enabling some rx_buf tests */ /* the device is jumpered for loopback - enabling some rx_buf tests */
int loopback; static int loopback;
module_param(loopback, int, 0); module_param(loopback, int, 0);
MODULE_PARM_DESC(loopback, MODULE_PARM_DESC(loopback,
"if set enable loopback mode, where the rx_buf " \ "if set enable loopback mode, where the rx_buf " \
"is checked to match tx_buf after the spi_message " \ "is checked to match tx_buf after the spi_message " \
"is executed"); "is executed");
static int loop_req;
module_param(loop_req, int, 0);
MODULE_PARM_DESC(loop_req,
"if set controller will be asked to enable test loop mode. " \
"If controller supported it, MISO and MOSI will be connected");
static int no_cs;
module_param(no_cs, int, 0);
MODULE_PARM_DESC(no_cs,
"if set Chip Select (CS) will not be used");
/* run only a specific test */ /* run only a specific test */
int run_only_test = -1; static int run_only_test = -1;
module_param(run_only_test, int, 0); module_param(run_only_test, int, 0);
MODULE_PARM_DESC(run_only_test, MODULE_PARM_DESC(run_only_test,
"only run the test with this number (0-based !)"); "only run the test with this number (0-based !)");
/* use vmalloc'ed buffers */ /* use vmalloc'ed buffers */
int use_vmalloc; static int use_vmalloc;
module_param(use_vmalloc, int, 0644); module_param(use_vmalloc, int, 0644);
MODULE_PARM_DESC(use_vmalloc, MODULE_PARM_DESC(use_vmalloc,
"use vmalloc'ed buffers instead of kmalloc'ed"); "use vmalloc'ed buffers instead of kmalloc'ed");
/* check rx ranges */ /* check rx ranges */
int check_ranges = 1; static int check_ranges = 1;
module_param(check_ranges, int, 0644); module_param(check_ranges, int, 0644);
MODULE_PARM_DESC(check_ranges, MODULE_PARM_DESC(check_ranges,
"checks rx_buffer pattern are valid"); "checks rx_buffer pattern are valid");
@ -313,6 +324,17 @@ static int spi_loopback_test_probe(struct spi_device *spi)
{ {
int ret; int ret;
if (loop_req || no_cs) {
spi->mode |= loop_req ? SPI_LOOP : 0;
spi->mode |= no_cs ? SPI_NO_CS : 0;
ret = spi_setup(spi);
if (ret) {
dev_err(&spi->dev, "SPI setup with SPI_LOOP or SPI_NO_CS failed (%d)\n",
ret);
return ret;
}
}
dev_info(&spi->dev, "Executing spi-loopback-tests\n"); dev_info(&spi->dev, "Executing spi-loopback-tests\n");
ret = spi_test_run_tests(spi, spi_tests); ret = spi_test_run_tests(spi, spi_tests);

View File

@ -1338,7 +1338,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
struct resource *r; struct resource *r;
int status = 0, i; int status = 0, i;
u32 regs_offset = 0; u32 regs_offset = 0;
static int bus_num = 1;
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
const struct of_device_id *match; const struct of_device_id *match;
@ -1374,14 +1373,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
of_property_read_u32(node, "ti,spi-num-cs", &num_cs); of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
master->num_chipselect = num_cs; master->num_chipselect = num_cs;
master->bus_num = bus_num++;
if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL)) if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL))
mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
} else { } else {
pdata = dev_get_platdata(&pdev->dev); pdata = dev_get_platdata(&pdev->dev);
master->num_chipselect = pdata->num_cs; master->num_chipselect = pdata->num_cs;
if (pdev->id != -1)
master->bus_num = pdev->id;
mcspi->pin_dir = pdata->pin_dir; mcspi->pin_dir = pdata->pin_dir;
} }
regs_offset = pdata->regs_offset; regs_offset = pdata->regs_offset;

View File

@ -669,8 +669,8 @@ static int orion_spi_probe(struct platform_device *pdev)
status = of_property_read_u32(np, "reg", &cs); status = of_property_read_u32(np, "reg", &cs);
if (status) { if (status) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"%s has no valid 'reg' property (%d)\n", "%pOF has no valid 'reg' property (%d)\n",
np->full_name, status); np, status);
status = 0; status = 0;
continue; continue;
} }

View File

@ -52,14 +52,14 @@ struct pic32_spi_regs {
/* Bit fields of SPI Control Register */ /* Bit fields of SPI Control Register */
#define CTRL_RX_INT_SHIFT 0 /* Rx interrupt generation */ #define CTRL_RX_INT_SHIFT 0 /* Rx interrupt generation */
#define RX_FIFO_EMTPY 0 #define RX_FIFO_EMPTY 0
#define RX_FIFO_NOT_EMPTY 1 /* not empty */ #define RX_FIFO_NOT_EMPTY 1 /* not empty */
#define RX_FIFO_HALF_FULL 2 /* full by half or more */ #define RX_FIFO_HALF_FULL 2 /* full by half or more */
#define RX_FIFO_FULL 3 /* completely full */ #define RX_FIFO_FULL 3 /* completely full */
#define CTRL_TX_INT_SHIFT 2 /* TX interrupt generation */ #define CTRL_TX_INT_SHIFT 2 /* TX interrupt generation */
#define TX_FIFO_ALL_EMPTY 0 /* completely empty */ #define TX_FIFO_ALL_EMPTY 0 /* completely empty */
#define TX_FIFO_EMTPY 1 /* empty */ #define TX_FIFO_EMPTY 1 /* empty */
#define TX_FIFO_HALF_EMPTY 2 /* empty by half or more */ #define TX_FIFO_HALF_EMPTY 2 /* empty by half or more */
#define TX_FIFO_NOT_FULL 3 /* atleast one empty */ #define TX_FIFO_NOT_FULL 3 /* atleast one empty */

View File

@ -2429,7 +2429,7 @@ static struct vendor_data vendor_lsi = {
.internal_cs_ctrl = true, .internal_cs_ctrl = true,
}; };
static struct amba_id pl022_ids[] = { static const struct amba_id pl022_ids[] = {
{ {
/* /*
* ARM PL022 variant, this has a 16bit wide * ARM PL022 variant, this has a 16bit wide

View File

@ -402,8 +402,8 @@ static void cs_assert(struct driver_data *drv_data)
return; return;
} }
if (gpio_is_valid(chip->gpio_cs)) { if (chip->gpiod_cs) {
gpio_set_value(chip->gpio_cs, chip->gpio_cs_inverted); gpiod_set_value(chip->gpiod_cs, chip->gpio_cs_inverted);
return; return;
} }
@ -424,8 +424,8 @@ static void cs_deassert(struct driver_data *drv_data)
return; return;
} }
if (gpio_is_valid(chip->gpio_cs)) { if (chip->gpiod_cs) {
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted); gpiod_set_value(chip->gpiod_cs, !chip->gpio_cs_inverted);
return; return;
} }
@ -1213,17 +1213,16 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
struct pxa2xx_spi_chip *chip_info) struct pxa2xx_spi_chip *chip_info)
{ {
struct driver_data *drv_data = spi_master_get_devdata(spi->master); struct driver_data *drv_data = spi_master_get_devdata(spi->master);
struct gpio_desc *gpiod;
int err = 0; int err = 0;
if (chip == NULL) if (chip == NULL)
return 0; return 0;
if (drv_data->cs_gpiods) { if (drv_data->cs_gpiods) {
struct gpio_desc *gpiod;
gpiod = drv_data->cs_gpiods[spi->chip_select]; gpiod = drv_data->cs_gpiods[spi->chip_select];
if (gpiod) { if (gpiod) {
chip->gpio_cs = desc_to_gpio(gpiod); chip->gpiod_cs = gpiod;
chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
gpiod_set_value(gpiod, chip->gpio_cs_inverted); gpiod_set_value(gpiod, chip->gpio_cs_inverted);
} }
@ -1237,8 +1236,10 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
/* NOTE: setup() can be called multiple times, possibly with /* NOTE: setup() can be called multiple times, possibly with
* different chip_info, release previously requested GPIO * different chip_info, release previously requested GPIO
*/ */
if (gpio_is_valid(chip->gpio_cs)) if (chip->gpiod_cs) {
gpio_free(chip->gpio_cs); gpio_free(desc_to_gpio(chip->gpiod_cs));
chip->gpiod_cs = NULL;
}
/* If (*cs_control) is provided, ignore GPIO chip select */ /* If (*cs_control) is provided, ignore GPIO chip select */
if (chip_info->cs_control) { if (chip_info->cs_control) {
@ -1254,11 +1255,11 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
return err; return err;
} }
chip->gpio_cs = chip_info->gpio_cs; gpiod = gpio_to_desc(chip_info->gpio_cs);
chip->gpiod_cs = gpiod;
chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
err = gpio_direction_output(chip->gpio_cs, err = gpiod_direction_output(gpiod, !chip->gpio_cs_inverted);
!chip->gpio_cs_inverted);
} }
return err; return err;
@ -1317,8 +1318,7 @@ static int setup(struct spi_device *spi)
} }
chip->frm = spi->chip_select; chip->frm = spi->chip_select;
} else }
chip->gpio_cs = -1;
chip->enable_dma = drv_data->master_info->enable_dma; chip->enable_dma = drv_data->master_info->enable_dma;
chip->timeout = TIMOUT_DFLT; chip->timeout = TIMOUT_DFLT;
} }
@ -1416,8 +1416,8 @@ static void cleanup(struct spi_device *spi)
return; return;
if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
gpio_is_valid(chip->gpio_cs)) chip->gpiod_cs)
gpio_free(chip->gpio_cs); gpio_free(desc_to_gpio(chip->gpiod_cs));
kfree(chip); kfree(chip);
} }
@ -1769,8 +1769,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
for (i = 0; i < master->num_chipselect; i++) { for (i = 0; i < master->num_chipselect; i++) {
struct gpio_desc *gpiod; struct gpio_desc *gpiod;
gpiod = devm_gpiod_get_index(dev, "cs", i, gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS);
GPIOD_OUT_HIGH);
if (IS_ERR(gpiod)) { if (IS_ERR(gpiod)) {
/* Means use native chip select */ /* Means use native chip select */
if (PTR_ERR(gpiod) == -ENOENT) if (PTR_ERR(gpiod) == -ENOENT)

View File

@ -83,7 +83,7 @@ struct chip_data {
u16 lpss_tx_threshold; u16 lpss_tx_threshold;
u8 enable_dma; u8 enable_dma;
union { union {
int gpio_cs; struct gpio_desc *gpiod_cs;
unsigned int frm; unsigned int frm;
}; };
int gpio_cs_inverted; int gpio_cs_inverted;

View File

@ -19,6 +19,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
@ -82,6 +83,8 @@
#define QUP_IO_M_MODE_BAM 3 #define QUP_IO_M_MODE_BAM 3
/* QUP_OPERATIONAL fields */ /* QUP_OPERATIONAL fields */
#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11) #define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10) #define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
#define QUP_OP_IN_SERVICE_FLAG BIT(9) #define QUP_OP_IN_SERVICE_FLAG BIT(9)
@ -118,7 +121,7 @@
#define SPI_NUM_CHIPSELECTS 4 #define SPI_NUM_CHIPSELECTS 4
#define SPI_MAX_DMA_XFER (SZ_64K - 64) #define SPI_MAX_XFER (SZ_64K - 64)
/* high speed mode is when bus rate is greater then 26MHz */ /* high speed mode is when bus rate is greater then 26MHz */
#define SPI_HS_MIN_RATE 26000000 #define SPI_HS_MIN_RATE 26000000
@ -147,13 +150,37 @@ struct spi_qup {
int n_words; int n_words;
int tx_bytes; int tx_bytes;
int rx_bytes; int rx_bytes;
const u8 *tx_buf;
u8 *rx_buf;
int qup_v1; int qup_v1;
int use_dma; int mode;
struct dma_slave_config rx_conf; struct dma_slave_config rx_conf;
struct dma_slave_config tx_conf; struct dma_slave_config tx_conf;
}; };
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer);
static inline bool spi_qup_is_flag_set(struct spi_qup *controller, u32 flag)
{
u32 opflag = readl_relaxed(controller->base + QUP_OPERATIONAL);
return (opflag & flag) != 0;
}
static inline bool spi_qup_is_dma_xfer(int mode)
{
if (mode == QUP_IO_M_MODE_DMOV || mode == QUP_IO_M_MODE_BAM)
return true;
return false;
}
/* get's the transaction size length */
static inline unsigned int spi_qup_len(struct spi_qup *controller)
{
return controller->n_words * controller->w_size;
}
static inline bool spi_qup_is_valid_state(struct spi_qup *controller) static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{ {
@ -207,29 +234,26 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
return 0; return 0;
} }
static void spi_qup_fifo_read(struct spi_qup *controller, static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
struct spi_transfer *xfer)
{ {
u8 *rx_buf = xfer->rx_buf; u8 *rx_buf = controller->rx_buf;
u32 word, state; int i, shift, num_bytes;
int idx, shift, w_size; u32 word;
w_size = controller->w_size; for (; num_words; num_words--) {
while (controller->rx_bytes < xfer->len) {
state = readl_relaxed(controller->base + QUP_OPERATIONAL);
if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
break;
word = readl_relaxed(controller->base + QUP_INPUT_FIFO); word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
num_bytes = min_t(int, spi_qup_len(controller) -
controller->rx_bytes,
controller->w_size);
if (!rx_buf) { if (!rx_buf) {
controller->rx_bytes += w_size; controller->rx_bytes += num_bytes;
continue; continue;
} }
for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) { for (i = 0; i < num_bytes; i++, controller->rx_bytes++) {
/* /*
* The data format depends on bytes per SPI word: * The data format depends on bytes per SPI word:
* 4 bytes: 0x12345678 * 4 bytes: 0x12345678
@ -237,38 +261,81 @@ static void spi_qup_fifo_read(struct spi_qup *controller,
* 1 byte : 0x00000012 * 1 byte : 0x00000012
*/ */
shift = BITS_PER_BYTE; shift = BITS_PER_BYTE;
shift *= (w_size - idx - 1); shift *= (controller->w_size - i - 1);
rx_buf[controller->rx_bytes] = word >> shift; rx_buf[controller->rx_bytes] = word >> shift;
} }
} }
} }
static void spi_qup_fifo_write(struct spi_qup *controller, static void spi_qup_read(struct spi_qup *controller, u32 *opflags)
struct spi_transfer *xfer)
{ {
const u8 *tx_buf = xfer->tx_buf; u32 remainder, words_per_block, num_words;
u32 word, state, data; bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
int idx, w_size;
w_size = controller->w_size; remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes,
controller->w_size);
words_per_block = controller->in_blk_sz >> 2;
while (controller->tx_bytes < xfer->len) { do {
/* ACK by clearing service flag */
writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
controller->base + QUP_OPERATIONAL);
state = readl_relaxed(controller->base + QUP_OPERATIONAL); if (is_block_mode) {
if (state & QUP_OP_OUT_FIFO_FULL) num_words = (remainder > words_per_block) ?
words_per_block : remainder;
} else {
if (!spi_qup_is_flag_set(controller,
QUP_OP_IN_FIFO_NOT_EMPTY))
break;
num_words = 1;
}
/* read up to the maximum transfer size available */
spi_qup_read_from_fifo(controller, num_words);
remainder -= num_words;
/* if block mode, check to see if next block is available */
if (is_block_mode && !spi_qup_is_flag_set(controller,
QUP_OP_IN_BLOCK_READ_REQ))
break; break;
word = 0; } while (remainder);
for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
if (!tx_buf) { /*
controller->tx_bytes += w_size; * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
break; * reads, it has to be cleared again at the very end. However, be sure
* to refresh opflags value because MAX_INPUT_DONE_FLAG may now be
* present and this is used to determine if transaction is complete
*/
*opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
controller->base + QUP_OPERATIONAL);
}
static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
{
const u8 *tx_buf = controller->tx_buf;
int i, num_bytes;
u32 word, data;
for (; num_words; num_words--) {
word = 0;
num_bytes = min_t(int, spi_qup_len(controller) -
controller->tx_bytes,
controller->w_size);
if (tx_buf)
for (i = 0; i < num_bytes; i++) {
data = tx_buf[controller->tx_bytes + i];
word |= data << (BITS_PER_BYTE * (3 - i));
} }
data = tx_buf[controller->tx_bytes]; controller->tx_bytes += num_bytes;
word |= data << (BITS_PER_BYTE * (3 - idx));
}
writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO); writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
} }
@ -281,31 +348,61 @@ static void spi_qup_dma_done(void *data)
complete(&qup->done); complete(&qup->done);
} }
static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer, static void spi_qup_write(struct spi_qup *controller)
enum dma_transfer_direction dir, {
bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
u32 remainder, words_per_block, num_words;
remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes,
controller->w_size);
words_per_block = controller->out_blk_sz >> 2;
do {
/* ACK by clearing service flag */
writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
controller->base + QUP_OPERATIONAL);
if (is_block_mode) {
num_words = (remainder > words_per_block) ?
words_per_block : remainder;
} else {
if (spi_qup_is_flag_set(controller,
QUP_OP_OUT_FIFO_FULL))
break;
num_words = 1;
}
spi_qup_write_to_fifo(controller, num_words);
remainder -= num_words;
/* if block mode, check to see if next block is available */
if (is_block_mode && !spi_qup_is_flag_set(controller,
QUP_OP_OUT_BLOCK_WRITE_REQ))
break;
} while (remainder);
}
static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
unsigned int nents, enum dma_transfer_direction dir,
dma_async_tx_callback callback) dma_async_tx_callback callback)
{ {
struct spi_qup *qup = spi_master_get_devdata(master); struct spi_qup *qup = spi_master_get_devdata(master);
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE; unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
struct scatterlist *sgl;
struct dma_chan *chan; struct dma_chan *chan;
dma_cookie_t cookie; dma_cookie_t cookie;
unsigned int nents;
if (dir == DMA_MEM_TO_DEV) { if (dir == DMA_MEM_TO_DEV)
chan = master->dma_tx; chan = master->dma_tx;
nents = xfer->tx_sg.nents; else
sgl = xfer->tx_sg.sgl;
} else {
chan = master->dma_rx; chan = master->dma_rx;
nents = xfer->rx_sg.nents;
sgl = xfer->rx_sg.sgl;
}
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags); desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
if (!desc) if (IS_ERR_OR_NULL(desc))
return -EINVAL; return desc ? PTR_ERR(desc) : -EINVAL;
desc->callback = callback; desc->callback = callback;
desc->callback_param = qup; desc->callback_param = qup;
@ -324,9 +421,33 @@ static void spi_qup_dma_terminate(struct spi_master *master,
dmaengine_terminate_all(master->dma_rx); dmaengine_terminate_all(master->dma_rx);
} }
static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer) static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max,
u32 *nents)
{
struct scatterlist *sg;
u32 total = 0;
for (sg = sgl; sg; sg = sg_next(sg)) {
unsigned int len = sg_dma_len(sg);
/* check for overflow as well as limit */
if (((total + len) < total) || ((total + len) > max))
break;
total += len;
(*nents)++;
}
return total;
}
static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{ {
dma_async_tx_callback rx_done = NULL, tx_done = NULL; dma_async_tx_callback rx_done = NULL, tx_done = NULL;
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
struct scatterlist *tx_sgl, *rx_sgl;
int ret; int ret;
if (xfer->rx_buf) if (xfer->rx_buf)
@ -334,43 +455,122 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
else if (xfer->tx_buf) else if (xfer->tx_buf)
tx_done = spi_qup_dma_done; tx_done = spi_qup_dma_done;
if (xfer->rx_buf) { rx_sgl = xfer->rx_sg.sgl;
ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done); tx_sgl = xfer->tx_sg.sgl;
do {
u32 rx_nents = 0, tx_nents = 0;
if (rx_sgl)
qup->n_words = spi_qup_sgl_get_nents_len(rx_sgl,
SPI_MAX_XFER, &rx_nents) / qup->w_size;
if (tx_sgl)
qup->n_words = spi_qup_sgl_get_nents_len(tx_sgl,
SPI_MAX_XFER, &tx_nents) / qup->w_size;
if (!qup->n_words)
return -EIO;
ret = spi_qup_io_config(spi, xfer);
if (ret) if (ret)
return ret; return ret;
dma_async_issue_pending(master->dma_rx); /* before issuing the descriptors, set the QUP to run */
} ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
if (xfer->tx_buf) { dev_warn(qup->dev, "cannot set RUN state\n");
ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
if (ret)
return ret; return ret;
}
if (rx_sgl) {
ret = spi_qup_prep_sg(master, rx_sgl, rx_nents,
DMA_DEV_TO_MEM, rx_done);
if (ret)
return ret;
dma_async_issue_pending(master->dma_rx);
}
dma_async_issue_pending(master->dma_tx); if (tx_sgl) {
} ret = spi_qup_prep_sg(master, tx_sgl, tx_nents,
DMA_MEM_TO_DEV, tx_done);
if (ret)
return ret;
dma_async_issue_pending(master->dma_tx);
}
if (!wait_for_completion_timeout(&qup->done, timeout))
return -ETIMEDOUT;
for (; rx_sgl && rx_nents--; rx_sgl = sg_next(rx_sgl))
;
for (; tx_sgl && tx_nents--; tx_sgl = sg_next(tx_sgl))
;
} while (rx_sgl || tx_sgl);
return 0; return 0;
} }
static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer) static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{ {
struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master); struct spi_qup *qup = spi_master_get_devdata(master);
int ret; int ret, n_words, iterations, offset = 0;
ret = spi_qup_set_state(qup, QUP_STATE_RUN); n_words = qup->n_words;
if (ret) { iterations = n_words / SPI_MAX_XFER; /* round down */
dev_warn(qup->dev, "cannot set RUN state\n"); qup->rx_buf = xfer->rx_buf;
return ret; qup->tx_buf = xfer->tx_buf;
}
ret = spi_qup_set_state(qup, QUP_STATE_PAUSE); do {
if (ret) { if (iterations)
dev_warn(qup->dev, "cannot set PAUSE state\n"); qup->n_words = SPI_MAX_XFER;
return ret; else
} qup->n_words = n_words % SPI_MAX_XFER;
spi_qup_fifo_write(qup, xfer); if (qup->tx_buf && offset)
qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER;
if (qup->rx_buf && offset)
qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER;
/*
* if the transaction is small enough, we need
* to fallback to FIFO mode
*/
if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
qup->mode = QUP_IO_M_MODE_FIFO;
ret = spi_qup_io_config(spi, xfer);
if (ret)
return ret;
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
dev_warn(qup->dev, "cannot set RUN state\n");
return ret;
}
ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
if (ret) {
dev_warn(qup->dev, "cannot set PAUSE state\n");
return ret;
}
if (qup->mode == QUP_IO_M_MODE_FIFO)
spi_qup_write(qup);
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
dev_warn(qup->dev, "cannot set RUN state\n");
return ret;
}
if (!wait_for_completion_timeout(&qup->done, timeout))
return -ETIMEDOUT;
offset++;
} while (iterations--);
return 0; return 0;
} }
@ -378,29 +578,15 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{ {
struct spi_qup *controller = dev_id; struct spi_qup *controller = dev_id;
struct spi_transfer *xfer;
u32 opflags, qup_err, spi_err; u32 opflags, qup_err, spi_err;
unsigned long flags;
int error = 0; int error = 0;
spin_lock_irqsave(&controller->lock, flags);
xfer = controller->xfer;
controller->xfer = NULL;
spin_unlock_irqrestore(&controller->lock, flags);
qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS); spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS); writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS); writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
if (!xfer) {
dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
qup_err, spi_err, opflags);
return IRQ_HANDLED;
}
if (qup_err) { if (qup_err) {
if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN) if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN)
@ -424,54 +610,27 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
error = -EIO; error = -EIO;
} }
if (!controller->use_dma) { if (spi_qup_is_dma_xfer(controller->mode)) {
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
if (opflags & QUP_OP_IN_SERVICE_FLAG) if (opflags & QUP_OP_IN_SERVICE_FLAG)
spi_qup_fifo_read(controller, xfer); spi_qup_read(controller, &opflags);
if (opflags & QUP_OP_OUT_SERVICE_FLAG) if (opflags & QUP_OP_OUT_SERVICE_FLAG)
spi_qup_fifo_write(controller, xfer); spi_qup_write(controller);
} }
spin_lock_irqsave(&controller->lock, flags); if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
controller->error = error;
controller->xfer = xfer;
spin_unlock_irqrestore(&controller->lock, flags);
if (controller->rx_bytes == xfer->len || error)
complete(&controller->done); complete(&controller->done);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static u32 /* set clock freq ... bits per word, determine mode */
spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer) static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
{
struct spi_qup *qup = spi_master_get_devdata(master);
u32 mode;
qup->w_size = 4;
if (xfer->bits_per_word <= 8)
qup->w_size = 1;
else if (xfer->bits_per_word <= 16)
qup->w_size = 2;
qup->n_words = xfer->len / qup->w_size;
if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
mode = QUP_IO_M_MODE_FIFO;
else
mode = QUP_IO_M_MODE_BLOCK;
return mode;
}
/* set clock freq ... bits per word */
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{ {
struct spi_qup *controller = spi_master_get_devdata(spi->master); struct spi_qup *controller = spi_master_get_devdata(spi->master);
u32 config, iomode, mode, control; int ret;
int ret, n_words;
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
dev_err(controller->dev, "too big size for loopback %d > %d\n", dev_err(controller->dev, "too big size for loopback %d > %d\n",
@ -486,30 +645,59 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
return -EIO; return -EIO;
} }
controller->w_size = DIV_ROUND_UP(xfer->bits_per_word, 8);
controller->n_words = xfer->len / controller->w_size;
if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32)))
controller->mode = QUP_IO_M_MODE_FIFO;
else if (spi->master->can_dma &&
spi->master->can_dma(spi->master, spi, xfer) &&
spi->master->cur_msg_mapped)
controller->mode = QUP_IO_M_MODE_BAM;
else
controller->mode = QUP_IO_M_MODE_BLOCK;
return 0;
}
/* prep qup for another spi transaction of specific type */
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{
struct spi_qup *controller = spi_master_get_devdata(spi->master);
u32 config, iomode, control;
unsigned long flags;
spin_lock_irqsave(&controller->lock, flags);
controller->xfer = xfer;
controller->error = 0;
controller->rx_bytes = 0;
controller->tx_bytes = 0;
spin_unlock_irqrestore(&controller->lock, flags);
if (spi_qup_set_state(controller, QUP_STATE_RESET)) { if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
dev_err(controller->dev, "cannot set RESET state\n"); dev_err(controller->dev, "cannot set RESET state\n");
return -EIO; return -EIO;
} }
mode = spi_qup_get_mode(spi->master, xfer); switch (controller->mode) {
n_words = controller->n_words; case QUP_IO_M_MODE_FIFO:
writel_relaxed(controller->n_words,
if (mode == QUP_IO_M_MODE_FIFO) { controller->base + QUP_MX_READ_CNT);
writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT); writel_relaxed(controller->n_words,
writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT); controller->base + QUP_MX_WRITE_CNT);
/* must be zero for FIFO */ /* must be zero for FIFO */
writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT); writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
} else if (!controller->use_dma) { break;
writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); case QUP_IO_M_MODE_BAM:
writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); writel_relaxed(controller->n_words,
controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(controller->n_words,
controller->base + QUP_MX_OUTPUT_CNT);
/* must be zero for BLOCK and BAM */ /* must be zero for BLOCK and BAM */
writel_relaxed(0, controller->base + QUP_MX_READ_CNT); writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
} else {
mode = QUP_IO_M_MODE_BAM;
writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
if (!controller->qup_v1) { if (!controller->qup_v1) {
void __iomem *input_cnt; void __iomem *input_cnt;
@ -524,23 +712,38 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
if (xfer->tx_buf) if (xfer->tx_buf)
writel_relaxed(0, input_cnt); writel_relaxed(0, input_cnt);
else else
writel_relaxed(n_words, input_cnt); writel_relaxed(controller->n_words, input_cnt);
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
} }
break;
case QUP_IO_M_MODE_BLOCK:
reinit_completion(&controller->done);
writel_relaxed(controller->n_words,
controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(controller->n_words,
controller->base + QUP_MX_OUTPUT_CNT);
/* must be zero for BLOCK and BAM */
writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
break;
default:
dev_err(controller->dev, "unknown mode = %d\n",
controller->mode);
return -EIO;
} }
iomode = readl_relaxed(controller->base + QUP_IO_M_MODES); iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
/* Set input and output transfer mode */ /* Set input and output transfer mode */
iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK); iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
if (!controller->use_dma) if (!spi_qup_is_dma_xfer(controller->mode))
iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN); iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
else else
iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN; iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT); iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT); iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES); writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
@ -581,7 +784,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
config |= xfer->bits_per_word - 1; config |= xfer->bits_per_word - 1;
config |= QUP_CONFIG_SPI_MODE; config |= QUP_CONFIG_SPI_MODE;
if (controller->use_dma) { if (spi_qup_is_dma_xfer(controller->mode)) {
if (!xfer->tx_buf) if (!xfer->tx_buf)
config |= QUP_CONFIG_NO_OUTPUT; config |= QUP_CONFIG_NO_OUTPUT;
if (!xfer->rx_buf) if (!xfer->rx_buf)
@ -599,7 +802,7 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
* status change in BAM mode * status change in BAM mode
*/ */
if (mode == QUP_IO_M_MODE_BAM) if (spi_qup_is_dma_xfer(controller->mode))
mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG; mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK); writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
@ -616,12 +819,13 @@ static int spi_qup_transfer_one(struct spi_master *master,
unsigned long timeout, flags; unsigned long timeout, flags;
int ret = -EIO; int ret = -EIO;
ret = spi_qup_io_config(spi, xfer); ret = spi_qup_io_prep(spi, xfer);
if (ret) if (ret)
return ret; return ret;
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC); timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
timeout = DIV_ROUND_UP(xfer->len * 8, timeout); timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER,
xfer->len) * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout); timeout = 100 * msecs_to_jiffies(timeout);
reinit_completion(&controller->done); reinit_completion(&controller->done);
@ -633,31 +837,22 @@ static int spi_qup_transfer_one(struct spi_master *master,
controller->tx_bytes = 0; controller->tx_bytes = 0;
spin_unlock_irqrestore(&controller->lock, flags); spin_unlock_irqrestore(&controller->lock, flags);
if (controller->use_dma) if (spi_qup_is_dma_xfer(controller->mode))
ret = spi_qup_do_dma(master, xfer); ret = spi_qup_do_dma(spi, xfer, timeout);
else else
ret = spi_qup_do_pio(master, xfer); ret = spi_qup_do_pio(spi, xfer, timeout);
if (ret) if (ret)
goto exit; goto exit;
if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
dev_warn(controller->dev, "cannot set EXECUTE state\n");
goto exit;
}
if (!wait_for_completion_timeout(&controller->done, timeout))
ret = -ETIMEDOUT;
exit: exit:
spi_qup_set_state(controller, QUP_STATE_RESET); spi_qup_set_state(controller, QUP_STATE_RESET);
spin_lock_irqsave(&controller->lock, flags); spin_lock_irqsave(&controller->lock, flags);
controller->xfer = NULL;
if (!ret) if (!ret)
ret = controller->error; ret = controller->error;
spin_unlock_irqrestore(&controller->lock, flags); spin_unlock_irqrestore(&controller->lock, flags);
if (ret && controller->use_dma) if (ret && spi_qup_is_dma_xfer(controller->mode))
spi_qup_dma_terminate(master, xfer); spi_qup_dma_terminate(master, xfer);
return ret; return ret;
@ -668,26 +863,28 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
{ {
struct spi_qup *qup = spi_master_get_devdata(master); struct spi_qup *qup = spi_master_get_devdata(master);
size_t dma_align = dma_get_cache_alignment(); size_t dma_align = dma_get_cache_alignment();
u32 mode; int n_words;
qup->use_dma = 0; if (xfer->rx_buf) {
if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
IS_ERR_OR_NULL(master->dma_rx))
return false;
if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
return false;
}
if (xfer->rx_buf && (xfer->len % qup->in_blk_sz || if (xfer->tx_buf) {
IS_ERR_OR_NULL(master->dma_rx) || if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
!IS_ALIGNED((size_t)xfer->rx_buf, dma_align))) IS_ERR_OR_NULL(master->dma_tx))
return false;
if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
return false;
}
n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8);
if (n_words <= (qup->in_fifo_sz / sizeof(u32)))
return false; return false;
if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
IS_ERR_OR_NULL(master->dma_tx) ||
!IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
return false;
mode = spi_qup_get_mode(master, xfer);
if (mode == QUP_IO_M_MODE_FIFO)
return false;
qup->use_dma = 1;
return true; return true;
} }
@ -750,6 +947,24 @@ err_tx:
return ret; return ret;
} }
static void spi_qup_set_cs(struct spi_device *spi, bool val)
{
struct spi_qup *controller;
u32 spi_ioc;
u32 spi_ioc_orig;
controller = spi_master_get_devdata(spi->master);
spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL);
spi_ioc_orig = spi_ioc;
if (!val)
spi_ioc |= SPI_IO_C_FORCE_CS;
else
spi_ioc &= ~SPI_IO_C_FORCE_CS;
if (spi_ioc != spi_ioc_orig)
writel_relaxed(spi_ioc, controller->base + SPI_IO_CONTROL);
}
static int spi_qup_probe(struct platform_device *pdev) static int spi_qup_probe(struct platform_device *pdev)
{ {
struct spi_master *master; struct spi_master *master;
@ -824,7 +1039,7 @@ static int spi_qup_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->dma_alignment = dma_get_cache_alignment(); master->dma_alignment = dma_get_cache_alignment();
master->max_dma_len = SPI_MAX_DMA_XFER; master->max_dma_len = SPI_MAX_XFER;
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
@ -842,9 +1057,10 @@ static int spi_qup_probe(struct platform_device *pdev)
else if (!ret) else if (!ret)
master->can_dma = spi_qup_can_dma; master->can_dma = spi_qup_can_dma;
/* set v1 flag if device is version 1 */ controller->qup_v1 = (uintptr_t)of_device_get_match_data(dev);
if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1"))
controller->qup_v1 = 1; if (!controller->qup_v1)
master->set_cs = spi_qup_set_cs;
spin_lock_init(&controller->lock); spin_lock_init(&controller->lock);
init_completion(&controller->done); init_completion(&controller->done);
@ -1037,7 +1253,7 @@ static int spi_qup_remove(struct platform_device *pdev)
} }
static const struct of_device_id spi_qup_dt_match[] = { static const struct of_device_id spi_qup_dt_match[] = {
{ .compatible = "qcom,spi-qup-v1.1.1", }, { .compatible = "qcom,spi-qup-v1.1.1", .data = (void *)1, },
{ .compatible = "qcom,spi-qup-v2.1.1", }, { .compatible = "qcom,spi-qup-v2.1.1", },
{ .compatible = "qcom,spi-qup-v2.2.1", }, { .compatible = "qcom,spi-qup-v2.2.1", },
{ } { }

View File

@ -568,7 +568,13 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); if (rs->n_bytes == 1)
writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else if (rs->n_bytes == 2)
writel_relaxed((rs->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else
writel_relaxed((rs->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
@ -666,7 +672,7 @@ static bool rockchip_spi_can_dma(struct spi_master *master,
static int rockchip_spi_probe(struct platform_device *pdev) static int rockchip_spi_probe(struct platform_device *pdev)
{ {
int ret = 0; int ret;
struct rockchip_spi *rs; struct rockchip_spi *rs;
struct spi_master *master; struct spi_master *master;
struct resource *mem; struct resource *mem;
@ -703,13 +709,13 @@ static int rockchip_spi_probe(struct platform_device *pdev)
} }
ret = clk_prepare_enable(rs->apb_pclk); ret = clk_prepare_enable(rs->apb_pclk);
if (ret) { if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable apb_pclk\n"); dev_err(&pdev->dev, "Failed to enable apb_pclk\n");
goto err_put_master; goto err_put_master;
} }
ret = clk_prepare_enable(rs->spiclk); ret = clk_prepare_enable(rs->spiclk);
if (ret) { if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable spi_clk\n"); dev_err(&pdev->dev, "Failed to enable spi_clk\n");
goto err_disable_apbclk; goto err_disable_apbclk;
} }
@ -786,7 +792,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
} }
ret = devm_spi_register_master(&pdev->dev, master); ret = devm_spi_register_master(&pdev->dev, master);
if (ret) { if (ret < 0) {
dev_err(&pdev->dev, "Failed to register master\n"); dev_err(&pdev->dev, "Failed to register master\n");
goto err_free_dma_rx; goto err_free_dma_rx;
} }
@ -816,11 +822,15 @@ static int rockchip_spi_remove(struct platform_device *pdev)
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct rockchip_spi *rs = spi_master_get_devdata(master); struct rockchip_spi *rs = spi_master_get_devdata(master);
pm_runtime_disable(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
clk_disable_unprepare(rs->spiclk); clk_disable_unprepare(rs->spiclk);
clk_disable_unprepare(rs->apb_pclk); clk_disable_unprepare(rs->apb_pclk);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
if (rs->dma_tx.ch) if (rs->dma_tx.ch)
dma_release_channel(rs->dma_tx.ch); dma_release_channel(rs->dma_tx.ch);
if (rs->dma_rx.ch) if (rs->dma_rx.ch)
@ -834,43 +844,34 @@ static int rockchip_spi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int rockchip_spi_suspend(struct device *dev) static int rockchip_spi_suspend(struct device *dev)
{ {
int ret = 0; int ret;
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
struct rockchip_spi *rs = spi_master_get_devdata(master); struct rockchip_spi *rs = spi_master_get_devdata(master);
ret = spi_master_suspend(rs->master); ret = spi_master_suspend(rs->master);
if (ret) if (ret < 0)
return ret; return ret;
if (!pm_runtime_suspended(dev)) { ret = pm_runtime_force_suspend(dev);
clk_disable_unprepare(rs->spiclk); if (ret < 0)
clk_disable_unprepare(rs->apb_pclk); return ret;
}
pinctrl_pm_select_sleep_state(dev); pinctrl_pm_select_sleep_state(dev);
return ret; return 0;
} }
static int rockchip_spi_resume(struct device *dev) static int rockchip_spi_resume(struct device *dev)
{ {
int ret = 0; int ret;
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
struct rockchip_spi *rs = spi_master_get_devdata(master); struct rockchip_spi *rs = spi_master_get_devdata(master);
pinctrl_pm_select_default_state(dev); pinctrl_pm_select_default_state(dev);
if (!pm_runtime_suspended(dev)) { ret = pm_runtime_force_resume(dev);
ret = clk_prepare_enable(rs->apb_pclk); if (ret < 0)
if (ret < 0) return ret;
return ret;
ret = clk_prepare_enable(rs->spiclk);
if (ret < 0) {
clk_disable_unprepare(rs->apb_pclk);
return ret;
}
}
ret = spi_master_resume(rs->master); ret = spi_master_resume(rs->master);
if (ret < 0) { if (ret < 0) {
@ -878,7 +879,7 @@ static int rockchip_spi_resume(struct device *dev)
clk_disable_unprepare(rs->apb_pclk); clk_disable_unprepare(rs->apb_pclk);
} }
return ret; return 0;
} }
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
@ -901,14 +902,14 @@ static int rockchip_spi_runtime_resume(struct device *dev)
struct rockchip_spi *rs = spi_master_get_devdata(master); struct rockchip_spi *rs = spi_master_get_devdata(master);
ret = clk_prepare_enable(rs->apb_pclk); ret = clk_prepare_enable(rs->apb_pclk);
if (ret) if (ret < 0)
return ret; return ret;
ret = clk_prepare_enable(rs->spiclk); ret = clk_prepare_enable(rs->spiclk);
if (ret) if (ret < 0)
clk_disable_unprepare(rs->apb_pclk); clk_disable_unprepare(rs->apb_pclk);
return ret; return 0;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
@ -919,6 +920,7 @@ static const struct dev_pm_ops rockchip_spi_pm = {
}; };
static const struct of_device_id rockchip_spi_dt_match[] = { static const struct of_device_id rockchip_spi_dt_match[] = {
{ .compatible = "rockchip,rv1108-spi", },
{ .compatible = "rockchip,rk3036-spi", }, { .compatible = "rockchip,rk3036-spi", },
{ .compatible = "rockchip,rk3066-spi", }, { .compatible = "rockchip,rk3066-spi", },
{ .compatible = "rockchip,rk3188-spi", }, { .compatible = "rockchip,rk3188-spi", },

View File

@ -38,6 +38,7 @@ struct sh_msiof_chipdata {
u16 tx_fifo_size; u16 tx_fifo_size;
u16 rx_fifo_size; u16 rx_fifo_size;
u16 master_flags; u16 master_flags;
u16 min_div;
}; };
struct sh_msiof_spi_priv { struct sh_msiof_spi_priv {
@ -49,6 +50,7 @@ struct sh_msiof_spi_priv {
struct completion done; struct completion done;
unsigned int tx_fifo_size; unsigned int tx_fifo_size;
unsigned int rx_fifo_size; unsigned int rx_fifo_size;
unsigned int min_div;
void *tx_dma_page; void *tx_dma_page;
void *rx_dma_page; void *rx_dma_page;
dma_addr_t tx_dma_addr; dma_addr_t tx_dma_addr;
@ -261,6 +263,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
if (!WARN_ON(!spi_hz || !parent_rate)) if (!WARN_ON(!spi_hz || !parent_rate))
div = DIV_ROUND_UP(parent_rate, spi_hz); div = DIV_ROUND_UP(parent_rate, spi_hz);
div = max_t(unsigned long, div, p->min_div);
for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) { for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) {
brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div); brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div);
/* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */ /* SCR_BRDV_DIV_1 is valid only if BRPS is x 1/1 or x 1/2 */
@ -998,24 +1002,33 @@ static const struct sh_msiof_chipdata sh_data = {
.tx_fifo_size = 64, .tx_fifo_size = 64,
.rx_fifo_size = 64, .rx_fifo_size = 64,
.master_flags = 0, .master_flags = 0,
.min_div = 1,
}; };
static const struct sh_msiof_chipdata r8a779x_data = { static const struct sh_msiof_chipdata rcar_gen2_data = {
.tx_fifo_size = 64, .tx_fifo_size = 64,
.rx_fifo_size = 64, .rx_fifo_size = 64,
.master_flags = SPI_MASTER_MUST_TX, .master_flags = SPI_MASTER_MUST_TX,
.min_div = 1,
};
static const struct sh_msiof_chipdata rcar_gen3_data = {
.tx_fifo_size = 64,
.rx_fifo_size = 64,
.master_flags = SPI_MASTER_MUST_TX,
.min_div = 2,
}; };
static const struct of_device_id sh_msiof_match[] = { static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
{ .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7790", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7791", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7792", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7793", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7794", .data = &rcar_gen2_data },
{ .compatible = "renesas,rcar-gen2-msiof", .data = &r8a779x_data }, { .compatible = "renesas,rcar-gen2-msiof", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7796", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7796", .data = &rcar_gen3_data },
{ .compatible = "renesas,rcar-gen3-msiof", .data = &r8a779x_data }, { .compatible = "renesas,rcar-gen3-msiof", .data = &rcar_gen3_data },
{ .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */ { .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */
{}, {},
}; };
@ -1230,6 +1243,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, p); platform_set_drvdata(pdev, p);
p->master = master; p->master = master;
p->info = info; p->info = info;
p->min_div = chipdata->min_div;
init_completion(&p->done); init_completion(&p->done);

View File

@ -446,8 +446,8 @@ static int spi_sh_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(&pdev->dev, "platform_get_irq error\n"); dev_err(&pdev->dev, "platform_get_irq error: %d\n", irq);
return -ENODEV; return irq;
} }
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data)); master = spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data));

View File

@ -1132,7 +1132,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
goto err_master_put; goto err_master_put;
} }
spi->rst = devm_reset_control_get(&pdev->dev, NULL); spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (!IS_ERR(spi->rst)) { if (!IS_ERR(spi->rst)) {
reset_control_assert(spi->rst); reset_control_assert(spi->rst);
udelay(2); udelay(2);

View File

@ -502,7 +502,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
init_completion(&sspi->done); init_completion(&sspi->done);
sspi->rstc = devm_reset_control_get(&pdev->dev, NULL); sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(sspi->rstc)) { if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n"); dev_err(&pdev->dev, "Couldn't get reset controller\n");
ret = PTR_ERR(sspi->rstc); ret = PTR_ERR(sspi->rstc);

View File

@ -1083,7 +1083,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
goto exit_free_irq; goto exit_free_irq;
} }
tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
if (IS_ERR(tspi->rst)) { if (IS_ERR(tspi->rst)) {
dev_err(&pdev->dev, "can not get reset\n"); dev_err(&pdev->dev, "can not get reset\n");
ret = PTR_ERR(tspi->rst); ret = PTR_ERR(tspi->rst);

View File

@ -485,7 +485,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
goto exit_free_irq; goto exit_free_irq;
} }
tsd->rst = devm_reset_control_get(&pdev->dev, "spi"); tsd->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
if (IS_ERR(tsd->rst)) { if (IS_ERR(tsd->rst)) {
dev_err(&pdev->dev, "can not get reset\n"); dev_err(&pdev->dev, "can not get reset\n");
ret = PTR_ERR(tsd->rst); ret = PTR_ERR(tsd->rst);

View File

@ -1081,7 +1081,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
goto exit_free_irq; goto exit_free_irq;
} }
tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
if (IS_ERR(tspi->rst)) { if (IS_ERR(tspi->rst)) {
dev_err(&pdev->dev, "can not get reset\n"); dev_err(&pdev->dev, "can not get reset\n");
ret = PTR_ERR(tspi->rst); ret = PTR_ERR(tspi->rst);

View File

@ -393,8 +393,8 @@ static int xlp_spi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
dev_err(&pdev->dev, "no IRQ resource found\n"); dev_err(&pdev->dev, "no IRQ resource found: %d\n", irq);
return -EINVAL; return irq;
} }
err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0, err = devm_request_irq(&pdev->dev, irq, xlp_spi_interrupt, 0,
pdev->name, xspi); pdev->name, xspi);

View File

@ -40,9 +40,13 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/idr.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/spi.h> #include <trace/events/spi.h>
#define SPI_DYN_FIRST_BUS_NUM 0
static DEFINE_IDR(spi_master_idr);
static void spidev_release(struct device *dev) static void spidev_release(struct device *dev)
{ {
@ -321,8 +325,7 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
if (rc != -ENODEV) if (rc != -ENODEV)
return rc; return rc;
add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias); return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
return 0;
} }
struct bus_type spi_bus_type = { struct bus_type spi_bus_type = {
@ -421,6 +424,7 @@ static LIST_HEAD(spi_controller_list);
/* /*
* Used to protect add/del opertion for board_info list and * Used to protect add/del opertion for board_info list and
* spi_controller list, and their matching process * spi_controller list, and their matching process
* also used to protect object of type struct idr
*/ */
static DEFINE_MUTEX(board_lock); static DEFINE_MUTEX(board_lock);
@ -1533,15 +1537,15 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
int rc; int rc;
/* Mode (clock phase/polarity/etc.) */ /* Mode (clock phase/polarity/etc.) */
if (of_find_property(nc, "spi-cpha", NULL)) if (of_property_read_bool(nc, "spi-cpha"))
spi->mode |= SPI_CPHA; spi->mode |= SPI_CPHA;
if (of_find_property(nc, "spi-cpol", NULL)) if (of_property_read_bool(nc, "spi-cpol"))
spi->mode |= SPI_CPOL; spi->mode |= SPI_CPOL;
if (of_find_property(nc, "spi-cs-high", NULL)) if (of_property_read_bool(nc, "spi-cs-high"))
spi->mode |= SPI_CS_HIGH; spi->mode |= SPI_CS_HIGH;
if (of_find_property(nc, "spi-3wire", NULL)) if (of_property_read_bool(nc, "spi-3wire"))
spi->mode |= SPI_3WIRE; spi->mode |= SPI_3WIRE;
if (of_find_property(nc, "spi-lsb-first", NULL)) if (of_property_read_bool(nc, "spi-lsb-first"))
spi->mode |= SPI_LSB_FIRST; spi->mode |= SPI_LSB_FIRST;
/* Device DUAL/QUAD mode */ /* Device DUAL/QUAD mode */
@ -1583,8 +1587,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
if (spi_controller_is_slave(ctlr)) { if (spi_controller_is_slave(ctlr)) {
if (strcmp(nc->name, "slave")) { if (strcmp(nc->name, "slave")) {
dev_err(&ctlr->dev, "%s is not called 'slave'\n", dev_err(&ctlr->dev, "%pOF is not called 'slave'\n",
nc->full_name); nc);
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
@ -1593,8 +1597,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
/* Device address */ /* Device address */
rc = of_property_read_u32(nc, "reg", &value); rc = of_property_read_u32(nc, "reg", &value);
if (rc) { if (rc) {
dev_err(&ctlr->dev, "%s has no valid 'reg' property (%d)\n", dev_err(&ctlr->dev, "%pOF has no valid 'reg' property (%d)\n",
nc->full_name, rc); nc, rc);
return rc; return rc;
} }
spi->chip_select = value; spi->chip_select = value;
@ -1603,8 +1607,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
rc = of_property_read_u32(nc, "spi-max-frequency", &value); rc = of_property_read_u32(nc, "spi-max-frequency", &value);
if (rc) { if (rc) {
dev_err(&ctlr->dev, dev_err(&ctlr->dev,
"%s has no valid 'spi-max-frequency' property (%d)\n", "%pOF has no valid 'spi-max-frequency' property (%d)\n", nc, rc);
nc->full_name, rc);
return rc; return rc;
} }
spi->max_speed_hz = value; spi->max_speed_hz = value;
@ -1621,8 +1624,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
/* Alloc an spi_device */ /* Alloc an spi_device */
spi = spi_alloc_device(ctlr); spi = spi_alloc_device(ctlr);
if (!spi) { if (!spi) {
dev_err(&ctlr->dev, "spi_device alloc error for %s\n", dev_err(&ctlr->dev, "spi_device alloc error for %pOF\n", nc);
nc->full_name);
rc = -ENOMEM; rc = -ENOMEM;
goto err_out; goto err_out;
} }
@ -1631,8 +1633,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
rc = of_modalias_node(nc, spi->modalias, rc = of_modalias_node(nc, spi->modalias,
sizeof(spi->modalias)); sizeof(spi->modalias));
if (rc < 0) { if (rc < 0) {
dev_err(&ctlr->dev, "cannot find modalias for %s\n", dev_err(&ctlr->dev, "cannot find modalias for %pOF\n", nc);
nc->full_name);
goto err_out; goto err_out;
} }
@ -1647,8 +1648,7 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
/* Register the new device */ /* Register the new device */
rc = spi_add_device(spi); rc = spi_add_device(spi);
if (rc) { if (rc) {
dev_err(&ctlr->dev, "spi_device register error %s\n", dev_err(&ctlr->dev, "spi_device register error %pOF\n", nc);
nc->full_name);
goto err_of_node_put; goto err_of_node_put;
} }
@ -1682,8 +1682,7 @@ static void of_register_spi_devices(struct spi_controller *ctlr)
spi = of_register_spi_device(ctlr, nc); spi = of_register_spi_device(ctlr, nc);
if (IS_ERR(spi)) { if (IS_ERR(spi)) {
dev_warn(&ctlr->dev, dev_warn(&ctlr->dev,
"Failed to create SPI device for %s\n", "Failed to create SPI device for %pOF\n", nc);
nc->full_name);
of_node_clear_flag(nc, OF_POPULATED); of_node_clear_flag(nc, OF_POPULATED);
} }
} }
@ -2052,11 +2051,10 @@ static int of_spi_register_master(struct spi_controller *ctlr)
*/ */
int spi_register_controller(struct spi_controller *ctlr) int spi_register_controller(struct spi_controller *ctlr)
{ {
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
struct device *dev = ctlr->dev.parent; struct device *dev = ctlr->dev.parent;
struct boardinfo *bi; struct boardinfo *bi;
int status = -ENODEV; int status = -ENODEV;
int dynamic = 0; int id;
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
@ -2072,19 +2070,28 @@ int spi_register_controller(struct spi_controller *ctlr)
*/ */
if (ctlr->num_chipselect == 0) if (ctlr->num_chipselect == 0)
return -EINVAL; return -EINVAL;
/* allocate dynamic bus number using Linux idr */
if ((ctlr->bus_num < 0) && ctlr->dev.of_node) if ((ctlr->bus_num < 0) && ctlr->dev.of_node) {
ctlr->bus_num = of_alias_get_id(ctlr->dev.of_node, "spi"); id = of_alias_get_id(ctlr->dev.of_node, "spi");
if (id >= 0) {
/* convention: dynamically assigned bus IDs count down from the max */ ctlr->bus_num = id;
if (ctlr->bus_num < 0) { mutex_lock(&board_lock);
/* FIXME switch to an IDR based scheme, something like id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
* I2C now uses, so we can't run out of "dynamic" IDs ctlr->bus_num + 1, GFP_KERNEL);
*/ mutex_unlock(&board_lock);
ctlr->bus_num = atomic_dec_return(&dyn_bus_id); if (WARN(id < 0, "couldn't get idr"))
dynamic = 1; return id == -ENOSPC ? -EBUSY : id;
}
}
if (ctlr->bus_num < 0) {
mutex_lock(&board_lock);
id = idr_alloc(&spi_master_idr, ctlr, SPI_DYN_FIRST_BUS_NUM, 0,
GFP_KERNEL);
mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr"))
return id;
ctlr->bus_num = id;
} }
INIT_LIST_HEAD(&ctlr->queue); INIT_LIST_HEAD(&ctlr->queue);
spin_lock_init(&ctlr->queue_lock); spin_lock_init(&ctlr->queue_lock);
spin_lock_init(&ctlr->bus_lock_spinlock); spin_lock_init(&ctlr->bus_lock_spinlock);
@ -2100,11 +2107,16 @@ int spi_register_controller(struct spi_controller *ctlr)
*/ */
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num); dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
status = device_add(&ctlr->dev); status = device_add(&ctlr->dev);
if (status < 0) if (status < 0) {
/* free bus id */
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
goto done; goto done;
dev_dbg(dev, "registered %s %s%s\n", }
dev_dbg(dev, "registered %s %s\n",
spi_controller_is_slave(ctlr) ? "slave" : "master", spi_controller_is_slave(ctlr) ? "slave" : "master",
dev_name(&ctlr->dev), dynamic ? " (dynamic)" : ""); dev_name(&ctlr->dev));
/* If we're using a queued driver, start the queue */ /* If we're using a queued driver, start the queue */
if (ctlr->transfer) if (ctlr->transfer)
@ -2113,6 +2125,10 @@ int spi_register_controller(struct spi_controller *ctlr)
status = spi_controller_initialize_queue(ctlr); status = spi_controller_initialize_queue(ctlr);
if (status) { if (status) {
device_del(&ctlr->dev); device_del(&ctlr->dev);
/* free bus id */
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
goto done; goto done;
} }
} }
@ -2191,19 +2207,33 @@ static int __unregister(struct device *dev, void *null)
*/ */
void spi_unregister_controller(struct spi_controller *ctlr) void spi_unregister_controller(struct spi_controller *ctlr)
{ {
struct spi_controller *found;
int dummy; int dummy;
/* First make sure that this controller was ever added */
mutex_lock(&board_lock);
found = idr_find(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
if (found != ctlr) {
dev_dbg(&ctlr->dev,
"attempting to delete unregistered controller [%s]\n",
dev_name(&ctlr->dev));
return;
}
if (ctlr->queued) { if (ctlr->queued) {
if (spi_destroy_queue(ctlr)) if (spi_destroy_queue(ctlr))
dev_err(&ctlr->dev, "queue remove failed\n"); dev_err(&ctlr->dev, "queue remove failed\n");
} }
mutex_lock(&board_lock); mutex_lock(&board_lock);
list_del(&ctlr->list); list_del(&ctlr->list);
mutex_unlock(&board_lock); mutex_unlock(&board_lock);
dummy = device_for_each_child(&ctlr->dev, NULL, __unregister); dummy = device_for_each_child(&ctlr->dev, NULL, __unregister);
device_unregister(&ctlr->dev); device_unregister(&ctlr->dev);
/* free bus id */
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
} }
EXPORT_SYMBOL_GPL(spi_unregister_controller); EXPORT_SYMBOL_GPL(spi_unregister_controller);
@ -3311,8 +3341,8 @@ static int of_spi_notify(struct notifier_block *nb, unsigned long action,
put_device(&ctlr->dev); put_device(&ctlr->dev);
if (IS_ERR(spi)) { if (IS_ERR(spi)) {
pr_err("%s: failed to create for '%s'\n", pr_err("%s: failed to create for '%pOF'\n",
__func__, rd->dn->full_name); __func__, rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED); of_node_clear_flag(rd->dn, OF_POPULATED);
return notifier_from_errno(PTR_ERR(spi)); return notifier_from_errno(PTR_ERR(spi));
} }

View File

@ -90,7 +90,7 @@ kvm_stat: FORCE
$(call descend,kvm/$@) $(call descend,kvm/$@)
all: acpi cgroup cpupower gpio hv firewire liblockdep \ all: acpi cgroup cpupower gpio hv firewire liblockdep \
perf selftests turbostat usb \ perf selftests spi turbostat usb \
virtio vm net x86_energy_perf_policy \ virtio vm net x86_energy_perf_policy \
tmon freefall iio objtool kvm_stat tmon freefall iio objtool kvm_stat
@ -100,7 +100,7 @@ acpi_install:
cpupower_install: cpupower_install:
$(call descend,power/$(@:_install=),install) $(call descend,power/$(@:_install=),install)
cgroup_install firewire_install gpio_install hv_install iio_install perf_install usb_install virtio_install vm_install net_install objtool_install: cgroup_install firewire_install gpio_install hv_install iio_install perf_install spi_install usb_install virtio_install vm_install net_install objtool_install:
$(call descend,$(@:_install=),install) $(call descend,$(@:_install=),install)
liblockdep_install: liblockdep_install:

2
tools/spi/Build 100644
View File

@ -0,0 +1,2 @@
spidev_test-y += spidev_test.o
spidev_fdx-y += spidev_fdx.o

View File

@ -1,6 +1,66 @@
CC = $(CROSS_COMPILE)gcc include ../scripts/Makefile.include
all: spidev_test spidev_fdx bindir ?= /usr/bin
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
endif
# Do not use make's built-in rules
# (this improves performance and avoids hard-to-debug behaviour);
MAKEFLAGS += -r
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
ALL_TARGETS := spidev_test spidev_fdx
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
all: $(ALL_PROGRAMS)
export srctree OUTPUT CC LD CFLAGS
include $(srctree)/tools/build/Makefile.include
#
# We need the following to be outside of kernel tree
#
$(OUTPUT)include/linux/spi/spidev.h: ../../include/uapi/linux/spi/spidev.h
mkdir -p $(OUTPUT)include/linux/spi 2>&1 || true
ln -sf $(CURDIR)/../../include/uapi/linux/spi/spidev.h $@
prepare: $(OUTPUT)include/linux/spi/spidev.h
#
# spidev_test
#
SPIDEV_TEST_IN := $(OUTPUT)spidev_test-in.o
$(SPIDEV_TEST_IN): prepare FORCE
$(Q)$(MAKE) $(build)=spidev_test
$(OUTPUT)spidev_test: $(SPIDEV_TEST_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
#
# spidev_fdx
#
SPIDEV_FDX_IN := $(OUTPUT)spidev_fdx-in.o
$(SPIDEV_FDX_IN): prepare FORCE
$(Q)$(MAKE) $(build)=spidev_fdx
$(OUTPUT)spidev_fdx: $(SPIDEV_FDX_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
clean: clean:
$(RM) spidev_test spidev_fdx rm -f $(ALL_PROGRAMS)
rm -f $(OUTPUT)include/linux/spi/spidev.h
find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
install: $(ALL_PROGRAMS)
install -d -m 755 $(DESTDIR)$(bindir); \
for program in $(ALL_PROGRAMS); do \
install $$program $(DESTDIR)$(bindir); \
done
FORCE:
.PHONY: all install clean FORCE prepare