Skip to content

Commit

Permalink
Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux
Browse files Browse the repository at this point in the history
Pull SPI changes from Grant Likely:
 "Changes to both core spi code and spi device drivers.  The driver
  changes are the usual set of bug fixes and platform enablement.

  Core code changes include:

   - More intelligent assignment of SPI bus numbers when using DT

   - Common mechanism for using gpios as CS lines

   - Pull checks for bits_per_word and transfer speed out of drivers and
     into core code

   - Ensure temporary DMA buffers are DMA safe"

* tag 'spi-for-linus' of git://git.secretlab.ca/git/linux: (50 commits)
  spi: Document cs_gpios and cs_gpio in kernel-doc
  spi/of: Fix initialization of cs_gpios array
  spi/pxa2xx: add support for Lynxpoint SPI controllers
  spi/pxa2xx: add support for Intel Low Power Subsystem SPI
  spi/pxa2xx: add support for SPI_LOOP
  spi/pxa2xx: add support for runtime PM
  spi/pxa2xx: add support for DMA engine
  spi/pxa2xx: break out the private DMA API usage into a separate file
  spi/ath79: add shutdown handler
  spi/mips-lantiq: set SPI_MASTER_HALF_DUPLEX flag
  spi/mips-lantiq: make use of spi_finalize_current_message
  spi/bcm63xx: work around inability to keep CS up
  spi/davinci: use request_threaded_irq() to fix deadlock
  spi/orion: Use module_platform_driver()
  spi/bcm63xx: reject transfers unable to transfer
  spi: Ensure memory used for spi_write_then_read() is DMA safe
  spi/spi-mpc512x-psc: init mode bits supported by the driver
  spi/mpc512x-psc: don't use obsolet cell-index property
  spi: Remove erroneous __init, __exit and __exit_p() references in drivers
  spi/s3c64xx: fix checkpatch warnings and error
  ...
  • Loading branch information
torvalds committed Feb 20, 2013
2 parents 10b6339 + 095c375 commit 3aad3f0
Show file tree
Hide file tree
Showing 43 changed files with 2,078 additions and 1,237 deletions.
12 changes: 12 additions & 0 deletions Documentation/devicetree/bindings/spi/sh-msiof.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Renesas MSIOF spi controller

Required properties:
- compatible : "renesas,sh-msiof" for SuperH or
"renesas,sh-mobile-msiof" for SH Mobile series
- reg : Offset and length of the register set for the device
- interrupts : interrupt line used by MSIOF

Optional properties:
- num-cs : total number of chip-selects
- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -7168,6 +7168,7 @@ F: drivers/clk/spear/

SPI SUBSYSTEM
M: Grant Likely <[email protected]>
M: Mark Brown <[email protected]>
L: [email protected]
Q: http://patchwork.kernel.org/project/spi-devel-general/list/
T: git git://git.secretlab.ca/git/linux-2.6.git
Expand Down
15 changes: 13 additions & 2 deletions drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -297,17 +297,28 @@ config SPI_PPC4xx
help
This selects a driver for the PPC4xx SPI Controller.

config SPI_PXA2XX_PXADMA
bool "PXA2xx SSP legacy PXA DMA API support"
depends on SPI_PXA2XX && ARCH_PXA
help
Enable PXA private legacy DMA API support. Note that this is
deprecated in favor of generic DMA engine API.

config SPI_PXA2XX_DMA
def_bool y
depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA

config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
depends on ARCH_PXA || PCI || ACPI
select PXA_SSP if ARCH_PXA
help
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
additional documentation can be found a Documentation/spi/pxa2xx.

config SPI_PXA2XX_PCI
def_bool SPI_PXA2XX && X86_32 && PCI
def_tristate SPI_PXA2XX && PCI

config SPI_RSPI
tristate "Renesas RSPI controller"
Expand Down
5 changes: 4 additions & 1 deletion drivers/spi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx.o
spi-pxa2xx-platform-objs := spi-pxa2xx.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
Expand Down
2 changes: 1 addition & 1 deletion drivers/spi/spi-altera.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
hw->count = 0;
hw->bytes_per_word = (t->bits_per_word ? : spi->bits_per_word) / 8;
hw->bytes_per_word = t->bits_per_word / 8;
hw->len = t->len / hw->bytes_per_word;

if (hw->irq >= 0) {
Expand Down
115 changes: 83 additions & 32 deletions drivers/spi/spi-ath79.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,24 @@
#include <linux/spi/spi_bitbang.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/err.h>

#include <asm/mach-ath79/ar71xx_regs.h>
#include <asm/mach-ath79/ath79_spi_platform.h>

#define DRV_NAME "ath79-spi"

#define ATH79_SPI_RRW_DELAY_FACTOR 12000
#define MHZ (1000 * 1000)

struct ath79_spi {
struct spi_bitbang bitbang;
u32 ioc_base;
u32 reg_ctrl;
void __iomem *base;
struct clk *clk;
unsigned rrw_delay;
};

static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
Expand All @@ -52,6 +59,12 @@ static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
return spi_master_get_devdata(spi->master);
}

static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs)
{
if (nsecs > sp->rrw_delay)
ndelay(nsecs - sp->rrw_delay);
}

static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
{
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
Expand Down Expand Up @@ -83,15 +96,8 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active)

}

static int ath79_spi_setup_cs(struct spi_device *spi)
static void ath79_spi_enable(struct ath79_spi *sp)
{
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
struct ath79_spi_controller_data *cdata;

cdata = spi->controller_data;
if (spi->chip_select && !cdata)
return -EINVAL;

/* enable GPIO mode */
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);

