Skip to content

Commit

Permalink
Merge branch 'next-spi' of git://git.secretlab.ca/git/linux-2.6
Browse files Browse the repository at this point in the history
* 'next-spi' of git://git.secretlab.ca/git/linux-2.6: (23 commits)
  spi: fix probe/remove section markings
  Add OMAP spi100k driver
  spi-imx: don't access struct device directly but use dev_get_platdata
  spi-imx: Add mx25 support
  spi-imx: use positive logic to distinguish cpu variants
  spi-imx: correct check for platform_get_irq failing
  ARM: NUC900: Add spi driver support for nuc900
  spi: SuperH MSIOF SPI Master driver V2
  spi: fix spidev compilation failure when VERBOSE is defined
  spi/au1550_spi: fix setupxfer not to override cfg with zeros
  spi/mpc8xxx: don't use __exit_p to wrap plat_mpc8xxx_spi_remove
  spi/i.MX: fix broken error handling for gpio_request
  spi/i.mx: drain MXC SPI transfer buffer when probing device
  MAINTAINERS: add SPI co-maintainer.
  spi/xilinx_spi: fix incorrect casting
  spi/mpc52xx-spi: minor cleanups
  xilinx_spi: add a platform driver using the xilinx_spi common module.
  xilinx_spi: add support for the DS570 IP.
  xilinx_spi: Switch to iomem functions and support little endian.
  xilinx_spi: Split into of driver and generic part.
  ...
  • Loading branch information
Linus Torvalds committed Dec 14, 2009
2 parents 2205afa + 965346e commit 478e4e9
Show file tree
Hide file tree
Showing 19 changed files with 2,484 additions and 229 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -5080,6 +5080,7 @@ F: drivers/char/specialix*

SPI SUBSYSTEM
M: David Brownell <dbrownell@users.sourceforge.net>
M: Grant Likely <grant.likely@secretlab.ca>
L: spi-devel-general@lists.sourceforge.net
S: Maintained
F: Documentation/spi/
Expand Down
35 changes: 35 additions & 0 deletions arch/arm/mach-w90x900/include/mach/nuc900_spi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* arch/arm/mach-w90x900/include/mach/nuc900_spi.h
*
* Copyright (c) 2009 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation;version 2 of the License.
*
*/

#ifndef __ASM_ARCH_SPI_H
#define __ASM_ARCH_SPI_H

extern void mfp_set_groupg(struct device *dev);

struct nuc900_spi_info {
unsigned int num_cs;
unsigned int lsb;
unsigned int txneg;
unsigned int rxneg;
unsigned int divider;
unsigned int sleep;
unsigned int txnum;
unsigned int txbitlen;
int bus_num;
};

struct nuc900_spi_chip {
unsigned char bits_per_word;
};

#endif /* __ASM_ARCH_SPI_H */
40 changes: 38 additions & 2 deletions drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ config SPI_OMAP24XX
SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI
(McSPI) modules.

config SPI_OMAP_100K
tristate "OMAP SPI 100K"
depends on SPI_MASTER && (ARCH_OMAP850 || ARCH_OMAP730)
help
OMAP SPI 100K master controller for omap7xx boards.

config SPI_ORION
tristate "Orion SPI master (EXPERIMENTAL)"
depends on PLAT_ORION && EXPERIMENTAL
Expand Down Expand Up @@ -220,6 +226,13 @@ config SPI_S3C24XX_GPIO
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.

config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on SUPERH && HAVE_CLK
select SPI_BITBANG
help
SPI driver for SuperH MSIOF blocks.

config SPI_SH_SCI
tristate "SuperH SCI SPI controller"
depends on SUPERH
Expand All @@ -240,15 +253,38 @@ config SPI_TXX9
SPI driver for Toshiba TXx9 MIPS SoCs

config SPI_XILINX
tristate "Xilinx SPI controller"
depends on (XILINX_VIRTEX || MICROBLAZE) && EXPERIMENTAL
tristate "Xilinx SPI controller common module"
depends on HAS_IOMEM && EXPERIMENTAL
select SPI_BITBANG
select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE)
help
This exposes the SPI controller IP from the Xilinx EDK.

See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
Product Specification document (DS464) for hardware details.

Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"

config SPI_XILINX_OF
tristate "Xilinx SPI controller OF device"
depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)
help
This is the OF driver for the SPI controller IP from the Xilinx EDK.