Expand All @@ -101,44 +107,48 @@ static int ath79_spi_setup_cs(struct spi_device *spi)

/* TODO: setup speed? */
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
}

if (spi->chip_select) {
int status = 0;
static void ath79_spi_disable(struct ath79_spi *sp)
{
/* restore CTRL register */
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
/* disable GPIO mode */
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
}

status = gpio_request(cdata->gpio, dev_name(&spi->dev));
if (status)
return status;
static int ath79_spi_setup_cs(struct spi_device *spi)
{
struct ath79_spi_controller_data *cdata;
int status;

status = gpio_direction_output(cdata->gpio,
spi->mode & SPI_CS_HIGH);
if (status) {
gpio_free(cdata->gpio);
return status;
}
} else {
cdata = spi->controller_data;
if (spi->chip_select && !cdata)
return -EINVAL;

status = 0;
if (spi->chip_select) {
unsigned long flags;

flags = GPIOF_DIR_OUT;
if (spi->mode & SPI_CS_HIGH)
sp->ioc_base |= AR71XX_SPI_IOC_CS0;
flags |= GPIOF_INIT_HIGH;
else
sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
flags |= GPIOF_INIT_LOW;

status = gpio_request_one(cdata->gpio, flags,
dev_name(&spi->dev));
}

return 0;
return status;
}

static void ath79_spi_cleanup_cs(struct spi_device *spi)
{
struct ath79_spi *sp = ath79_spidev_to_sp(spi);

if (spi->chip_select) {
struct ath79_spi_controller_data *cdata = spi->controller_data;
gpio_free(cdata->gpio);
}

/* restore CTRL register */
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
/* disable GPIO mode */
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
}

static int ath79_spi_setup(struct spi_device *spi)
Expand Down Expand Up @@ -184,7 +194,11 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,

/* setup MSB (to slave) on trailing edge */
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
ath79_spi_delay(sp, nsecs);
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
ath79_spi_delay(sp, nsecs);
if (bits == 1)
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);

word <<= 1;
}
Expand All @@ -198,6 +212,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
struct ath79_spi *sp;
struct ath79_spi_platform_data *pdata;
struct resource *r;
unsigned long rate;
int ret;

master = spi_alloc_master(&pdev->dev, sizeof(*sp));
Expand Down Expand Up @@ -236,12 +251,39 @@ static int ath79_spi_probe(struct platform_device *pdev)
goto err_put_master;
}

sp->clk = clk_get(&pdev->dev, "ahb");
if (IS_ERR(sp->clk)) {
ret = PTR_ERR(sp->clk);
goto err_unmap;
}

ret = clk_enable(sp->clk);
if (ret)
goto err_clk_put;

rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
if (!rate) {
ret = -EINVAL;
goto err_clk_disable;
}

sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
dev_dbg(&pdev->dev, "register read/write delay is %u nsecs\n",
sp->rrw_delay);

ath79_spi_enable(sp);
ret = spi_bitbang_start(&sp->bitbang);
if (ret)
goto err_unmap;
goto err_disable;

return 0;

err_disable:
ath79_spi_disable(sp);
err_clk_disable:
clk_disable(sp->clk);
err_clk_put:
clk_put(sp->clk);
err_unmap:
iounmap(sp->base);
err_put_master:
Expand All @@ -256,16 +298,25 @@ static int ath79_spi_remove(struct platform_device *pdev)
struct ath79_spi *sp = platform_get_drvdata(pdev);

spi_bitbang_stop(&sp->bitbang);
ath79_spi_disable(sp);
clk_disable(sp->clk);
clk_put(sp->clk);
iounmap(sp->base);
platform_set_drvdata(pdev, NULL);
spi_master_put(sp->bitbang.master);

return 0;
}

static void ath79_spi_shutdown(struct platform_device *pdev)
{
ath79_spi_remove(pdev);
}

static struct platform_driver ath79_spi_driver = {
.probe = ath79_spi_probe,
.remove = ath79_spi_remove,
.shutdown = ath79_spi_shutdown,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
Expand Down
2 changes: 1 addition & 1 deletion drivers/spi/spi-atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ static struct platform_driver atmel_spi_driver = {
.suspend = atmel_spi_suspend,
.resume = atmel_spi_resume,
.probe = atmel_spi_probe,
.remove = __exit_p(atmel_spi_remove),
.remove = atmel_spi_remove,
};
module_platform_driver(atmel_spi_driver);

Expand Down
8 changes: 4 additions & 4 deletions drivers/spi/spi-au1550.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw)
}
}

static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
static void au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
{
u32 stat, cfg;

Expand Down Expand Up @@ -766,7 +766,7 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
}


static int __init au1550_spi_probe(struct platform_device *pdev)
static int au1550_spi_probe(struct platform_device *pdev)
{
struct au1550_spi *hw;
struct spi_master *master;
Expand Down Expand Up @@ -968,7 +968,7 @@ static int __init au1550_spi_probe(struct platform_device *pdev)
return err;
}

static int __exit au1550_spi_remove(struct platform_device *pdev)
static int au1550_spi_remove(struct platform_device *pdev)
{
struct au1550_spi *hw = platform_get_drvdata(pdev);

Expand Down Expand Up @@ -997,7 +997,7 @@ static int __exit au1550_spi_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:au1550-spi");

static struct platform_driver au1550_spi_drv = {
.remove = __exit_p(au1550_spi_remove),
.remove = au1550_spi_remove,
.driver = {
.name = "au1550-spi",
.owner = THIS_MODULE,
Expand Down
Loading

0 comments on commit 3aad3f0

Please sign in to comment.