config SPI_XILINX_PLTFM
tristate "Xilinx SPI controller platform device"
depends on SPI_XILINX
help
This is the platform driver for the SPI controller IP
from the Xilinx EDK.

config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Nuvoton NUC900 series ARM SoCs

#
# Add new SPI master controllers in alphabetical order above this line
#
Expand Down
5 changes: 5 additions & 0 deletions drivers/spi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o
obj-$(CONFIG_SPI_ORION) += orion_spi.o
obj-$(CONFIG_SPI_PL022) += amba-pl022.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
Expand All @@ -32,8 +33,12 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
obj-$(CONFIG_SPI_XILINX_PLTFM) += xilinx_spi_pltfm.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
# ... add above this line ...

# SPI protocol drivers (device/link on bus)
Expand Down
10 changes: 8 additions & 2 deletions drivers/spi/au1550_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,14 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
unsigned bpw, hz;
u32 cfg, stat;

bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
bpw = spi->bits_per_word;
hz = spi->max_speed_hz;
if (t) {
if (t->bits_per_word)
bpw = t->bits_per_word;
if (t->speed_hz)
hz = t->speed_hz;
}

if (bpw < 4 || bpw > 24) {
dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n",
Expand Down
86 changes: 72 additions & 14 deletions drivers/spi/mpc52xx_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/spi/mpc52xx_spi.h>
#include <linux/of_spi.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
#include <asm/time.h>
#include <asm/mpc52xx.h>

Expand Down Expand Up @@ -53,21 +53,20 @@ MODULE_LICENSE("GPL");
/* FSM state return values */
#define FSM_STOP 0 /* Nothing more for the state machine to */
/* do. If something interesting happens */
/* then and IRQ will be received */
/* then an IRQ will be received */
#define FSM_POLL 1 /* need to poll for completion, an IRQ is */
/* not expected */
#define FSM_CONTINUE 2 /* Keep iterating the state machine */

/* Driver internal data */
struct mpc52xx_spi {
struct spi_master *master;
u32 sysclk;
void __iomem *regs;
int irq0; /* MODF irq */
int irq1; /* SPIF irq */
int ipb_freq;
unsigned int ipb_freq;

/* Statistics */
/* Statistics; not used now, but will be reintroduced for debugfs */
int msg_count;
int wcol_count;
int wcol_ticks;
Expand All @@ -79,7 +78,6 @@ struct mpc52xx_spi {
spinlock_t lock;
struct work_struct work;


/* Details of current transfer (length, and buffer pointers) */
struct spi_message *message; /* current message */
struct spi_transfer *transfer; /* current transfer */
Expand All @@ -89,14 +87,22 @@ struct mpc52xx_spi {
u8 *rx_buf;
const u8 *tx_buf;
int cs_change;
int gpio_cs_count;
unsigned int *gpio_cs;
};

/*
* CS control function
*/
static void mpc52xx_spi_chipsel(struct mpc52xx_spi *ms, int value)
{
out_8(ms->regs + SPI_PORTDATA, value ? 0 : 0x08);
int cs;

if (ms->gpio_cs_count > 0) {
cs = ms->message->spi->chip_select;
gpio_set_value(ms->gpio_cs[cs], value ? 0 : 1);
} else
out_8(ms->regs + SPI_PORTDATA, value ? 0 : 0x08);
}

/*
Expand Down Expand Up @@ -221,7 +227,7 @@ static int mpc52xx_spi_fsmstate_transfer(int irq, struct mpc52xx_spi *ms,
ms->wcol_tx_timestamp = get_tbl();
data = 0;
if (ms->tx_buf)
data = *(ms->tx_buf-1);
data = *(ms->tx_buf - 1);
out_8(ms->regs + SPI_DATA, data); /* try again */
return FSM_CONTINUE;
} else if (status & SPI_STATUS_MODF) {
Expand Down Expand Up @@ -390,7 +396,9 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
struct spi_master *master;
struct mpc52xx_spi *ms;
void __iomem *regs;
int rc;
u8 ctrl1;
int rc, i = 0;
int gpio_cs;

/* MMIO registers */
dev_dbg(&op->dev, "probing mpc5200 SPI device\n");
Expand All @@ -399,7 +407,8 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
return -ENODEV;

/* initialize the device */
out_8(regs+SPI_CTRL1, SPI_CTRL1_SPIE | SPI_CTRL1_SPE | SPI_CTRL1_MSTR);
ctrl1 = SPI_CTRL1_SPIE | SPI_CTRL1_SPE | SPI_CTRL1_MSTR;
out_8(regs + SPI_CTRL1, ctrl1);
out_8(regs + SPI_CTRL2, 0x0);
out_8(regs + SPI_DATADIR, 0xe); /* Set output pins */
out_8(regs + SPI_PORTDATA, 0x8); /* Deassert /SS signal */
Expand All @@ -409,6 +418,8 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
* on the SPI bus. This fault will also occur if the SPI signals
* are not connected to any pins (port_config setting) */
in_8(regs + SPI_STATUS);
out_8(regs + SPI_CTRL1, ctrl1);

in_8(regs + SPI_DATA);
if (in_8(regs + SPI_STATUS) & SPI_STATUS_MODF) {
dev_err(&op->dev, "mode fault; is port_config correct?\n");
Expand All @@ -422,10 +433,12 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
rc = -ENOMEM;
goto err_alloc;
}

master->bus_num = -1;
master->num_chipselect = 1;
master->setup = mpc52xx_spi_setup;
master->transfer = mpc52xx_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;

dev_set_drvdata(&op->dev, master);

ms = spi_master_get_devdata(master);
Expand All @@ -435,16 +448,51 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
ms->irq1 = irq_of_parse_and_map(op->node, 1);
ms->state = mpc52xx_spi_fsmstate_idle;
ms->ipb_freq = mpc5xxx_get_bus_frequency(op->node);
ms->gpio_cs_count = of_gpio_count(op->node);
if (ms->gpio_cs_count > 0) {
master->num_chipselect = ms->gpio_cs_count;
ms->gpio_cs = kmalloc(ms->gpio_cs_count * sizeof(unsigned int),
GFP_KERNEL);
if (!ms->gpio_cs) {
rc = -ENOMEM;
goto err_alloc;
}

for (i = 0; i < ms->gpio_cs_count; i++) {
gpio_cs = of_get_gpio(op->node, i);
if (gpio_cs < 0) {
dev_err(&op->dev,
"could not parse the gpio field "
"in oftree\n");
rc = -ENODEV;
goto err_gpio;
}

rc = gpio_request(gpio_cs, dev_name(&op->dev));
if (rc) {
dev_err(&op->dev,
"can't request spi cs gpio #%d "
"on gpio line %d\n", i, gpio_cs);
goto err_gpio;
}

gpio_direction_output(gpio_cs, 1);
ms->gpio_cs[i] = gpio_cs;
}
} else {
master->num_chipselect = 1;
}

spin_lock_init(&ms->lock);
INIT_LIST_HEAD(&ms->queue);
INIT_WORK(&ms->work, mpc52xx_spi_wq);

/* Decide if interrupts can be used */
if (ms->irq0 && ms->irq1) {
rc = request_irq(ms->irq0, mpc52xx_spi_irq, IRQF_SAMPLE_RANDOM,
rc = request_irq(ms->irq0, mpc52xx_spi_irq, 0,
"mpc5200-spi-modf", ms);
rc |= request_irq(ms->irq1, mpc52xx_spi_irq, IRQF_SAMPLE_RANDOM,
"mpc5200-spi-spiF", ms);
rc |= request_irq(ms->irq1, mpc52xx_spi_irq, 0,
"mpc5200-spi-spif", ms);
if (rc) {
free_irq(ms->irq0, ms);
free_irq(ms->irq1, ms);
Expand All @@ -471,6 +519,11 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op,
err_register:
dev_err(&ms->master->dev, "initialization failed\n");
spi_master_put(master);
err_gpio:
while (i-- > 0)
gpio_free(ms->gpio_cs[i]);

kfree(ms->gpio_cs);
err_alloc:
err_init:
iounmap(regs);
Expand All @@ -481,10 +534,15 @@ static int __devexit mpc52xx_spi_remove(struct of_device *op)
{
struct spi_master *master = dev_get_drvdata(&op->dev);
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
int i;

free_irq(ms->irq0, ms);
free_irq(ms->irq1, ms);

for (i = 0; i < ms->gpio_cs_count; i++)
gpio_free(ms->gpio_cs[i]);

kfree(ms->gpio_cs);
spi_unregister_master(master);
spi_master_put(master);
iounmap(ms->regs);
Expand Down
Loading

0 comments on commit 478e4e9

Please sign in to comment.