mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +00:00
SPI changes for v3.8
Primarily SPI device driver bug fixes, one removal of an old driver, and some new tegra support. There is some core code change too, but all in all pretty small stuff. The new features to note are: - Common code for describing GPIO CS lines in the device tree - Remove the SPI_BUFSIZ limitation on spi_write_the_read() - core spi ensures bits_per_word is set correctly - SPARC can now use SPI -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJQyg7oAAoJEEFnBt12D9kBdeIP/j29x9sdtN/jXOXi5kdpnuuo SnksHB8pvP8OUq12Zx6X8rT7jrpwQLLEz1WwZcrTxZv6/aVm3MiUTLqqgwM++4Ve MbNWuLN525ifvpD2421EIClzpSz7NjgsjKQoGK6+w8X03YVPJrbBYKpxvs4JWt/g IEPuJT0J5J3g6cFDk41SN0DoXKpZijwIWcJ9hCDZimwYXxxs6QloD3Z7hoGVyGp9 7zP3CB4muXM9BDXnAy6GK9bRz6m31soWKDto0bmH93Axfk+2IEAmxW6dE7uhGFfA o4IWMAWeZ5YOiAOYzANJTkdOqHE36TfdaEZGG2wqTUKbnsQwCgnWVp8vqNPJMoi/ 1o/Zh2wBMcxuUFEL6h/fqBsLvAH3jKOaTf+dzBsz6+eK5FHxvI6BvsdvfdlTvPsv K0hKkGW0F55sYEty4dPr7toea0tCBsAm4tZmjj93afH824U3p/DYL8Av8SYn3vaP xiImsS4bxu75kLXquHFypclbEAVHc5iFqWATY8CGZrECsX/euzh6IW4CcfbZg+wi 8v309vBkjs0K/1xz034GpK+sGnmVBAO99WZUWQmJW0pwfBGJflvRJQ1Rw49ZAFAw 60I3jKN84ZbvuMKvhaoCYSIgv0euMeb1To4acGEVfgbpdVH5YoohtL1kZw/1x+Ob YD+qukZS/4PEJlr6VzLA =bvpH -----END PGP SIGNATURE----- Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6 Pull SPI updates from Grant Likely: "Primarily SPI device driver bug fixes, one removal of an old driver, and some new tegra support. There is some core code change too, but all in all pretty small stuff. The new features to note are: - Common code for describing GPIO CS lines in the device tree - Remove the SPI_BUFSIZ limitation on spi_write_the_read() - core spi ensures bits_per_word is set correctly - SPARC can now use SPI" * tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6: (36 commits) spi/sparc: Allow of_register_spi_devices for sparc spi: Remove HOTPLUG section attributes spi: Add support for specifying 3-wire mode via device tree spi: Fix comparison of different integer types spi/orion: Add SPI_CHPA and SPI_CPOL support to kirkwood driver. spi/sh: Add SH Mobile series as dependency to MSIOF controller spi/sh-msiof: Remove unneeded clock name spi: Remove SPI_BUFSIZ restriction on spi_write_then_read() spi/stmp: remove obsolete driver spi/clps711x: New SPI master driver spi: omap2-mcspi: remove duplicate inclusion of linux/err.h spi: omap2-mcspi: Fix the redifine warning spi/sh-hspi: add CS manual control support of_spi: add generic binding support to specify cs gpio spi: omap2-mcspi: remove duplicated include from spi-omap2-mcspi.c spi/bitbang: (cosmetic) simplify list manipulation spi/bitbang: avoid needless loop flow manipulations spi/omap: fix D0/D1 direction confusion spi: tegra: add spi driver for sflash controller spi: Dont call master->setup if not populated ...
This commit is contained in:
commit
d3b43e12b2
@ -0,0 +1,26 @@
|
||||
NVIDIA Tegra20 SFLASH controller.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "nvidia,tegra20-sflash".
|
||||
- reg: Should contain SFLASH registers location and length.
|
||||
- interrupts: Should contain SFLASH interrupts.
|
||||
- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
|
||||
request selector for this SFLASH controller.
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
|
||||
spi@7000d600 {
|
||||
compatible = "nvidia,tegra20-sflash";
|
||||
reg = <0x7000c380 0x80>;
|
||||
interrupts = <0 39 0x04>;
|
||||
nvidia,dma-request-selector = <&apbdma 16>;
|
||||
spi-max-frequency = <25000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -0,0 +1,26 @@
|
||||
NVIDIA Tegra20/Tegra30 SLINK controller.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "nvidia,tegra20-slink", "nvidia,tegra30-slink".
|
||||
- reg: Should contain SLINK registers location and length.
|
||||
- interrupts: Should contain SLINK interrupts.
|
||||
- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
|
||||
request selector for this SLINK controller.
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
|
||||
slink@7000d600 {
|
||||
compatible = "nvidia,tegra20-slink";
|
||||
reg = <0x7000d600 0x200>;
|
||||
interrupts = <0 82 0x04>;
|
||||
nvidia,dma-request-selector = <&apbdma 16>;
|
||||
spi-max-frequency = <25000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
@ -6,7 +6,9 @@ Required properties:
|
||||
- "ti,omap4-spi" for OMAP4+.
|
||||
- ti,spi-num-cs : Number of chipselect supported by the instance.
|
||||
- ti,hwmods: Name of the hwmod associated to the McSPI
|
||||
|
||||
- ti,pindir-d0-out-d1-in: Select the D0 pin as output and D1 as
|
||||
input. The default is D0 as input and
|
||||
D1 as output.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -12,6 +12,7 @@ The SPI master node requires the following properties:
|
||||
- #size-cells - should be zero.
|
||||
- compatible - name of SPI bus controller following generic names
|
||||
recommended practice.
|
||||
- cs-gpios - (optional) gpios chip select.
|
||||
No other properties are required in the SPI bus node. It is assumed
|
||||
that a driver for an SPI bus device will understand that it is an SPI bus.
|
||||
However, the binding does not attempt to define the specific method for
|
||||
@ -24,6 +25,22 @@ support describing the chip select layout.
|
||||
Optional property:
|
||||
- num-cs : total number of chipselects
|
||||
|
||||
If cs-gpios is used the number of chip select will automatically increased
|
||||
with max(cs-gpios > hw cs)
|
||||
|
||||
So if for example the controller has 2 CS lines, and the cs-gpios
|
||||
property looks like this:
|
||||
|
||||
cs-gpios = <&gpio1 0 0> <0> <&gpio1 1 0> <&gpio1 2 0>;
|
||||
|
||||
Then it should be configured so that num_chipselect = 4 with the
|
||||
following mapping:
|
||||
|
||||
cs0 : &gpio1 0 0
|
||||
cs1 : native
|
||||
cs2 : &gpio1 1 0
|
||||
cs3 : &gpio1 2 0
|
||||
|
||||
SPI slave nodes must be children of the SPI master node and can
|
||||
contain the following properties.
|
||||
- reg - (required) chip select address of device.
|
||||
@ -36,6 +53,11 @@ contain the following properties.
|
||||
shifted clock phase (CPHA) mode
|
||||
- spi-cs-high - (optional) Empty property indicating device requires
|
||||
chip select active high
|
||||
- spi-3wire - (optional) Empty property indicating device requires
|
||||
3-wire mode.
|
||||
|
||||
If a gpio chipselect is used for the SPI slave the gpio number will be passed
|
||||
via the cs_gpio
|
||||
|
||||
SPI example for an MPC5200 SPI bus:
|
||||
spi@f00 {
|
||||
|
@ -123,6 +123,13 @@ config SPI_BUTTERFLY
|
||||
inexpensive battery powered microcontroller evaluation board.
|
||||
This same cable can be used to flash new firmware.
|
||||
|
||||
config SPI_CLPS711X
|
||||
tristate "CLPS711X host SPI controller"
|
||||
depends on ARCH_CLPS711X
|
||||
help
|
||||
This enables dedicated general purpose SPI/Microwire1-compatible
|
||||
master mode interface (SSI1) for CLPS711X-based CPUs.
|
||||
|
||||
config SPI_COLDFIRE_QSPI
|
||||
tristate "Freescale Coldfire QSPI controller"
|
||||
depends on (M520x || M523x || M5249 || M525x || M527x || M528x || M532x)
|
||||
@ -341,10 +348,10 @@ config SPI_SC18IS602
|
||||
|
||||
config SPI_SH_MSIOF
|
||||
tristate "SuperH MSIOF SPI controller"
|
||||
depends on SUPERH && HAVE_CLK
|
||||
depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
|
||||
select SPI_BITBANG
|
||||
help
|
||||
SPI driver for SuperH MSIOF blocks.
|
||||
SPI driver for SuperH and SH Mobile MSIOF blocks.
|
||||
|
||||
config SPI_SH
|
||||
tristate "SuperH SPI controller"
|
||||
@ -372,12 +379,6 @@ config SPI_SIRF
|
||||
help
|
||||
SPI driver for CSR SiRFprimaII SoCs
|
||||
|
||||
config SPI_STMP3XXX
|
||||
tristate "Freescale STMP37xx/378x SPI/SSP controller"
|
||||
depends on ARCH_STMP3XXX
|
||||
help
|
||||
SPI driver for Freescale STMP37xx/378x SoC SSP interface
|
||||
|
||||
config SPI_MXS
|
||||
tristate "Freescale MXS SPI controller"
|
||||
depends on ARCH_MXS
|
||||
@ -385,6 +386,20 @@ config SPI_MXS
|
||||
help
|
||||
SPI driver for Freescale MXS devices.
|
||||
|
||||
config SPI_TEGRA20_SFLASH
|
||||
tristate "Nvidia Tegra20 Serial flash Controller"
|
||||
depends on ARCH_TEGRA
|
||||
help
|
||||
SPI driver for Nvidia Tegra20 Serial flash Controller interface.
|
||||
The main usecase of this controller is to use spi flash as boot
|
||||
device.
|
||||
|
||||
config SPI_TEGRA20_SLINK
|
||||
tristate "Nvidia Tegra20/Tegra30 SLINK Controller"
|
||||
depends on ARCH_TEGRA && TEGRA20_APB_DMA
|
||||
help
|
||||
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
|
||||
|
||||
config SPI_TI_SSP
|
||||
tristate "TI Sequencer Serial Port - SPI Support"
|
||||
depends on MFD_TI_SSP
|
||||
|
@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
|
||||
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
|
||||
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
|
||||
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
|
||||
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
|
||||
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
|
||||
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
|
||||
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
|
||||
@ -59,11 +60,11 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
|
||||
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
|
||||
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
|
||||
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
|
||||
obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o
|
||||
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
|
||||
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
|
||||
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
|
||||
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
|
||||
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
|
||||
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
|
||||
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
|
||||
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
|
||||
|
||||
|
@ -215,7 +215,7 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit altera_spi_probe(struct platform_device *pdev)
|
||||
static int altera_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct altera_spi_platform_data *platp = pdev->dev.platform_data;
|
||||
struct altera_spi *hw;
|
||||
@ -290,7 +290,7 @@ exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit altera_spi_remove(struct platform_device *dev)
|
||||
static int altera_spi_remove(struct platform_device *dev)
|
||||
{
|
||||
struct altera_spi *hw = platform_get_drvdata(dev);
|
||||
struct spi_master *master = hw->bitbang.master;
|
||||
@ -311,7 +311,7 @@ MODULE_DEVICE_TABLE(of, altera_spi_match);
|
||||
|
||||
static struct platform_driver altera_spi_driver = {
|
||||
.probe = altera_spi_probe,
|
||||
.remove = __devexit_p(altera_spi_remove),
|
||||
.remove = altera_spi_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -192,7 +192,7 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
|
||||
return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
|
||||
}
|
||||
|
||||
static __devinit int ath79_spi_probe(struct platform_device *pdev)
|
||||
static int ath79_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct ath79_spi *sp;
|
||||
@ -251,7 +251,7 @@ err_put_master:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int ath79_spi_remove(struct platform_device *pdev)
|
||||
static int ath79_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ath79_spi *sp = platform_get_drvdata(pdev);
|
||||
|
||||
@ -265,7 +265,7 @@ static __devexit int ath79_spi_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver ath79_spi_driver = {
|
||||
.probe = ath79_spi_probe,
|
||||
.remove = __devexit_p(ath79_spi_remove),
|
||||
.remove = ath79_spi_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -907,7 +907,7 @@ static void atmel_spi_cleanup(struct spi_device *spi)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __devinit atmel_spi_probe(struct platform_device *pdev)
|
||||
static int atmel_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs;
|
||||
int irq;
|
||||
@ -1003,7 +1003,7 @@ out_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit atmel_spi_remove(struct platform_device *pdev)
|
||||
static int atmel_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include <bcm63xx_dev_spi.h>
|
||||
|
||||
#define PFX KBUILD_MODNAME
|
||||
#define DRV_VER "0.1.2"
|
||||
|
||||
struct bcm63xx_spi {
|
||||
struct completion done;
|
||||
@ -170,13 +169,6 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = bcm63xx_spi_check_transfer(spi, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
|
||||
spi->mode & ~MODEBITS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
|
||||
__func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
|
||||
|
||||
@ -337,7 +329,7 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
|
||||
static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
|
||||
static int bcm63xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -441,8 +433,8 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
|
||||
goto out_clk_disable;
|
||||
}
|
||||
|
||||
dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n",
|
||||
r->start, irq, bs->fifo_size, DRV_VER);
|
||||
dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n",
|
||||
r->start, irq, bs->fifo_size);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -457,7 +449,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
|
||||
static int bcm63xx_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
|
||||
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
|
||||
@ -485,6 +477,8 @@ static int bcm63xx_spi_suspend(struct device *dev)
|
||||
platform_get_drvdata(to_platform_device(dev));
|
||||
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
|
||||
|
||||
spi_master_suspend(master);
|
||||
|
||||
clk_disable(bs->clk);
|
||||
|
||||
return 0;
|
||||
@ -498,6 +492,8 @@ static int bcm63xx_spi_resume(struct device *dev)
|
||||
|
||||
clk_enable(bs->clk);
|
||||
|
||||
spi_master_resume(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -518,7 +514,7 @@ static struct platform_driver bcm63xx_spi_driver = {
|
||||
.pm = BCM63XX_SPI_PM_OPS,
|
||||
},
|
||||
.probe = bcm63xx_spi_probe,
|
||||
.remove = __devexit_p(bcm63xx_spi_remove),
|
||||
.remove = bcm63xx_spi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(bcm63xx_spi_driver);
|
||||
|
@ -755,8 +755,7 @@ bfin_sport_spi_destroy_queue(struct bfin_sport_spi_master_data *drv_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
bfin_sport_spi_probe(struct platform_device *pdev)
|
||||
static int bfin_sport_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bfin5xx_spi_master *platform_info;
|
||||
@ -863,8 +862,7 @@ bfin_sport_spi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* stop hardware and remove the driver */
|
||||
static int __devexit
|
||||
bfin_sport_spi_remove(struct platform_device *pdev)
|
||||
static int bfin_sport_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_sport_spi_master_data *drv_data = platform_get_drvdata(pdev);
|
||||
int status = 0;
|
||||
@ -935,7 +933,7 @@ static struct platform_driver bfin_sport_spi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = bfin_sport_spi_probe,
|
||||
.remove = __devexit_p(bfin_sport_spi_remove),
|
||||
.remove = bfin_sport_spi_remove,
|
||||
.suspend = bfin_sport_spi_suspend,
|
||||
.resume = bfin_sport_spi_resume,
|
||||
};
|
||||
|
@ -1387,7 +1387,7 @@ out_error_get_res:
|
||||
}
|
||||
|
||||
/* stop hardware and remove the driver */
|
||||
static int __devexit bfin_spi_remove(struct platform_device *pdev)
|
||||
static int bfin_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
|
||||
int status = 0;
|
||||
@ -1477,7 +1477,7 @@ static struct platform_driver bfin_spi_driver = {
|
||||
},
|
||||
.suspend = bfin_spi_suspend,
|
||||
.resume = bfin_spi_resume,
|
||||
.remove = __devexit_p(bfin_spi_remove),
|
||||
.remove = bfin_spi_remove,
|
||||
};
|
||||
|
||||
static int __init bfin_spi_init(void)
|
||||
|
@ -260,11 +260,11 @@ static void bitbang_work(struct work_struct *work)
|
||||
struct spi_bitbang *bitbang =
|
||||
container_of(work, struct spi_bitbang, work);
|
||||
unsigned long flags;
|
||||
struct spi_message *m, *_m;
|
||||
|
||||
spin_lock_irqsave(&bitbang->lock, flags);
|
||||
bitbang->busy = 1;
|
||||
while (!list_empty(&bitbang->queue)) {
|
||||
struct spi_message *m;
|
||||
list_for_each_entry_safe(m, _m, &bitbang->queue, queue) {
|
||||
struct spi_device *spi;
|
||||
unsigned nsecs;
|
||||
struct spi_transfer *t = NULL;
|
||||
@ -273,9 +273,7 @@ static void bitbang_work(struct work_struct *work)
|
||||
int status;
|
||||
int do_setup = -1;
|
||||
|
||||
m = container_of(bitbang->queue.next, struct spi_message,
|
||||
queue);
|
||||
list_del_init(&m->queue);
|
||||
list_del(&m->queue);
|
||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
||||
|
||||
/* FIXME this is made-up ... the correct value is known to
|
||||
@ -346,17 +344,14 @@ static void bitbang_work(struct work_struct *work)
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
|
||||
if (!cs_change)
|
||||
continue;
|
||||
if (t->transfer_list.next == &m->transfers)
|
||||
break;
|
||||
|
||||
/* sometimes a short mid-message deselect of the chip
|
||||
* may be needed to terminate a mode or command
|
||||
*/
|
||||
ndelay(nsecs);
|
||||
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
|
||||
ndelay(nsecs);
|
||||
if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) {
|
||||
/* sometimes a short mid-message deselect of the chip
|
||||
* may be needed to terminate a mode or command
|
||||
*/
|
||||
ndelay(nsecs);
|
||||
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
|
||||
ndelay(nsecs);
|
||||
}
|
||||
}
|
||||
|
||||
m->status = status;
|
||||
|
296
drivers/spi/spi-clps711x.c
Normal file
296
drivers/spi/spi-clps711x.c
Normal file
@ -0,0 +1,296 @@
|
||||
/*
|
||||
* CLPS711X SPI bus driver
|
||||
*
|
||||
* Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/platform_data/spi-clps711x.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define DRIVER_NAME "spi-clps711x"
|
||||
|
||||
struct spi_clps711x_data {
|
||||
struct completion done;
|
||||
|
||||
struct clk *spi_clk;
|
||||
u32 max_speed_hz;
|
||||
|
||||
u8 *tx_buf;
|
||||
u8 *rx_buf;
|
||||
int count;
|
||||
int len;
|
||||
|
||||
int chipselect[0];
|
||||
};
|
||||
|
||||
static int spi_clps711x_setup(struct spi_device *spi)
|
||||
{
|
||||
struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (spi->bits_per_word != 8) {
|
||||
dev_err(&spi->dev, "Unsupported master bus width %i\n",
|
||||
spi->bits_per_word);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* We are expect that SPI-device is not selected */
|
||||
gpio_direction_output(hw->chipselect[spi->chip_select],
|
||||
!(spi->mode & SPI_CS_HIGH));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spi_clps711x_setup_mode(struct spi_device *spi)
|
||||
{
|
||||
/* Setup edge for transfer */
|
||||
if (spi->mode & SPI_CPHA)
|
||||
clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
|
||||
else
|
||||
clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
|
||||
}
|
||||
|
||||
static int spi_clps711x_setup_xfer(struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
|
||||
u8 bpw = xfer->bits_per_word ? : spi->bits_per_word;
|
||||
struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (bpw != 8) {
|
||||
dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Setup SPI frequency divider */
|
||||
if (!speed || (speed >= hw->max_speed_hz))
|
||||
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
|
||||
SYSCON1_ADCKSEL(3), SYSCON1);
|
||||
else if (speed >= (hw->max_speed_hz / 2))
|
||||
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
|
||||
SYSCON1_ADCKSEL(2), SYSCON1);
|
||||
else if (speed >= (hw->max_speed_hz / 8))
|
||||
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
|
||||
SYSCON1_ADCKSEL(1), SYSCON1);
|
||||
else
|
||||
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
|
||||
SYSCON1_ADCKSEL(0), SYSCON1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spi_clps711x_transfer_one_message(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
|
||||
struct spi_transfer *xfer;
|
||||
int status = 0, cs = hw->chipselect[msg->spi->chip_select];
|
||||
u32 data;
|
||||
|
||||
spi_clps711x_setup_mode(msg->spi);
|
||||
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
|
||||
status = -EINVAL;
|
||||
goto out_xfr;
|
||||
}
|
||||
|
||||
gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
|
||||
|
||||
INIT_COMPLETION(hw->done);
|
||||
|
||||
hw->count = 0;
|
||||
hw->len = xfer->len;
|
||||
hw->tx_buf = (u8 *)xfer->tx_buf;
|
||||
hw->rx_buf = (u8 *)xfer->rx_buf;
|
||||
|
||||
/* Initiate transfer */
|
||||
data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
|
||||
clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
|
||||
|
||||
wait_for_completion(&hw->done);
|
||||
|
||||
if (xfer->delay_usecs)
|
||||
udelay(xfer->delay_usecs);
|
||||
|
||||
if (xfer->cs_change ||
|
||||
list_is_last(&xfer->transfer_list, &msg->transfers))
|
||||
gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
|
||||
|
||||
msg->actual_length += xfer->len;
|
||||
}
|
||||
|
||||
out_xfr:
|
||||
msg->status = status;
|
||||
spi_finalize_current_message(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
|
||||
u32 data;
|
||||
|
||||
/* Handle RX */
|
||||
data = clps_readb(SYNCIO);
|
||||
if (hw->rx_buf)
|
||||
hw->rx_buf[hw->count] = (u8)data;
|
||||
|
||||
hw->count++;
|
||||
|
||||
/* Handle TX */
|
||||
if (hw->count < hw->len) {
|
||||
data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
|
||||
clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
|
||||
} else
|
||||
complete(&hw->done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int spi_clps711x_probe(struct platform_device *pdev)
|
||||
{
|
||||
int i, ret;
|
||||
struct spi_master *master;
|
||||
struct spi_clps711x_data *hw;
|
||||
struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->num_chipselect < 1) {
|
||||
dev_err(&pdev->dev, "At least one CS must be defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
master = spi_alloc_master(&pdev->dev,
|
||||
sizeof(struct spi_clps711x_data) +
|
||||
sizeof(int) * pdata->num_chipselect);
|
||||
if (!master) {
|
||||
dev_err(&pdev->dev, "SPI allocating memory error\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
master->bus_num = pdev->id;
|
||||
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
|
||||
master->num_chipselect = pdata->num_chipselect;
|
||||
master->setup = spi_clps711x_setup;
|
||||
master->transfer_one_message = spi_clps711x_transfer_one_message;
|
||||
|
||||
hw = spi_master_get_devdata(master);
|
||||
|
||||
for (i = 0; i < master->num_chipselect; i++) {
|
||||
hw->chipselect[i] = pdata->chipselect[i];
|
||||
if (!gpio_is_valid(hw->chipselect[i])) {
|
||||
dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
if (gpio_request(hw->chipselect[i], DRIVER_NAME)) {
|
||||
dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
hw->spi_clk = devm_clk_get(&pdev->dev, "spi");
|
||||
if (IS_ERR(hw->spi_clk)) {
|
||||
dev_err(&pdev->dev, "Can't get clocks\n");
|
||||
ret = PTR_ERR(hw->spi_clk);
|
||||
goto err_out;
|
||||
}
|
||||
hw->max_speed_hz = clk_get_rate(hw->spi_clk);
|
||||
|
||||
init_completion(&hw->done);
|
||||
platform_set_drvdata(pdev, master);
|
||||
|
||||
/* Disable extended mode due hardware problems */
|
||||
clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
|
||||
|
||||
/* Clear possible pending interrupt */
|
||||
clps_readl(SYNCIO);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
|
||||
dev_name(&pdev->dev), hw);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Can't request IRQ\n");
|
||||
clk_put(hw->spi_clk);
|
||||
goto clk_out;
|
||||
}
|
||||
|
||||
ret = spi_register_master(master);
|
||||
if (!ret) {
|
||||
dev_info(&pdev->dev,
|
||||
"SPI bus driver initialized. Master clock %u Hz\n",
|
||||
hw->max_speed_hz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(&pdev->dev, "Failed to register master\n");
|
||||
devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
|
||||
|
||||
clk_out:
|
||||
devm_clk_put(&pdev->dev, hw->spi_clk);
|
||||
|
||||
err_out:
|
||||
while (--i >= 0)
|
||||
if (gpio_is_valid(hw->chipselect[i]))
|
||||
gpio_free(hw->chipselect[i]);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
spi_master_put(master);
|
||||
kfree(master);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_clps711x_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
|
||||
|
||||
devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw);
|
||||
|
||||
for (i = 0; i < master->num_chipselect; i++)
|
||||
if (gpio_is_valid(hw->chipselect[i]))
|
||||
gpio_free(hw->chipselect[i]);
|
||||
|
||||
devm_clk_put(&pdev->dev, hw->spi_clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
spi_unregister_master(master);
|
||||
kfree(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver clps711x_spi_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = spi_clps711x_probe,
|
||||
.remove = spi_clps711x_remove,
|
||||
};
|
||||
module_platform_driver(clps711x_spi_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
|
||||
MODULE_DESCRIPTION("CLPS711X SPI bus driver");
|
@ -401,7 +401,7 @@ static int mcfqspi_setup(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit mcfqspi_probe(struct platform_device *pdev)
|
||||
static int mcfqspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct mcfqspi *mcfqspi;
|
||||
@ -515,7 +515,7 @@ fail0:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __devexit mcfqspi_remove(struct platform_device *pdev)
|
||||
static int mcfqspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
|
||||
@ -594,7 +594,7 @@ static struct platform_driver mcfqspi_driver = {
|
||||
.driver.owner = THIS_MODULE,
|
||||
.driver.pm = &mcfqspi_pm,
|
||||
.probe = mcfqspi_probe,
|
||||
.remove = __devexit_p(mcfqspi_remove),
|
||||
.remove = mcfqspi_remove,
|
||||
};
|
||||
module_platform_driver(mcfqspi_driver);
|
||||
|
||||
|
@ -769,7 +769,7 @@ rx_dma_failed:
|
||||
* It will invoke spi_bitbang_start to create work queue so that client driver
|
||||
* can register transfer method to work queue.
|
||||
*/
|
||||
static int __devinit davinci_spi_probe(struct platform_device *pdev)
|
||||
static int davinci_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct davinci_spi *dspi;
|
||||
@ -952,7 +952,7 @@ err:
|
||||
* It will also call spi_bitbang_stop to destroy the work queue which was
|
||||
* created by spi_bitbang_start.
|
||||
*/
|
||||
static int __devexit davinci_spi_remove(struct platform_device *pdev)
|
||||
static int davinci_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_spi *dspi;
|
||||
struct spi_master *master;
|
||||
@ -980,7 +980,7 @@ static struct platform_driver davinci_spi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = davinci_spi_probe,
|
||||
.remove = __devexit_p(davinci_spi_remove),
|
||||
.remove = davinci_spi_remove,
|
||||
};
|
||||
module_platform_driver(davinci_spi_driver);
|
||||
|
||||
|
@ -26,7 +26,7 @@ struct dw_spi_mmio {
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
|
||||
static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_spi_mmio *dwsmmio;
|
||||
struct dw_spi *dws;
|
||||
@ -106,7 +106,7 @@ err_end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
|
||||
static int dw_spi_mmio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
|
||||
struct resource *mem;
|
||||
@ -129,7 +129,7 @@ static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver dw_spi_mmio_driver = {
|
||||
.probe = dw_spi_mmio_probe,
|
||||
.remove = __devexit_p(dw_spi_mmio_remove),
|
||||
.remove = dw_spi_mmio_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -32,7 +32,7 @@ struct dw_spi_pci {
|
||||
struct dw_spi dws;
|
||||
};
|
||||
|
||||
static int __devinit spi_pci_probe(struct pci_dev *pdev,
|
||||
static int spi_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct dw_spi_pci *dwpci;
|
||||
@ -105,7 +105,7 @@ err_disable:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit spi_pci_remove(struct pci_dev *pdev)
|
||||
static void spi_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
|
||||
|
||||
@ -159,7 +159,7 @@ static struct pci_driver dw_spi_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pci_ids,
|
||||
.probe = spi_pci_probe,
|
||||
.remove = __devexit_p(spi_pci_remove),
|
||||
.remove = spi_pci_remove,
|
||||
.suspend = spi_suspend,
|
||||
.resume = spi_resume,
|
||||
};
|
||||
|
@ -696,7 +696,7 @@ static void dw_spi_cleanup(struct spi_device *spi)
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
static int __devinit init_queue(struct dw_spi *dws)
|
||||
static int init_queue(struct dw_spi *dws)
|
||||
{
|
||||
INIT_LIST_HEAD(&dws->queue);
|
||||
spin_lock_init(&dws->lock);
|
||||
@ -795,7 +795,7 @@ static void spi_hw_init(struct dw_spi *dws)
|
||||
}
|
||||
}
|
||||
|
||||
int __devinit dw_spi_add_host(struct dw_spi *dws)
|
||||
int dw_spi_add_host(struct dw_spi *dws)
|
||||
{
|
||||
struct spi_master *master;
|
||||
int ret;
|
||||
@ -877,7 +877,7 @@ exit:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_spi_add_host);
|
||||
|
||||
void __devexit dw_spi_remove_host(struct dw_spi *dws)
|
||||
void dw_spi_remove_host(struct dw_spi *dws)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
|
@ -1023,7 +1023,7 @@ static void ep93xx_spi_release_dma(struct ep93xx_spi *espi)
|
||||
free_page((unsigned long)espi->zeropage);
|
||||
}
|
||||
|
||||
static int __devinit ep93xx_spi_probe(struct platform_device *pdev)
|
||||
static int ep93xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct ep93xx_spi_info *info;
|
||||
@ -1138,7 +1138,7 @@ fail_release_master:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit ep93xx_spi_remove(struct platform_device *pdev)
|
||||
static int ep93xx_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct ep93xx_spi *espi = spi_master_get_devdata(master);
|
||||
@ -1180,7 +1180,7 @@ static struct platform_driver ep93xx_spi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ep93xx_spi_probe,
|
||||
.remove = __devexit_p(ep93xx_spi_remove),
|
||||
.remove = ep93xx_spi_remove,
|
||||
};
|
||||
module_platform_driver(ep93xx_spi_driver);
|
||||
|
||||
|
@ -403,7 +403,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit falcon_sflash_probe(struct platform_device *pdev)
|
||||
static int falcon_sflash_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct falcon_sflash *priv;
|
||||
struct spi_master *master;
|
||||
@ -438,7 +438,7 @@ static int __devinit falcon_sflash_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit falcon_sflash_remove(struct platform_device *pdev)
|
||||
static int falcon_sflash_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct falcon_sflash *priv = platform_get_drvdata(pdev);
|
||||
|
||||
@ -455,7 +455,7 @@ MODULE_DEVICE_TABLE(of, falcon_sflash_match);
|
||||
|
||||
static struct platform_driver falcon_sflash_driver = {
|
||||
.probe = falcon_sflash_probe,
|
||||
.remove = __devexit_p(falcon_sflash_remove),
|
||||
.remove = falcon_sflash_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -587,7 +587,7 @@ static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
|
||||
iounmap(mspi->reg_base);
|
||||
}
|
||||
|
||||
static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
|
||||
static struct spi_master * fsl_espi_probe(struct device *dev,
|
||||
struct resource *mem, unsigned int irq)
|
||||
{
|
||||
struct fsl_spi_platform_data *pdata = dev->platform_data;
|
||||
@ -686,7 +686,7 @@ static int of_fsl_espi_get_chipselects(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit of_fsl_espi_probe(struct platform_device *ofdev)
|
||||
static int of_fsl_espi_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct device *dev = &ofdev->dev;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
@ -725,7 +725,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit of_fsl_espi_remove(struct platform_device *dev)
|
||||
static int of_fsl_espi_remove(struct platform_device *dev)
|
||||
{
|
||||
return mpc8xxx_spi_remove(&dev->dev);
|
||||
}
|
||||
@ -743,7 +743,7 @@ static struct platform_driver fsl_espi_driver = {
|
||||
.of_match_table = of_fsl_espi_match,
|
||||
},
|
||||
.probe = of_fsl_espi_probe,
|
||||
.remove = __devexit_p(of_fsl_espi_remove),
|
||||
.remove = of_fsl_espi_remove,
|
||||
};
|
||||
module_platform_driver(fsl_espi_driver);
|
||||
|
||||
|
@ -169,7 +169,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __devexit mpc8xxx_spi_remove(struct device *dev)
|
||||
int mpc8xxx_spi_remove(struct device *dev)
|
||||
{
|
||||
struct mpc8xxx_spi *mpc8xxx_spi;
|
||||
struct spi_master *master;
|
||||
@ -189,7 +189,7 @@ int __devexit mpc8xxx_spi_remove(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev)
|
||||
int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct device *dev = &ofdev->dev;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
|
@ -843,7 +843,7 @@ static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
|
||||
fsl_spi_cpm_free(mspi);
|
||||
}
|
||||
|
||||
static struct spi_master * __devinit fsl_spi_probe(struct device *dev,
|
||||
static struct spi_master * fsl_spi_probe(struct device *dev,
|
||||
struct resource *mem, unsigned int irq)
|
||||
{
|
||||
struct fsl_spi_platform_data *pdata = dev->platform_data;
|
||||
@ -1041,7 +1041,7 @@ static int of_fsl_spi_free_chipselects(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit of_fsl_spi_probe(struct platform_device *ofdev)
|
||||
static int of_fsl_spi_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct device *dev = &ofdev->dev;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
@ -1081,7 +1081,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit of_fsl_spi_remove(struct platform_device *ofdev)
|
||||
static int of_fsl_spi_remove(struct platform_device *ofdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -1105,7 +1105,7 @@ static struct platform_driver of_fsl_spi_driver = {
|
||||
.of_match_table = of_fsl_spi_match,
|
||||
},
|
||||
.probe = of_fsl_spi_probe,
|
||||
.remove = __devexit_p(of_fsl_spi_remove),
|
||||
.remove = of_fsl_spi_remove,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MPC832x_RDB
|
||||
@ -1116,7 +1116,7 @@ static struct platform_driver of_fsl_spi_driver = {
|
||||
* tree can work with OpenFirmware driver. But for now we support old trees
|
||||
* as well.
|
||||
*/
|
||||
static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
|
||||
static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *mem;
|
||||
int irq;
|
||||
@ -1139,7 +1139,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
|
||||
static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
return mpc8xxx_spi_remove(&pdev->dev);
|
||||
}
|
||||
@ -1147,7 +1147,7 @@ static int __devexit plat_mpc8xxx_spi_remove(struct platform_device *pdev)
|
||||
MODULE_ALIAS("platform:mpc8xxx_spi");
|
||||
static struct platform_driver mpc8xxx_spi_driver = {
|
||||
.probe = plat_mpc8xxx_spi_probe,
|
||||
.remove = __devexit_p(plat_mpc8xxx_spi_remove),
|
||||
.remove = plat_mpc8xxx_spi_remove,
|
||||
.driver = {
|
||||
.name = "mpc8xxx_spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -287,7 +287,7 @@ static void spi_gpio_cleanup(struct spi_device *spi)
|
||||
spi_bitbang_cleanup(spi);
|
||||
}
|
||||
|
||||
static int __devinit spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
|
||||
static int spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
|
||||
{
|
||||
int value;
|
||||
|
||||
@ -301,9 +301,8 @@ static int __devinit spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
|
||||
return value;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label,
|
||||
u16 *res_flags)
|
||||
static int spi_gpio_request(struct spi_gpio_platform_data *pdata,
|
||||
const char *label, u16 *res_flags)
|
||||
{
|
||||
int value;
|
||||
|
||||
@ -392,7 +391,7 @@ static inline int spi_gpio_probe_dt(struct platform_device *pdev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __devinit spi_gpio_probe(struct platform_device *pdev)
|
||||
static int spi_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
int status;
|
||||
struct spi_master *master;
|
||||
@ -485,7 +484,7 @@ gpio_free:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __devexit spi_gpio_remove(struct platform_device *pdev)
|
||||
static int spi_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_gpio *spi_gpio;
|
||||
struct spi_gpio_platform_data *pdata;
|
||||
@ -518,7 +517,7 @@ static struct platform_driver spi_gpio_driver = {
|
||||
.of_match_table = of_match_ptr(spi_gpio_dt_ids),
|
||||
},
|
||||
.probe = spi_gpio_probe,
|
||||
.remove = __devexit_p(spi_gpio_remove),
|
||||
.remove = spi_gpio_remove,
|
||||
};
|
||||
module_platform_driver(spi_gpio_driver);
|
||||
|
||||
|
@ -750,7 +750,7 @@ static void spi_imx_cleanup(struct spi_device *spi)
|
||||
{
|
||||
}
|
||||
|
||||
static int __devinit spi_imx_probe(struct platform_device *pdev)
|
||||
static int spi_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *of_id =
|
||||
@ -906,7 +906,7 @@ out_gpio_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit spi_imx_remove(struct platform_device *pdev)
|
||||
static int spi_imx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@ -942,7 +942,7 @@ static struct platform_driver spi_imx_driver = {
|
||||
},
|
||||
.id_table = spi_imx_devtype,
|
||||
.probe = spi_imx_probe,
|
||||
.remove = __devexit_p(spi_imx_remove),
|
||||
.remove = spi_imx_remove,
|
||||
};
|
||||
module_platform_driver(spi_imx_driver);
|
||||
|
||||
|
@ -406,7 +406,7 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/* bus_num is used only for the case dev->platform_data == NULL */
|
||||
static int __devinit mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
||||
static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
||||
u32 size, unsigned int irq,
|
||||
s16 bus_num)
|
||||
{
|
||||
@ -492,7 +492,7 @@ free_master:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit mpc512x_psc_spi_do_remove(struct device *dev)
|
||||
static int mpc512x_psc_spi_do_remove(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
||||
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
|
||||
@ -508,7 +508,7 @@ static int __devexit mpc512x_psc_spi_do_remove(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit mpc512x_psc_spi_of_probe(struct platform_device *op)
|
||||
static int mpc512x_psc_spi_of_probe(struct platform_device *op)
|
||||
{
|
||||
const u32 *regaddr_p;
|
||||
u64 regaddr64, size64;
|
||||
@ -539,7 +539,7 @@ static int __devinit mpc512x_psc_spi_of_probe(struct platform_device *op)
|
||||
irq_of_parse_and_map(op->dev.of_node, 0), id);
|
||||
}
|
||||
|
||||
static int __devexit mpc512x_psc_spi_of_remove(struct platform_device *op)
|
||||
static int mpc512x_psc_spi_of_remove(struct platform_device *op)
|
||||
{
|
||||
return mpc512x_psc_spi_do_remove(&op->dev);
|
||||
}
|
||||
@ -553,7 +553,7 @@ MODULE_DEVICE_TABLE(of, mpc512x_psc_spi_of_match);
|
||||
|
||||
static struct platform_driver mpc512x_psc_spi_of_driver = {
|
||||
.probe = mpc512x_psc_spi_of_probe,
|
||||
.remove = __devexit_p(mpc512x_psc_spi_of_remove),
|
||||
.remove = mpc512x_psc_spi_of_remove,
|
||||
.driver = {
|
||||
.name = "mpc512x-psc-spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -363,7 +363,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/* bus_num is used only for the case dev->platform_data == NULL */
|
||||
static int __devinit mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
||||
static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
||||
u32 size, unsigned int irq, s16 bus_num)
|
||||
{
|
||||
struct fsl_spi_platform_data *pdata = dev->platform_data;
|
||||
@ -450,7 +450,7 @@ free_master:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op)
|
||||
static int mpc52xx_psc_spi_of_probe(struct platform_device *op)
|
||||
{
|
||||
const u32 *regaddr_p;
|
||||
u64 regaddr64, size64;
|
||||
@ -479,7 +479,7 @@ static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op)
|
||||
irq_of_parse_and_map(op->dev.of_node, 0), id);
|
||||
}
|
||||
|
||||
static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op)
|
||||
static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
|
||||
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
|
||||
@ -505,7 +505,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
|
||||
|
||||
static struct platform_driver mpc52xx_psc_spi_of_driver = {
|
||||
.probe = mpc52xx_psc_spi_of_probe,
|
||||
.remove = __devexit_p(mpc52xx_psc_spi_of_remove),
|
||||
.remove = mpc52xx_psc_spi_of_remove,
|
||||
.driver = {
|
||||
.name = "mpc52xx-psc-spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -390,7 +390,7 @@ static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||
/*
|
||||
* OF Platform Bus Binding
|
||||
*/
|
||||
static int __devinit mpc52xx_spi_probe(struct platform_device *op)
|
||||
static int mpc52xx_spi_probe(struct platform_device *op)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct mpc52xx_spi *ms;
|
||||
@ -527,7 +527,7 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit mpc52xx_spi_remove(struct platform_device *op)
|
||||
static int mpc52xx_spi_remove(struct platform_device *op)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
|
||||
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
|
||||
@ -547,7 +547,7 @@ static int __devexit mpc52xx_spi_remove(struct platform_device *op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mpc52xx_spi_match[] __devinitconst = {
|
||||
static const struct of_device_id mpc52xx_spi_match[] = {
|
||||
{ .compatible = "fsl,mpc5200-spi", },
|
||||
{}
|
||||
};
|
||||
@ -560,6 +560,6 @@ static struct platform_driver mpc52xx_spi_of_driver = {
|
||||
.of_match_table = mpc52xx_spi_match,
|
||||
},
|
||||
.probe = mpc52xx_spi_probe,
|
||||
.remove = __devexit_p(mpc52xx_spi_remove),
|
||||
.remove = mpc52xx_spi_remove,
|
||||
};
|
||||
module_platform_driver(mpc52xx_spi_of_driver);
|
||||
|
@ -509,7 +509,7 @@ static const struct of_device_id mxs_spi_dt_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mxs_spi_dt_ids);
|
||||
|
||||
static int __devinit mxs_spi_probe(struct platform_device *pdev)
|
||||
static int mxs_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(mxs_spi_dt_ids, &pdev->dev);
|
||||
@ -636,7 +636,7 @@ out_master_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit mxs_spi_remove(struct platform_device *pdev)
|
||||
static int mxs_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct mxs_spi *spi;
|
||||
@ -659,7 +659,7 @@ static int __devexit mxs_spi_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver mxs_spi_driver = {
|
||||
.probe = mxs_spi_probe,
|
||||
.remove = __devexit_p(mxs_spi_remove),
|
||||
.remove = mxs_spi_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -346,7 +346,7 @@ static void nuc900_init_spi(struct nuc900_spi *hw)
|
||||
nuc900_enable_int(hw);
|
||||
}
|
||||
|
||||
static int __devinit nuc900_spi_probe(struct platform_device *pdev)
|
||||
static int nuc900_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct nuc900_spi *hw;
|
||||
struct spi_master *master;
|
||||
@ -453,7 +453,7 @@ err_nomem:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit nuc900_spi_remove(struct platform_device *dev)
|
||||
static int nuc900_spi_remove(struct platform_device *dev)
|
||||
{
|
||||
struct nuc900_spi *hw = platform_get_drvdata(dev);
|
||||
|
||||
@ -477,7 +477,7 @@ static int __devexit nuc900_spi_remove(struct platform_device *dev)
|
||||
|
||||
static struct platform_driver nuc900_spi_driver = {
|
||||
.probe = nuc900_spi_probe,
|
||||
.remove = __devexit_p(nuc900_spi_remove),
|
||||
.remove = nuc900_spi_remove,
|
||||
.driver = {
|
||||
.name = "nuc900-spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -243,7 +243,7 @@ static irqreturn_t tiny_spi_irq(int irq, void *dev)
|
||||
#ifdef CONFIG_OF
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
|
||||
static int tiny_spi_of_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tiny_spi *hw = platform_get_drvdata(pdev);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
@ -277,13 +277,13 @@ static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
#else /* !CONFIG_OF */
|
||||
static int __devinit tiny_spi_of_probe(struct platform_device *pdev)
|
||||
static int tiny_spi_of_probe(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int __devinit tiny_spi_probe(struct platform_device *pdev)
|
||||
static int tiny_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tiny_spi_platform_data *platp = pdev->dev.platform_data;
|
||||
struct tiny_spi *hw;
|
||||
@ -373,7 +373,7 @@ exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit tiny_spi_remove(struct platform_device *pdev)
|
||||
static int tiny_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tiny_spi *hw = platform_get_drvdata(pdev);
|
||||
struct spi_master *master = hw->bitbang.master;
|
||||
@ -399,7 +399,7 @@ MODULE_DEVICE_TABLE(of, tiny_spi_match);
|
||||
|
||||
static struct platform_driver tiny_spi_driver = {
|
||||
.probe = tiny_spi_probe,
|
||||
.remove = __devexit_p(tiny_spi_remove),
|
||||
.remove = tiny_spi_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -266,7 +266,7 @@ static int octeon_spi_nop_transfer_hardware(struct spi_master *master)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit octeon_spi_probe(struct platform_device *pdev)
|
||||
static int octeon_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
struct resource *res_mem;
|
||||
@ -326,7 +326,7 @@ fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit octeon_spi_remove(struct platform_device *pdev)
|
||||
static int octeon_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct octeon_spi *p = platform_get_drvdata(pdev);
|
||||
u64 register_base = p->register_base;
|
||||
@ -352,7 +352,7 @@ static struct platform_driver octeon_spi_driver = {
|
||||
.of_match_table = octeon_spi_match,
|
||||
},
|
||||
.probe = octeon_spi_probe,
|
||||
.remove = __devexit_p(octeon_spi_remove),
|
||||
.remove = octeon_spi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(octeon_spi_driver);
|
||||
|
@ -486,7 +486,7 @@ static int __init omap1_spi100k_reset(struct omap1_spi100k *spi100k)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit omap1_spi100k_probe(struct platform_device *pdev)
|
||||
static int omap1_spi100k_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct omap1_spi100k *spi100k;
|
||||
|
@ -39,7 +39,6 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
@ -130,6 +129,7 @@ struct omap2_mcspi {
|
||||
struct omap2_mcspi_dma *dma_channels;
|
||||
struct device *dev;
|
||||
struct omap2_mcspi_regs ctx;
|
||||
unsigned int pin_dir:1;
|
||||
};
|
||||
|
||||
struct omap2_mcspi_cs {
|
||||
@ -323,19 +323,11 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
unsigned int count;
|
||||
u8 * rx;
|
||||
const u8 * tx;
|
||||
void __iomem *chstat_reg;
|
||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
count = xfer->len;
|
||||
|
||||
rx = xfer->rx_buf;
|
||||
tx = xfer->tx_buf;
|
||||
chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||
|
||||
if (mcspi_dma->dma_tx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
struct scatterlist sg;
|
||||
@ -359,19 +351,6 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
||||
dma_async_issue_pending(mcspi_dma->dma_tx);
|
||||
omap2_mcspi_set_dma_req(spi, 0, 1);
|
||||
|
||||
wait_for_completion(&mcspi_dma->dma_tx_completion);
|
||||
dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
/* for TX_ONLY mode, be sure all words have shifted out */
|
||||
if (rx == NULL) {
|
||||
if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_TXS) < 0)
|
||||
dev_err(&spi->dev, "TXS timed out\n");
|
||||
else if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_EOT) < 0)
|
||||
dev_err(&spi->dev, "EOT timed out\n");
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
@ -492,6 +471,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
struct dma_slave_config cfg;
|
||||
enum dma_slave_buswidth width;
|
||||
unsigned es;
|
||||
void __iomem *chstat_reg;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
@ -526,8 +506,24 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
omap2_mcspi_tx_dma(spi, xfer, cfg);
|
||||
|
||||
if (rx != NULL)
|
||||
return omap2_mcspi_rx_dma(spi, xfer, cfg, es);
|
||||
count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
|
||||
|
||||
if (tx != NULL) {
|
||||
chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||
wait_for_completion(&mcspi_dma->dma_tx_completion);
|
||||
dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
/* for TX_ONLY mode, be sure all words have shifted out */
|
||||
if (rx == NULL) {
|
||||
if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_TXS) < 0)
|
||||
dev_err(&spi->dev, "TXS timed out\n");
|
||||
else if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_EOT) < 0)
|
||||
dev_err(&spi->dev, "EOT timed out\n");
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -765,8 +761,15 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
|
||||
/* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
|
||||
* REVISIT: this controller could support SPI_3WIRE mode.
|
||||
*/
|
||||
l &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
|
||||
l |= OMAP2_MCSPI_CHCONF_DPE0;
|
||||
if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
|
||||
l &= ~OMAP2_MCSPI_CHCONF_IS;
|
||||
l &= ~OMAP2_MCSPI_CHCONF_DPE1;
|
||||
l |= OMAP2_MCSPI_CHCONF_DPE0;
|
||||
} else {
|
||||
l |= OMAP2_MCSPI_CHCONF_IS;
|
||||
l |= OMAP2_MCSPI_CHCONF_DPE1;
|
||||
l &= ~OMAP2_MCSPI_CHCONF_DPE0;
|
||||
}
|
||||
|
||||
/* wordlength */
|
||||
l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
|
||||
@ -1085,7 +1088,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
|
||||
static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
|
||||
{
|
||||
struct spi_master *master = mcspi->master;
|
||||
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
|
||||
@ -1138,7 +1141,7 @@ static const struct of_device_id omap_mcspi_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
|
||||
|
||||
static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
|
||||
static int omap2_mcspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
const struct omap2_mcspi_platform_config *pdata;
|
||||
@ -1167,6 +1170,11 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
|
||||
master->cleanup = omap2_mcspi_cleanup;
|
||||
master->dev.of_node = node;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, master);
|
||||
|
||||
mcspi = spi_master_get_devdata(master);
|
||||
mcspi->master = master;
|
||||
|
||||
match = of_match_device(omap_mcspi_of_match, &pdev->dev);
|
||||
if (match) {
|
||||
u32 num_cs = 1; /* default number of chipselect */
|
||||
@ -1175,19 +1183,17 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
|
||||
of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
|
||||
master->num_chipselect = num_cs;
|
||||
master->bus_num = bus_num++;
|
||||
if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL))
|
||||
mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
|
||||
} else {
|
||||
pdata = pdev->dev.platform_data;
|
||||
master->num_chipselect = pdata->num_cs;
|
||||
if (pdev->id != -1)
|
||||
master->bus_num = pdev->id;
|
||||
mcspi->pin_dir = pdata->pin_dir;
|
||||
}
|
||||
regs_offset = pdata->regs_offset;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, master);
|
||||
|
||||
mcspi = spi_master_get_devdata(master);
|
||||
mcspi->master = master;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (r == NULL) {
|
||||
status = -ENODEV;
|
||||
@ -1272,7 +1278,7 @@ free_master:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
|
||||
static int omap2_mcspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct omap2_mcspi *mcspi;
|
||||
@ -1341,7 +1347,7 @@ static struct platform_driver omap2_mcspi_driver = {
|
||||
.of_match_table = omap_mcspi_of_match,
|
||||
},
|
||||
.probe = omap2_mcspi_probe,
|
||||
.remove = __devexit_p(omap2_mcspi_remove),
|
||||
.remove = omap2_mcspi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(omap2_mcspi_driver);
|
||||
|
@ -32,8 +32,12 @@
|
||||
#define ORION_SPI_DATA_IN_REG 0x0c
|
||||
#define ORION_SPI_INT_CAUSE_REG 0x10
|
||||
|
||||
#define ORION_SPI_MODE_CPOL (1 << 11)
|
||||
#define ORION_SPI_MODE_CPHA (1 << 12)
|
||||
#define ORION_SPI_IF_8_16_BIT_MODE (1 << 5)
|
||||
#define ORION_SPI_CLK_PRESCALE_MASK 0x1F
|
||||
#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \
|
||||
ORION_SPI_MODE_CPHA)
|
||||
|
||||
struct orion_spi {
|
||||
struct spi_master *master;
|
||||
@ -123,6 +127,23 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
orion_spi_mode_set(struct spi_device *spi)
|
||||
{
|
||||
u32 reg;
|
||||
struct orion_spi *orion_spi;
|
||||
|
||||
orion_spi = spi_master_get_devdata(spi->master);
|
||||
|
||||
reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
|
||||
reg &= ~ORION_SPI_MODE_MASK;
|
||||
if (spi->mode & SPI_CPOL)
|
||||
reg |= ORION_SPI_MODE_CPOL;
|
||||
if (spi->mode & SPI_CPHA)
|
||||
reg |= ORION_SPI_MODE_CPHA;
|
||||
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
|
||||
}
|
||||
|
||||
/*
|
||||
* called only when no transfer is active on the bus
|
||||
*/
|
||||
@ -142,6 +163,8 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||
if ((t != NULL) && t->bits_per_word)
|
||||
bits_per_word = t->bits_per_word;
|
||||
|
||||
orion_spi_mode_set(spi);
|
||||
|
||||
rc = orion_spi_baudrate_set(spi, speed);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -399,7 +422,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* we support only mode 0, and no options */
|
||||
master->mode_bits = 0;
|
||||
master->mode_bits = SPI_CPHA | SPI_CPOL;
|
||||
|
||||
master->setup = orion_spi_setup;
|
||||
master->transfer_one_message = orion_spi_transfer_one_message;
|
||||
@ -478,7 +501,7 @@ static int __exit orion_spi_remove(struct platform_device *pdev)
|
||||
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
|
||||
static const struct of_device_id orion_spi_of_match_table[] __devinitdata = {
|
||||
static const struct of_device_id orion_spi_of_match_table[] = {
|
||||
{ .compatible = "marvell,orion-spi", },
|
||||
{}
|
||||
};
|
||||
|
@ -371,6 +371,7 @@ struct pl022 {
|
||||
/* Two optional pin states - default & sleep */
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
struct pinctrl_state *pins_idle;
|
||||
struct pinctrl_state *pins_sleep;
|
||||
struct spi_master *master;
|
||||
struct pl022_ssp_controller *master_info;
|
||||
@ -1088,7 +1089,7 @@ err_alloc_rx_sg:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int __devinit pl022_dma_probe(struct pl022 *pl022)
|
||||
static int pl022_dma_probe(struct pl022 *pl022)
|
||||
{
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
@ -2057,8 +2058,7 @@ pl022_platform_data_dt_get(struct device *dev)
|
||||
return pd;
|
||||
}
|
||||
|
||||
static int __devinit
|
||||
pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
{
|
||||
struct device *dev = &adev->dev;
|
||||
struct pl022_ssp_controller *platform_info = adev->dev.platform_data;
|
||||
@ -2116,6 +2116,11 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
} else
|
||||
dev_err(dev, "could not get default pinstate\n");
|
||||
|
||||
pl022->pins_idle = pinctrl_lookup_state(pl022->pinctrl,
|
||||
PINCTRL_STATE_IDLE);
|
||||
if (IS_ERR(pl022->pins_idle))
|
||||
dev_dbg(dev, "could not get idle pinstate\n");
|
||||
|
||||
pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl,
|
||||
PINCTRL_STATE_SLEEP);
|
||||
if (IS_ERR(pl022->pins_sleep))
|
||||
@ -2246,10 +2251,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
pm_runtime_set_autosuspend_delay(dev,
|
||||
platform_info->autosuspend_delay);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
} else {
|
||||
pm_runtime_put(dev);
|
||||
}
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_spi_register:
|
||||
@ -2270,7 +2274,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __devexit
|
||||
static int
|
||||
pl022_remove(struct amba_device *adev)
|
||||
{
|
||||
struct pl022 *pl022 = amba_get_drvdata(adev);
|
||||
@ -2303,35 +2307,47 @@ pl022_remove(struct amba_device *adev)
|
||||
* the runtime counterparts to handle external resources like
|
||||
* clocks, pins and regulators when going to sleep.
|
||||
*/
|
||||
static void pl022_suspend_resources(struct pl022 *pl022)
|
||||
static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
|
||||
{
|
||||
int ret;
|
||||
struct pinctrl_state *pins_state;
|
||||
|
||||
clk_disable(pl022->clk);
|
||||
|
||||
pins_state = runtime ? pl022->pins_idle : pl022->pins_sleep;
|
||||
/* Optionally let pins go into sleep states */
|
||||
if (!IS_ERR(pl022->pins_sleep)) {
|
||||
ret = pinctrl_select_state(pl022->pinctrl,
|
||||
pl022->pins_sleep);
|
||||
if (!IS_ERR(pins_state)) {
|
||||
ret = pinctrl_select_state(pl022->pinctrl, pins_state);
|
||||
if (ret)
|
||||
dev_err(&pl022->adev->dev,
|
||||
"could not set pins to sleep state\n");
|
||||
dev_err(&pl022->adev->dev, "could not set %s pins\n",
|
||||
runtime ? "idle" : "sleep");
|
||||
}
|
||||
}
|
||||
|
||||
static void pl022_resume_resources(struct pl022 *pl022)
|
||||
static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Optionaly enable pins to be muxed in and configured */
|
||||
/* First go to the default state */
|
||||
if (!IS_ERR(pl022->pins_default)) {
|
||||
ret = pinctrl_select_state(pl022->pinctrl,
|
||||
pl022->pins_default);
|
||||
ret = pinctrl_select_state(pl022->pinctrl, pl022->pins_default);
|
||||
if (ret)
|
||||
dev_err(&pl022->adev->dev,
|
||||
"could not set default pins\n");
|
||||
}
|
||||
|
||||
if (!runtime) {
|
||||
/* Then let's idle the pins until the next transfer happens */
|
||||
if (!IS_ERR(pl022->pins_idle)) {
|
||||
ret = pinctrl_select_state(pl022->pinctrl,
|
||||
pl022->pins_idle);
|
||||
if (ret)
|
||||
dev_err(&pl022->adev->dev,
|
||||
"could not set idle pins\n");
|
||||
}
|
||||
}
|
||||
|
||||
clk_enable(pl022->clk);
|
||||
}
|
||||
#endif
|
||||
@ -2347,7 +2363,9 @@ static int pl022_suspend(struct device *dev)
|
||||
dev_warn(dev, "cannot suspend master\n");
|
||||
return ret;
|
||||
}
|
||||
pl022_suspend_resources(pl022);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
pl022_suspend_resources(pl022, false);
|
||||
|
||||
dev_dbg(dev, "suspended\n");
|
||||
return 0;
|
||||
@ -2358,7 +2376,8 @@ static int pl022_resume(struct device *dev)
|
||||
struct pl022 *pl022 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
pl022_resume_resources(pl022);
|
||||
pl022_resume_resources(pl022, false);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
/* Start the queue running */
|
||||
ret = spi_master_resume(pl022->master);
|
||||
@ -2376,7 +2395,7 @@ static int pl022_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct pl022 *pl022 = dev_get_drvdata(dev);
|
||||
|
||||
pl022_suspend_resources(pl022);
|
||||
pl022_suspend_resources(pl022, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2384,7 +2403,7 @@ static int pl022_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct pl022 *pl022 = dev_get_drvdata(dev);
|
||||
|
||||
pl022_resume_resources(pl022);
|
||||
pl022_resume_resources(pl022, true);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -2464,7 +2483,7 @@ static struct amba_driver pl022_driver = {
|
||||
},
|
||||
.id_table = pl022_ids,
|
||||
.probe = pl022_probe,
|
||||
.remove = __devexit_p(pl022_remove),
|
||||
.remove = pl022_remove,
|
||||
};
|
||||
|
||||
static int __init pl022_init(void)
|
||||
|
@ -51,7 +51,7 @@ void pxa_ssp_free(struct ssp_device *ssp)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pxa_ssp_free);
|
||||
|
||||
static int __devinit ce4100_spi_probe(struct pci_dev *dev,
|
||||
static int ce4100_spi_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int ret;
|
||||
@ -129,7 +129,7 @@ err_nomem:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit ce4100_spi_remove(struct pci_dev *dev)
|
||||
static void ce4100_spi_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct ce4100_info *spi_info;
|
||||
struct ssp_device *ssp;
|
||||
@ -161,7 +161,7 @@ static struct pci_driver ce4100_spi_driver = {
|
||||
.name = "ce4100_spi",
|
||||
.id_table = ce4100_spi_devices,
|
||||
.probe = ce4100_spi_probe,
|
||||
.remove = __devexit_p(ce4100_spi_remove),
|
||||
.remove = ce4100_spi_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(ce4100_spi_driver);
|
||||
|
@ -1438,7 +1438,7 @@ static void cleanup(struct spi_device *spi)
|
||||
kfree(chip);
|
||||
}
|
||||
|
||||
static int __devinit init_queue(struct driver_data *drv_data)
|
||||
static int init_queue(struct driver_data *drv_data)
|
||||
{
|
||||
INIT_LIST_HEAD(&drv_data->queue);
|
||||
spin_lock_init(&drv_data->lock);
|
||||
@ -1526,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
|
||||
static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pxa2xx_spi_master *platform_info;
|
||||
|
@ -661,7 +661,7 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit rspi_request_dma(struct rspi_data *rspi,
|
||||
static int rspi_request_dma(struct rspi_data *rspi,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
|
||||
@ -709,7 +709,7 @@ static int __devinit rspi_request_dma(struct rspi_data *rspi,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit rspi_release_dma(struct rspi_data *rspi)
|
||||
static void rspi_release_dma(struct rspi_data *rspi)
|
||||
{
|
||||
if (rspi->chan_tx)
|
||||
dma_release_channel(rspi->chan_tx);
|
||||
@ -717,7 +717,7 @@ static void __devexit rspi_release_dma(struct rspi_data *rspi)
|
||||
dma_release_channel(rspi->chan_rx);
|
||||
}
|
||||
|
||||
static int __devexit rspi_remove(struct platform_device *pdev)
|
||||
static int rspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rspi_data *rspi = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
@ -731,7 +731,7 @@ static int __devexit rspi_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit rspi_probe(struct platform_device *pdev)
|
||||
static int rspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct spi_master *master;
|
||||
@ -827,7 +827,7 @@ error1:
|
||||
|
||||
static struct platform_driver rspi_driver = {
|
||||
.probe = rspi_probe,
|
||||
.remove = __devexit_p(rspi_remove),
|
||||
.remove = rspi_remove,
|
||||
.driver = {
|
||||
.name = "rspi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -506,7 +506,7 @@ static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit s3c24xx_spi_probe(struct platform_device *pdev)
|
||||
static int s3c24xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c2410_spi_info *pdata;
|
||||
struct s3c24xx_spi *hw;
|
||||
@ -663,7 +663,7 @@ static int __devinit s3c24xx_spi_probe(struct platform_device *pdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit s3c24xx_spi_remove(struct platform_device *dev)
|
||||
static int s3c24xx_spi_remove(struct platform_device *dev)
|
||||
{
|
||||
struct s3c24xx_spi *hw = platform_get_drvdata(dev);
|
||||
|
||||
@ -722,7 +722,7 @@ static const struct dev_pm_ops s3c24xx_spi_pmops = {
|
||||
MODULE_ALIAS("platform:s3c2410-spi");
|
||||
static struct platform_driver s3c24xx_spi_driver = {
|
||||
.probe = s3c24xx_spi_probe,
|
||||
.remove = __devexit_p(s3c24xx_spi_remove),
|
||||
.remove = s3c24xx_spi_remove,
|
||||
.driver = {
|
||||
.name = "s3c2410-spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -516,7 +516,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
||||
|
||||
/* Disable Clock */
|
||||
if (sdd->port_conf->clk_from_cmu) {
|
||||
clk_disable(sdd->src_clk);
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
} else {
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
val &= ~S3C64XX_SPI_ENCLK_ENABLE;
|
||||
@ -564,7 +564,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
||||
/* There is half-multiplier before the SPI */
|
||||
clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
|
||||
/* Enable Clock */
|
||||
clk_enable(sdd->src_clk);
|
||||
clk_prepare_enable(sdd->src_clk);
|
||||
} else {
|
||||
/* Configure Clock */
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
@ -1056,7 +1056,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
|
||||
flush_fifo(sdd);
|
||||
}
|
||||
|
||||
static int __devinit s3c64xx_spi_get_dmares(
|
||||
static int s3c64xx_spi_get_dmares(
|
||||
struct s3c64xx_spi_driver_data *sdd, bool tx)
|
||||
{
|
||||
struct platform_device *pdev = sdd->pdev;
|
||||
@ -1112,7 +1112,7 @@ static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
|
||||
dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio);
|
||||
goto free_gpio;
|
||||
}
|
||||
|
||||
sdd->gpios[idx] = gpio;
|
||||
ret = gpio_request(gpio, "spi-bus");
|
||||
if (ret) {
|
||||
dev_err(dev, "gpio [%d] request failed: %d\n",
|
||||
@ -1135,7 +1135,7 @@ static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
|
||||
gpio_free(sdd->gpios[idx]);
|
||||
}
|
||||
|
||||
static struct __devinit s3c64xx_spi_info * s3c64xx_spi_parse_dt(
|
||||
static struct s3c64xx_spi_info * s3c64xx_spi_parse_dt(
|
||||
struct device *dev)
|
||||
{
|
||||
struct s3c64xx_spi_info *sci;
|
||||
@ -1302,7 +1302,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
||||
goto err3;
|
||||
}
|
||||
|
||||
if (clk_enable(sdd->clk)) {
|
||||
if (clk_prepare_enable(sdd->clk)) {
|
||||
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
|
||||
ret = -EBUSY;
|
||||
goto err4;
|
||||
@ -1317,7 +1317,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
||||
goto err5;
|
||||
}
|
||||
|
||||
if (clk_enable(sdd->src_clk)) {
|
||||
if (clk_prepare_enable(sdd->src_clk)) {
|
||||
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
|
||||
ret = -EBUSY;
|
||||
goto err6;
|
||||
@ -1361,11 +1361,11 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
||||
err8:
|
||||
free_irq(irq, sdd);
|
||||
err7:
|
||||
clk_disable(sdd->src_clk);
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
err6:
|
||||
clk_put(sdd->src_clk);
|
||||
err5:
|
||||
clk_disable(sdd->clk);
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
err4:
|
||||
clk_put(sdd->clk);
|
||||
err3:
|
||||
@ -1393,10 +1393,10 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
|
||||
|
||||
free_irq(platform_get_irq(pdev, 0), sdd);
|
||||
|
||||
clk_disable(sdd->src_clk);
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
clk_put(sdd->src_clk);
|
||||
|
||||
clk_disable(sdd->clk);
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
clk_put(sdd->clk);
|
||||
|
||||
if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
|
||||
@ -1417,8 +1417,8 @@ static int s3c64xx_spi_suspend(struct device *dev)
|
||||
spi_master_suspend(master);
|
||||
|
||||
/* Disable the clock */
|
||||
clk_disable(sdd->src_clk);
|
||||
clk_disable(sdd->clk);
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
|
||||
if (!sdd->cntrlr_info->cfg_gpio && dev->of_node)
|
||||
s3c64xx_spi_dt_gpio_free(sdd);
|
||||
@ -1440,8 +1440,8 @@ static int s3c64xx_spi_resume(struct device *dev)
|
||||
sci->cfg_gpio();
|
||||
|
||||
/* Enable the clock */
|
||||
clk_enable(sdd->src_clk);
|
||||
clk_enable(sdd->clk);
|
||||
clk_prepare_enable(sdd->src_clk);
|
||||
clk_prepare_enable(sdd->clk);
|
||||
|
||||
s3c64xx_spi_hwinit(sdd, sdd->port_id);
|
||||
|
||||
@ -1457,8 +1457,8 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||
|
||||
clk_disable(sdd->clk);
|
||||
clk_disable(sdd->src_clk);
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1468,8 +1468,8 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||
|
||||
clk_enable(sdd->src_clk);
|
||||
clk_enable(sdd->clk);
|
||||
clk_prepare_enable(sdd->src_clk);
|
||||
clk_prepare_enable(sdd->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -68,6 +68,16 @@ static u32 hspi_read(struct hspi_priv *hspi, int reg)
|
||||
return ioread32(hspi->addr + reg);
|
||||
}
|
||||
|
||||
static void hspi_bit_set(struct hspi_priv *hspi, int reg, u32 mask, u32 set)
|
||||
{
|
||||
u32 val = hspi_read(hspi, reg);
|
||||
|
||||
val &= ~mask;
|
||||
val |= set & mask;
|
||||
|
||||
hspi_write(hspi, reg, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* transfer function
|
||||
*/
|
||||
@ -105,6 +115,13 @@ static int hspi_unprepare_transfer(struct spi_master *master)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0)
|
||||
#define hspi_hw_cs_disable(hspi) hspi_hw_cs_ctrl(hspi, 1)
|
||||
static void hspi_hw_cs_ctrl(struct hspi_priv *hspi, int hi)
|
||||
{
|
||||
hspi_bit_set(hspi, SPSCR, (1 << 6), (hi) << 6);
|
||||
}
|
||||
|
||||
static void hspi_hw_setup(struct hspi_priv *hspi,
|
||||
struct spi_message *msg,
|
||||
struct spi_transfer *t)
|
||||
@ -155,7 +172,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
|
||||
|
||||
hspi_write(hspi, SPCR, spcr);
|
||||
hspi_write(hspi, SPSR, 0x0);
|
||||
hspi_write(hspi, SPSCR, 0x1); /* master mode */
|
||||
hspi_write(hspi, SPSCR, 0x21); /* master mode / CS control */
|
||||
}
|
||||
|
||||
static int hspi_transfer_one_message(struct spi_master *master,
|
||||
@ -166,12 +183,21 @@ static int hspi_transfer_one_message(struct spi_master *master,
|
||||
u32 tx;
|
||||
u32 rx;
|
||||
int ret, i;
|
||||
unsigned int cs_change;
|
||||
const int nsecs = 50;
|
||||
|
||||
dev_dbg(hspi->dev, "%s\n", __func__);
|
||||
|
||||
cs_change = 1;
|
||||
ret = 0;
|
||||
list_for_each_entry(t, &msg->transfers, transfer_list) {
|
||||
hspi_hw_setup(hspi, msg, t);
|
||||
|
||||
if (cs_change) {
|
||||
hspi_hw_setup(hspi, msg, t);
|
||||
hspi_hw_cs_enable(hspi);
|
||||
ndelay(nsecs);
|
||||
}
|
||||
cs_change = t->cs_change;
|
||||
|
||||
for (i = 0; i < t->len; i++) {
|
||||
|
||||
@ -198,9 +224,22 @@ static int hspi_transfer_one_message(struct spi_master *master,
|
||||
}
|
||||
|
||||
msg->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
|
||||
if (cs_change) {
|
||||
ndelay(nsecs);
|
||||
hspi_hw_cs_disable(hspi);
|
||||
ndelay(nsecs);
|
||||
}
|
||||
}
|
||||
|
||||
msg->status = ret;
|
||||
if (!cs_change) {
|
||||
ndelay(nsecs);
|
||||
hspi_hw_cs_disable(hspi);
|
||||
}
|
||||
spi_finalize_current_message(master);
|
||||
|
||||
return ret;
|
||||
@ -229,7 +268,7 @@ static void hspi_cleanup(struct spi_device *spi)
|
||||
dev_dbg(dev, "%s cleanup\n", spi->modalias);
|
||||
}
|
||||
|
||||
static int __devinit hspi_probe(struct platform_device *pdev)
|
||||
static int hspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct spi_master *master;
|
||||
@ -300,7 +339,7 @@ static int __devinit hspi_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit hspi_remove(struct platform_device *pdev)
|
||||
static int hspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
@ -314,7 +353,7 @@ static int __devexit hspi_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver hspi_driver = {
|
||||
.probe = hspi_probe,
|
||||
.remove = __devexit_p(hspi_remove),
|
||||
.remove = hspi_remove,
|
||||
.driver = {
|
||||
.name = "sh-hspi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -597,7 +597,6 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
|
||||
struct resource *r;
|
||||
struct spi_master *master;
|
||||
struct sh_msiof_spi_priv *p;
|
||||
char clk_name[16];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
@ -614,10 +613,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
|
||||
p->info = pdev->dev.platform_data;
|
||||
init_completion(&p->done);
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "msiof%d", pdev->id);
|
||||
p->clk = clk_get(&pdev->dev, clk_name);
|
||||
p->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(p->clk)) {
|
||||
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
|
||||
dev_err(&pdev->dev, "cannot get clock\n");
|
||||
ret = PTR_ERR(p->clk);
|
||||
goto err1;
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ static irqreturn_t spi_sh_irq(int irq, void *_ss)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devexit spi_sh_remove(struct platform_device *pdev)
|
||||
static int spi_sh_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
@ -444,7 +444,7 @@ static int __devexit spi_sh_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit spi_sh_probe(struct platform_device *pdev)
|
||||
static int spi_sh_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct spi_master *master;
|
||||
@ -539,7 +539,7 @@ static int __devinit spi_sh_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver spi_sh_driver = {
|
||||
.probe = spi_sh_probe,
|
||||
.remove = __devexit_p(spi_sh_remove),
|
||||
.remove = spi_sh_remove,
|
||||
.driver = {
|
||||
.name = "sh_spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -479,7 +479,7 @@ static int spi_sirfsoc_setup(struct spi_device *spi)
|
||||
return spi_sirfsoc_setup_transfer(spi, NULL);
|
||||
}
|
||||
|
||||
static int __devinit spi_sirfsoc_probe(struct platform_device *pdev)
|
||||
static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sirfsoc_spi *sspi;
|
||||
struct spi_master *master;
|
||||
@ -604,7 +604,7 @@ err_cs:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit spi_sirfsoc_remove(struct platform_device *pdev)
|
||||
static int spi_sirfsoc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct sirfsoc_spi *sspi;
|
||||
@ -673,7 +673,7 @@ static struct platform_driver spi_sirfsoc_driver = {
|
||||
.of_match_table = spi_sirfsoc_of_match,
|
||||
},
|
||||
.probe = spi_sirfsoc_probe,
|
||||
.remove = __devexit_p(spi_sirfsoc_remove),
|
||||
.remove = spi_sirfsoc_remove,
|
||||
};
|
||||
module_platform_driver(spi_sirfsoc_driver);
|
||||
|
||||
|
@ -1,664 +0,0 @@
|
||||
/*
|
||||
* Freescale STMP378X SPI master driver
|
||||
*
|
||||
* Author: dmitry pervushin <dimka@embeddedalley.com>
|
||||
*
|
||||
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <mach/platform.h>
|
||||
#include <mach/stmp3xxx.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/regs-ssp.h>
|
||||
#include <mach/regs-apbh.h>
|
||||
|
||||
|
||||
/* 0 means DMA mode(recommended, default), !0 - PIO mode */
|
||||
static int pio;
|
||||
static int clock;
|
||||
|
||||
/* default timeout for busy waits is 2 seconds */
|
||||
#define STMP_SPI_TIMEOUT (2 * HZ)
|
||||
|
||||
struct stmp_spi {
|
||||
int id;
|
||||
|
||||
void * __iomem regs; /* vaddr of the control registers */
|
||||
|
||||
int irq, err_irq;
|
||||
u32 dma;
|
||||
struct stmp3xxx_dma_descriptor d;
|
||||
|
||||
u32 speed_khz;
|
||||
u32 saved_timings;
|
||||
u32 divider;
|
||||
|
||||
struct clk *clk;
|
||||
struct device *master_dev;
|
||||
|
||||
struct work_struct work;
|
||||
struct workqueue_struct *workqueue;
|
||||
|
||||
/* lock protects queue access */
|
||||
spinlock_t lock;
|
||||
struct list_head queue;
|
||||
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
#define busy_wait(cond) \
|
||||
({ \
|
||||
unsigned long end_jiffies = jiffies + STMP_SPI_TIMEOUT; \
|
||||
bool succeeded = false; \
|
||||
do { \
|
||||
if (cond) { \
|
||||
succeeded = true; \
|
||||
break; \
|
||||
} \
|
||||
cpu_relax(); \
|
||||
} while (time_before(jiffies, end_jiffies)); \
|
||||
succeeded; \
|
||||
})
|
||||
|
||||
/**
|
||||
* stmp_spi_init_hw
|
||||
* Initialize the SSP port
|
||||
*/
|
||||
static int stmp_spi_init_hw(struct stmp_spi *ss)
|
||||
{
|
||||
int err = 0;
|
||||
void *pins = ss->master_dev->platform_data;
|
||||
|
||||
err = stmp3xxx_request_pin_group(pins, dev_name(ss->master_dev));
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
ss->clk = clk_get(NULL, "ssp");
|
||||
if (IS_ERR(ss->clk)) {
|
||||
err = PTR_ERR(ss->clk);
|
||||
goto out_free_pins;
|
||||
}
|
||||
clk_enable(ss->clk);
|
||||
|
||||
stmp3xxx_reset_block(ss->regs, false);
|
||||
stmp3xxx_dma_reset_channel(ss->dma);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_pins:
|
||||
stmp3xxx_release_pin_group(pins, dev_name(ss->master_dev));
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void stmp_spi_release_hw(struct stmp_spi *ss)
|
||||
{
|
||||
void *pins = ss->master_dev->platform_data;
|
||||
|
||||
if (ss->clk && !IS_ERR(ss->clk)) {
|
||||
clk_disable(ss->clk);
|
||||
clk_put(ss->clk);
|
||||
}
|
||||
stmp3xxx_release_pin_group(pins, dev_name(ss->master_dev));
|
||||
}
|
||||
|
||||
static int stmp_spi_setup_transfer(struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
{
|
||||
u8 bits_per_word;
|
||||
u32 hz;
|
||||
struct stmp_spi *ss = spi_master_get_devdata(spi->master);
|
||||
u16 rate;
|
||||
|
||||
bits_per_word = spi->bits_per_word;
|
||||
if (t && t->bits_per_word)
|
||||
bits_per_word = t->bits_per_word;
|
||||
|
||||
/*
|
||||
* Calculate speed:
|
||||
* - by default, use maximum speed from ssp clk
|
||||
* - if device overrides it, use it
|
||||
* - if transfer specifies other speed, use transfer's one
|
||||
*/
|
||||
hz = 1000 * ss->speed_khz / ss->divider;
|
||||
if (spi->max_speed_hz)
|
||||
hz = min(hz, spi->max_speed_hz);
|
||||
if (t && t->speed_hz)
|
||||
hz = min(hz, t->speed_hz);
|
||||
|
||||
if (hz == 0) {
|
||||
dev_err(&spi->dev, "Cannot continue with zero clock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bits_per_word != 8) {
|
||||
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
|
||||
__func__, bits_per_word);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&spi->dev, "Requested clk rate = %uHz, max = %uHz/%d = %uHz\n",
|
||||
hz, ss->speed_khz, ss->divider,
|
||||
ss->speed_khz * 1000 / ss->divider);
|
||||
|
||||
if (ss->speed_khz * 1000 / ss->divider < hz) {
|
||||
dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
|
||||
__func__, hz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rate = 1000 * ss->speed_khz/ss->divider/hz;
|
||||
|
||||
writel(BF(ss->divider, SSP_TIMING_CLOCK_DIVIDE) |
|
||||
BF(rate - 1, SSP_TIMING_CLOCK_RATE),
|
||||
HW_SSP_TIMING + ss->regs);
|
||||
|
||||
writel(BF(1 /* mode SPI */, SSP_CTRL1_SSP_MODE) |
|
||||
BF(4 /* 8 bits */, SSP_CTRL1_WORD_LENGTH) |
|
||||
((spi->mode & SPI_CPOL) ? BM_SSP_CTRL1_POLARITY : 0) |
|
||||
((spi->mode & SPI_CPHA) ? BM_SSP_CTRL1_PHASE : 0) |
|
||||
(pio ? 0 : BM_SSP_CTRL1_DMA_ENABLE),
|
||||
ss->regs + HW_SSP_CTRL1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmp_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
/* spi_setup() does basic checks,
|
||||
* stmp_spi_setup_transfer() does more later
|
||||
*/
|
||||
if (spi->bits_per_word != 8) {
|
||||
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
|
||||
__func__, spi->bits_per_word);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 stmp_spi_cs(unsigned cs)
|
||||
{
|
||||
return ((cs & 1) ? BM_SSP_CTRL0_WAIT_FOR_CMD : 0) |
|
||||
((cs & 2) ? BM_SSP_CTRL0_WAIT_FOR_IRQ : 0);
|
||||
}
|
||||
|
||||
static int stmp_spi_txrx_dma(struct stmp_spi *ss, int cs,
|
||||
unsigned char *buf, dma_addr_t dma_buf, int len,
|
||||
int first, int last, bool write)
|
||||
{
|
||||
u32 c0 = 0;
|
||||
dma_addr_t spi_buf_dma = dma_buf;
|
||||
int status = 0;
|
||||
enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
|
||||
c0 |= (first ? BM_SSP_CTRL0_LOCK_CS : 0);
|
||||
c0 |= (last ? BM_SSP_CTRL0_IGNORE_CRC : 0);
|
||||
c0 |= (write ? 0 : BM_SSP_CTRL0_READ);
|
||||
c0 |= BM_SSP_CTRL0_DATA_XFER;
|
||||
|
||||
c0 |= stmp_spi_cs(cs);
|
||||
|
||||
c0 |= BF(len, SSP_CTRL0_XFER_COUNT);
|
||||
|
||||
if (!dma_buf)
|
||||
spi_buf_dma = dma_map_single(ss->master_dev, buf, len, dir);
|
||||
|
||||
ss->d.command->cmd =
|
||||
BF(len, APBH_CHn_CMD_XFER_COUNT) |
|
||||
BF(1, APBH_CHn_CMD_CMDWORDS) |
|
||||
BM_APBH_CHn_CMD_WAIT4ENDCMD |
|
||||
BM_APBH_CHn_CMD_IRQONCMPLT |
|
||||
BF(write ? BV_APBH_CHn_CMD_COMMAND__DMA_READ :
|
||||
BV_APBH_CHn_CMD_COMMAND__DMA_WRITE,
|
||||
APBH_CHn_CMD_COMMAND);
|
||||
ss->d.command->pio_words[0] = c0;
|
||||
ss->d.command->buf_ptr = spi_buf_dma;
|
||||
|
||||
stmp3xxx_dma_reset_channel(ss->dma);
|
||||
stmp3xxx_dma_clear_interrupt(ss->dma);
|
||||
stmp3xxx_dma_enable_interrupt(ss->dma);
|
||||
init_completion(&ss->done);
|
||||
stmp3xxx_dma_go(ss->dma, &ss->d, 1);
|
||||
wait_for_completion(&ss->done);
|
||||
|
||||
if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) & BM_SSP_CTRL0_RUN))
|
||||
status = -ETIMEDOUT;
|
||||
|
||||
if (!dma_buf)
|
||||
dma_unmap_single(ss->master_dev, spi_buf_dma, len, dir);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static inline void stmp_spi_enable(struct stmp_spi *ss)
|
||||
{
|
||||
stmp3xxx_setl(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0);
|
||||
stmp3xxx_clearl(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0);
|
||||
}
|
||||
|
||||
static inline void stmp_spi_disable(struct stmp_spi *ss)
|
||||
{
|
||||
stmp3xxx_clearl(BM_SSP_CTRL0_LOCK_CS, ss->regs + HW_SSP_CTRL0);
|
||||
stmp3xxx_setl(BM_SSP_CTRL0_IGNORE_CRC, ss->regs + HW_SSP_CTRL0);
|
||||
}
|
||||
|
||||
static int stmp_spi_txrx_pio(struct stmp_spi *ss, int cs,
|
||||
unsigned char *buf, int len,
|
||||
bool first, bool last, bool write)
|
||||
{
|
||||
if (first)
|
||||
stmp_spi_enable(ss);
|
||||
|
||||
stmp3xxx_setl(stmp_spi_cs(cs), ss->regs + HW_SSP_CTRL0);
|
||||
|
||||
while (len--) {
|
||||
if (last && len <= 0)
|
||||
stmp_spi_disable(ss);
|
||||
|
||||
stmp3xxx_clearl(BM_SSP_CTRL0_XFER_COUNT,
|
||||
ss->regs + HW_SSP_CTRL0);
|
||||
stmp3xxx_setl(1, ss->regs + HW_SSP_CTRL0);
|
||||
|
||||
if (write)
|
||||
stmp3xxx_clearl(BM_SSP_CTRL0_READ,
|
||||
ss->regs + HW_SSP_CTRL0);
|
||||
else
|
||||
stmp3xxx_setl(BM_SSP_CTRL0_READ,
|
||||
ss->regs + HW_SSP_CTRL0);
|
||||
|
||||
/* Run! */
|
||||
stmp3xxx_setl(BM_SSP_CTRL0_RUN, ss->regs + HW_SSP_CTRL0);
|
||||
|
||||
if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) &
|
||||
BM_SSP_CTRL0_RUN))
|
||||
break;
|
||||
|
||||
if (write)
|
||||
writel(*buf, ss->regs + HW_SSP_DATA);
|
||||
|
||||
/* Set TRANSFER */
|
||||
stmp3xxx_setl(BM_SSP_CTRL0_DATA_XFER, ss->regs + HW_SSP_CTRL0);
|
||||
|
||||
if (!write) {
|
||||
if (busy_wait((readl(ss->regs + HW_SSP_STATUS) &
|
||||
BM_SSP_STATUS_FIFO_EMPTY)))
|
||||
break;
|
||||
*buf = readl(ss->regs + HW_SSP_DATA) & 0xFF;
|
||||
}
|
||||
|
||||
if (!busy_wait(readl(ss->regs + HW_SSP_CTRL0) &
|
||||
BM_SSP_CTRL0_RUN))
|
||||
break;
|
||||
|
||||
/* advance to the next byte */
|
||||
buf++;
|
||||
}
|
||||
|
||||
return len < 0 ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int stmp_spi_handle_message(struct stmp_spi *ss, struct spi_message *m)
|
||||
{
|
||||
bool first, last;
|
||||
struct spi_transfer *t, *tmp_t;
|
||||
int status = 0;
|
||||
int cs;
|
||||
|
||||
cs = m->spi->chip_select;
|
||||
|
||||
list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
|
||||
|
||||
first = (&t->transfer_list == m->transfers.next);
|
||||
last = (&t->transfer_list == m->transfers.prev);
|
||||
|
||||
if (first || t->speed_hz || t->bits_per_word)
|
||||
stmp_spi_setup_transfer(m->spi, t);
|
||||
|
||||
/* reject "not last" transfers which request to change cs */
|
||||
if (t->cs_change && !last) {
|
||||
dev_err(&m->spi->dev,
|
||||
"Message with t->cs_change has been skipped\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t->tx_buf) {
|
||||
status = pio ?
|
||||
stmp_spi_txrx_pio(ss, cs, (void *)t->tx_buf,
|
||||
t->len, first, last, true) :
|
||||
stmp_spi_txrx_dma(ss, cs, (void *)t->tx_buf,
|
||||
t->tx_dma, t->len, first, last, true);
|
||||
#ifdef DEBUG
|
||||
if (t->len < 0x10)
|
||||
print_hex_dump_bytes("Tx ",
|
||||
DUMP_PREFIX_OFFSET,
|
||||
t->tx_buf, t->len);
|
||||
else
|
||||
pr_debug("Tx: %d bytes\n", t->len);
|
||||
#endif
|
||||
}
|
||||
if (t->rx_buf) {
|
||||
status = pio ?
|
||||
stmp_spi_txrx_pio(ss, cs, t->rx_buf,
|
||||
t->len, first, last, false) :
|
||||
stmp_spi_txrx_dma(ss, cs, t->rx_buf,
|
||||
t->rx_dma, t->len, first, last, false);
|
||||
#ifdef DEBUG
|
||||
if (t->len < 0x10)
|
||||
print_hex_dump_bytes("Rx ",
|
||||
DUMP_PREFIX_OFFSET,
|
||||
t->rx_buf, t->len);
|
||||
else
|
||||
pr_debug("Rx: %d bytes\n", t->len);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
|
||||
if (status)
|
||||
break;
|
||||
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmp_spi_handle - handle messages from the queue
|
||||
*/
|
||||
static void stmp_spi_handle(struct work_struct *w)
|
||||
{
|
||||
struct stmp_spi *ss = container_of(w, struct stmp_spi, work);
|
||||
unsigned long flags;
|
||||
struct spi_message *m;
|
||||
|
||||
spin_lock_irqsave(&ss->lock, flags);
|
||||
while (!list_empty(&ss->queue)) {
|
||||
m = list_entry(ss->queue.next, struct spi_message, queue);
|
||||
list_del_init(&m->queue);
|
||||
spin_unlock_irqrestore(&ss->lock, flags);
|
||||
|
||||
m->status = stmp_spi_handle_message(ss, m);
|
||||
m->complete(m->context);
|
||||
|
||||
spin_lock_irqsave(&ss->lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&ss->lock, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmp_spi_transfer - perform message transfer.
|
||||
* Called indirectly from spi_async, queues all the messages to
|
||||
* spi_handle_message.
|
||||
* @spi: spi device
|
||||
* @m: message to be queued
|
||||
*/
|
||||
static int stmp_spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||
{
|
||||
struct stmp_spi *ss = spi_master_get_devdata(spi->master);
|
||||
unsigned long flags;
|
||||
|
||||
m->status = -EINPROGRESS;
|
||||
spin_lock_irqsave(&ss->lock, flags);
|
||||
list_add_tail(&m->queue, &ss->queue);
|
||||
queue_work(ss->workqueue, &ss->work);
|
||||
spin_unlock_irqrestore(&ss->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t stmp_spi_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct stmp_spi *ss = dev_id;
|
||||
|
||||
stmp3xxx_dma_clear_interrupt(ss->dma);
|
||||
complete(&ss->done);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t stmp_spi_irq_err(int irq, void *dev_id)
|
||||
{
|
||||
struct stmp_spi *ss = dev_id;
|
||||
u32 c1, st;
|
||||
|
||||
c1 = readl(ss->regs + HW_SSP_CTRL1);
|
||||
st = readl(ss->regs + HW_SSP_STATUS);
|
||||
dev_err(ss->master_dev, "%s: status = 0x%08X, c1 = 0x%08X\n",
|
||||
__func__, st, c1);
|
||||
stmp3xxx_clearl(c1 & 0xCCCC0000, ss->regs + HW_SSP_CTRL1);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit stmp_spi_probe(struct platform_device *dev)
|
||||
{
|
||||
int err = 0;
|
||||
struct spi_master *master;
|
||||
struct stmp_spi *ss;
|
||||
struct resource *r;
|
||||
|
||||
master = spi_alloc_master(&dev->dev, sizeof(struct stmp_spi));
|
||||
if (master == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto out0;
|
||||
}
|
||||
master->flags = SPI_MASTER_HALF_DUPLEX;
|
||||
|
||||
ss = spi_master_get_devdata(master);
|
||||
platform_set_drvdata(dev, master);
|
||||
|
||||
/* Get resources(memory, IRQ) associated with the device */
|
||||
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (r == NULL) {
|
||||
err = -ENODEV;
|
||||
goto out_put_master;
|
||||
}
|
||||
ss->regs = ioremap(r->start, resource_size(r));
|
||||
if (!ss->regs) {
|
||||
err = -EINVAL;
|
||||
goto out_put_master;
|
||||
}
|
||||
|
||||
ss->master_dev = &dev->dev;
|
||||
ss->id = dev->id;
|
||||
|
||||
INIT_WORK(&ss->work, stmp_spi_handle);
|
||||
INIT_LIST_HEAD(&ss->queue);
|
||||
spin_lock_init(&ss->lock);
|
||||
|
||||
ss->workqueue = create_singlethread_workqueue(dev_name(&dev->dev));
|
||||
if (!ss->workqueue) {
|
||||
err = -ENXIO;
|
||||
goto out_put_master;
|
||||
}
|
||||
master->transfer = stmp_spi_transfer;
|
||||
master->setup = stmp_spi_setup;
|
||||
|
||||
/* the spi->mode bits understood by this driver: */
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||
|
||||
ss->irq = platform_get_irq(dev, 0);
|
||||
if (ss->irq < 0) {
|
||||
err = ss->irq;
|
||||
goto out_put_master;
|
||||
}
|
||||
ss->err_irq = platform_get_irq(dev, 1);
|
||||
if (ss->err_irq < 0) {
|
||||
err = ss->err_irq;
|
||||
goto out_put_master;
|
||||
}
|
||||
|
||||
r = platform_get_resource(dev, IORESOURCE_DMA, 0);
|
||||
if (r == NULL) {
|
||||
err = -ENODEV;
|
||||
goto out_put_master;
|
||||
}
|
||||
|
||||
ss->dma = r->start;
|
||||
err = stmp3xxx_dma_request(ss->dma, &dev->dev, dev_name(&dev->dev));
|
||||
if (err)
|
||||
goto out_put_master;
|
||||
|
||||
err = stmp3xxx_dma_allocate_command(ss->dma, &ss->d);
|
||||
if (err)
|
||||
goto out_free_dma;
|
||||
|
||||
master->bus_num = dev->id;
|
||||
master->num_chipselect = 1;
|
||||
|
||||
/* SPI controller initializations */
|
||||
err = stmp_spi_init_hw(ss);
|
||||
if (err) {
|
||||
dev_dbg(&dev->dev, "cannot initialize hardware\n");
|
||||
goto out_free_dma_desc;
|
||||
}
|
||||
|
||||
if (clock) {
|
||||
dev_info(&dev->dev, "clock rate forced to %d\n", clock);
|
||||
clk_set_rate(ss->clk, clock);
|
||||
}
|
||||
ss->speed_khz = clk_get_rate(ss->clk);
|
||||
ss->divider = 2;
|
||||
dev_info(&dev->dev, "max possible speed %d = %ld/%d kHz\n",
|
||||
ss->speed_khz, clk_get_rate(ss->clk), ss->divider);
|
||||
|
||||
/* Register for SPI interrupt */
|
||||
err = request_irq(ss->irq, stmp_spi_irq, 0,
|
||||
dev_name(&dev->dev), ss);
|
||||
if (err) {
|
||||
dev_dbg(&dev->dev, "request_irq failed, %d\n", err);
|
||||
goto out_release_hw;
|
||||
}
|
||||
|
||||
/* ..and shared interrupt for all SSP controllers */
|
||||
err = request_irq(ss->err_irq, stmp_spi_irq_err, IRQF_SHARED,
|
||||
dev_name(&dev->dev), ss);
|
||||
if (err) {
|
||||
dev_dbg(&dev->dev, "request_irq(error) failed, %d\n", err);
|
||||
goto out_free_irq;
|
||||
}
|
||||
|
||||
err = spi_register_master(master);
|
||||
if (err) {
|
||||
dev_dbg(&dev->dev, "cannot register spi master, %d\n", err);
|
||||
goto out_free_irq_2;
|
||||
}
|
||||
dev_info(&dev->dev, "at (mapped) 0x%08X, irq=%d, bus %d, %s mode\n",
|
||||
(u32)ss->regs, ss->irq, master->bus_num,
|
||||
pio ? "PIO" : "DMA");
|
||||
return 0;
|
||||
|
||||
out_free_irq_2:
|
||||
free_irq(ss->err_irq, ss);
|
||||
out_free_irq:
|
||||
free_irq(ss->irq, ss);
|
||||
out_free_dma_desc:
|
||||
stmp3xxx_dma_free_command(ss->dma, &ss->d);
|
||||
out_free_dma:
|
||||
stmp3xxx_dma_release(ss->dma);
|
||||
out_release_hw:
|
||||
stmp_spi_release_hw(ss);
|
||||
out_put_master:
|
||||
if (ss->workqueue)
|
||||
destroy_workqueue(ss->workqueue);
|
||||
if (ss->regs)
|
||||
iounmap(ss->regs);
|
||||
platform_set_drvdata(dev, NULL);
|
||||
spi_master_put(master);
|
||||
out0:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit stmp_spi_remove(struct platform_device *dev)
|
||||
{
|
||||
struct stmp_spi *ss;
|
||||
struct spi_master *master;
|
||||
|
||||
master = spi_master_get(platform_get_drvdata(dev));
|
||||
ss = spi_master_get_devdata(master);
|
||||
|
||||
spi_unregister_master(master);
|
||||
|
||||
free_irq(ss->err_irq, ss);
|
||||
free_irq(ss->irq, ss);
|
||||
stmp3xxx_dma_free_command(ss->dma, &ss->d);
|
||||
stmp3xxx_dma_release(ss->dma);
|
||||
stmp_spi_release_hw(ss);
|
||||
destroy_workqueue(ss->workqueue);
|
||||
iounmap(ss->regs);
|
||||
spi_master_put(master);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stmp_spi_suspend(struct platform_device *pdev, pm_message_t pmsg)
|
||||
{
|
||||
struct stmp_spi *ss;
|
||||
struct spi_master *master;
|
||||
|
||||
master = platform_get_drvdata(pdev);
|
||||
ss = spi_master_get_devdata(master);
|
||||
|
||||
ss->saved_timings = readl(HW_SSP_TIMING + ss->regs);
|
||||
clk_disable(ss->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmp_spi_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct stmp_spi *ss;
|
||||
struct spi_master *master;
|
||||
|
||||
master = platform_get_drvdata(pdev);
|
||||
ss = spi_master_get_devdata(master);
|
||||
|
||||
clk_enable(ss->clk);
|
||||
stmp3xxx_reset_block(ss->regs, false);
|
||||
writel(ss->saved_timings, ss->regs + HW_SSP_TIMING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define stmp_spi_suspend NULL
|
||||
#define stmp_spi_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver stmp_spi_driver = {
|
||||
.probe = stmp_spi_probe,
|
||||
.remove = __devexit_p(stmp_spi_remove),
|
||||
.driver = {
|
||||
.name = "stmp3xxx_ssp",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.suspend = stmp_spi_suspend,
|
||||
.resume = stmp_spi_resume,
|
||||
};
|
||||
module_platform_driver(stmp_spi_driver);
|
||||
|
||||
module_param(pio, int, S_IRUGO);
|
||||
module_param(clock, int, S_IRUGO);
|
||||
MODULE_AUTHOR("dmitry pervushin <dpervushin@embeddedalley.com>");
|
||||
MODULE_DESCRIPTION("STMP3xxx SPI/SSP driver");
|
||||
MODULE_LICENSE("GPL");
|
665
drivers/spi/spi-tegra20-sflash.c
Normal file
665
drivers/spi/spi-tegra20-sflash.c
Normal file
@ -0,0 +1,665 @@
|
||||
/*
|
||||
* SPI driver for Nvidia's Tegra20 Serial Flash Controller.
|
||||
*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Author: Laxman Dewangan <ldewangan@nvidia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi-tegra.h>
|
||||
#include <mach/clk.h>
|
||||
|
||||
#define SPI_COMMAND 0x000
|
||||
#define SPI_GO BIT(30)
|
||||
#define SPI_M_S BIT(28)
|
||||
#define SPI_ACTIVE_SCLK_MASK (0x3 << 26)
|
||||
#define SPI_ACTIVE_SCLK_DRIVE_LOW (0 << 26)
|
||||
#define SPI_ACTIVE_SCLK_DRIVE_HIGH (1 << 26)
|
||||
#define SPI_ACTIVE_SCLK_PULL_LOW (2 << 26)
|
||||
#define SPI_ACTIVE_SCLK_PULL_HIGH (3 << 26)
|
||||
|
||||
#define SPI_CK_SDA_FALLING (1 << 21)
|
||||
#define SPI_CK_SDA_RISING (0 << 21)
|
||||
#define SPI_CK_SDA_MASK (1 << 21)
|
||||
#define SPI_ACTIVE_SDA (0x3 << 18)
|
||||
#define SPI_ACTIVE_SDA_DRIVE_LOW (0 << 18)
|
||||
#define SPI_ACTIVE_SDA_DRIVE_HIGH (1 << 18)
|
||||
#define SPI_ACTIVE_SDA_PULL_LOW (2 << 18)
|
||||
#define SPI_ACTIVE_SDA_PULL_HIGH (3 << 18)
|
||||
|
||||
#define SPI_CS_POL_INVERT BIT(16)
|
||||
#define SPI_TX_EN BIT(15)
|
||||
#define SPI_RX_EN BIT(14)
|
||||
#define SPI_CS_VAL_HIGH BIT(13)
|
||||
#define SPI_CS_VAL_LOW 0x0
|
||||
#define SPI_CS_SW BIT(12)
|
||||
#define SPI_CS_HW 0x0
|
||||
#define SPI_CS_DELAY_MASK (7 << 9)
|
||||
#define SPI_CS3_EN BIT(8)
|
||||
#define SPI_CS2_EN BIT(7)
|
||||
#define SPI_CS1_EN BIT(6)
|
||||
#define SPI_CS0_EN BIT(5)
|
||||
|
||||
#define SPI_CS_MASK (SPI_CS3_EN | SPI_CS2_EN | \
|
||||
SPI_CS1_EN | SPI_CS0_EN)
|
||||
#define SPI_BIT_LENGTH(x) (((x) & 0x1f) << 0)
|
||||
|
||||
#define SPI_MODES (SPI_ACTIVE_SCLK_MASK | SPI_CK_SDA_MASK)
|
||||
|
||||
#define SPI_STATUS 0x004
|
||||
#define SPI_BSY BIT(31)
|
||||
#define SPI_RDY BIT(30)
|
||||
#define SPI_TXF_FLUSH BIT(29)
|
||||
#define SPI_RXF_FLUSH BIT(28)
|
||||
#define SPI_RX_UNF BIT(27)
|
||||
#define SPI_TX_OVF BIT(26)
|
||||
#define SPI_RXF_EMPTY BIT(25)
|
||||
#define SPI_RXF_FULL BIT(24)
|
||||
#define SPI_TXF_EMPTY BIT(23)
|
||||
#define SPI_TXF_FULL BIT(22)
|
||||
#define SPI_BLK_CNT(count) (((count) & 0xffff) + 1)
|
||||
|
||||
#define SPI_FIFO_ERROR (SPI_RX_UNF | SPI_TX_OVF)
|
||||
#define SPI_FIFO_EMPTY (SPI_TX_EMPTY | SPI_RX_EMPTY)
|
||||
|
||||
#define SPI_RX_CMP 0x8
|
||||
#define SPI_DMA_CTL 0x0C
|
||||
#define SPI_DMA_EN BIT(31)
|
||||
#define SPI_IE_RXC BIT(27)
|
||||
#define SPI_IE_TXC BIT(26)
|
||||
#define SPI_PACKED BIT(20)
|
||||
#define SPI_RX_TRIG_MASK (0x3 << 18)
|
||||
#define SPI_RX_TRIG_1W (0x0 << 18)
|
||||
#define SPI_RX_TRIG_4W (0x1 << 18)
|
||||
#define SPI_TX_TRIG_MASK (0x3 << 16)
|
||||
#define SPI_TX_TRIG_1W (0x0 << 16)
|
||||
#define SPI_TX_TRIG_4W (0x1 << 16)
|
||||
#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF);
|
||||
|
||||
#define SPI_TX_FIFO 0x10
|
||||
#define SPI_RX_FIFO 0x20
|
||||
|
||||
#define DATA_DIR_TX (1 << 0)
|
||||
#define DATA_DIR_RX (1 << 1)
|
||||
|
||||
#define MAX_CHIP_SELECT 4
|
||||
#define SPI_FIFO_DEPTH 4
|
||||
#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
struct tegra_sflash_data {
|
||||
struct device *dev;
|
||||
struct spi_master *master;
|
||||
spinlock_t lock;
|
||||
|
||||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
unsigned irq;
|
||||
u32 spi_max_frequency;
|
||||
u32 cur_speed;
|
||||
|
||||
struct spi_device *cur_spi;
|
||||
unsigned cur_pos;
|
||||
unsigned cur_len;
|
||||
unsigned bytes_per_word;
|
||||
unsigned cur_direction;
|
||||
unsigned curr_xfer_words;
|
||||
|
||||
unsigned cur_rx_pos;
|
||||
unsigned cur_tx_pos;
|
||||
|
||||
u32 tx_status;
|
||||
u32 rx_status;
|
||||
u32 status_reg;
|
||||
|
||||
u32 def_command_reg;
|
||||
u32 command_reg;
|
||||
u32 dma_control_reg;
|
||||
|
||||
struct completion xfer_completion;
|
||||
struct spi_transfer *curr_xfer;
|
||||
};
|
||||
|
||||
static int tegra_sflash_runtime_suspend(struct device *dev);
|
||||
static int tegra_sflash_runtime_resume(struct device *dev);
|
||||
|
||||
static inline unsigned long tegra_sflash_readl(struct tegra_sflash_data *tsd,
|
||||
unsigned long reg)
|
||||
{
|
||||
return readl(tsd->base + reg);
|
||||
}
|
||||
|
||||
static inline void tegra_sflash_writel(struct tegra_sflash_data *tsd,
|
||||
unsigned long val, unsigned long reg)
|
||||
{
|
||||
writel(val, tsd->base + reg);
|
||||
}
|
||||
|
||||
static void tegra_sflash_clear_status(struct tegra_sflash_data *tsd)
|
||||
{
|
||||
/* Write 1 to clear status register */
|
||||
tegra_sflash_writel(tsd, SPI_RDY | SPI_FIFO_ERROR, SPI_STATUS);
|
||||
}
|
||||
|
||||
static unsigned tegra_sflash_calculate_curr_xfer_param(
|
||||
struct spi_device *spi, struct tegra_sflash_data *tsd,
|
||||
struct spi_transfer *t)
|
||||
{
|
||||
unsigned remain_len = t->len - tsd->cur_pos;
|
||||
unsigned max_word;
|
||||
|
||||
tsd->bytes_per_word = (t->bits_per_word - 1) / 8 + 1;
|
||||
max_word = remain_len / tsd->bytes_per_word;
|
||||
if (max_word > SPI_FIFO_DEPTH)
|
||||
max_word = SPI_FIFO_DEPTH;
|
||||
tsd->curr_xfer_words = max_word;
|
||||
return max_word;
|
||||
}
|
||||
|
||||
static unsigned tegra_sflash_fill_tx_fifo_from_client_txbuf(
|
||||
struct tegra_sflash_data *tsd, struct spi_transfer *t)
|
||||
{
|
||||
unsigned nbytes;
|
||||
unsigned long status;
|
||||
unsigned max_n_32bit = tsd->curr_xfer_words;
|
||||
u8 *tx_buf = (u8 *)t->tx_buf + tsd->cur_tx_pos;
|
||||
|
||||
if (max_n_32bit > SPI_FIFO_DEPTH)
|
||||
max_n_32bit = SPI_FIFO_DEPTH;
|
||||
nbytes = max_n_32bit * tsd->bytes_per_word;
|
||||
|
||||
status = tegra_sflash_readl(tsd, SPI_STATUS);
|
||||
while (!(status & SPI_TXF_FULL)) {
|
||||
int i;
|
||||
unsigned int x = 0;
|
||||
|
||||
for (i = 0; nbytes && (i < tsd->bytes_per_word);
|
||||
i++, nbytes--)
|
||||
x |= ((*tx_buf++) << i*8);
|
||||
tegra_sflash_writel(tsd, x, SPI_TX_FIFO);
|
||||
if (!nbytes)
|
||||
break;
|
||||
|
||||
status = tegra_sflash_readl(tsd, SPI_STATUS);
|
||||
}
|
||||
tsd->cur_tx_pos += max_n_32bit * tsd->bytes_per_word;
|
||||
return max_n_32bit;
|
||||
}
|
||||
|
||||
static int tegra_sflash_read_rx_fifo_to_client_rxbuf(
|
||||
struct tegra_sflash_data *tsd, struct spi_transfer *t)
|
||||
{
|
||||
unsigned long status;
|
||||
unsigned int read_words = 0;
|
||||
u8 *rx_buf = (u8 *)t->rx_buf + tsd->cur_rx_pos;
|
||||
|
||||
status = tegra_sflash_readl(tsd, SPI_STATUS);
|
||||
while (!(status & SPI_RXF_EMPTY)) {
|
||||
int i;
|
||||
unsigned long x;
|
||||
|
||||
x = tegra_sflash_readl(tsd, SPI_RX_FIFO);
|
||||
for (i = 0; (i < tsd->bytes_per_word); i++)
|
||||
*rx_buf++ = (x >> (i*8)) & 0xFF;
|
||||
read_words++;
|
||||
status = tegra_sflash_readl(tsd, SPI_STATUS);
|
||||
}
|
||||
tsd->cur_rx_pos += read_words * tsd->bytes_per_word;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_sflash_start_cpu_based_transfer(
|
||||
struct tegra_sflash_data *tsd, struct spi_transfer *t)
|
||||
{
|
||||
unsigned long val = 0;
|
||||
unsigned cur_words;
|
||||
|
||||
if (tsd->cur_direction & DATA_DIR_TX)
|
||||
val |= SPI_IE_TXC;
|
||||
|
||||
if (tsd->cur_direction & DATA_DIR_RX)
|
||||
val |= SPI_IE_RXC;
|
||||
|
||||
tegra_sflash_writel(tsd, val, SPI_DMA_CTL);
|
||||
tsd->dma_control_reg = val;
|
||||
|
||||
if (tsd->cur_direction & DATA_DIR_TX)
|
||||
cur_words = tegra_sflash_fill_tx_fifo_from_client_txbuf(tsd, t);
|
||||
else
|
||||
cur_words = tsd->curr_xfer_words;
|
||||
val |= SPI_DMA_BLK_COUNT(cur_words);
|
||||
tegra_sflash_writel(tsd, val, SPI_DMA_CTL);
|
||||
tsd->dma_control_reg = val;
|
||||
val |= SPI_DMA_EN;
|
||||
tegra_sflash_writel(tsd, val, SPI_DMA_CTL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_sflash_start_transfer_one(struct spi_device *spi,
|
||||
struct spi_transfer *t, bool is_first_of_msg,
|
||||
bool is_single_xfer)
|
||||
{
|
||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
|
||||
u32 speed;
|
||||
unsigned long command;
|
||||
|
||||
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
|
||||
if (!speed)
|
||||
speed = tsd->spi_max_frequency;
|
||||
if (speed != tsd->cur_speed) {
|
||||
clk_set_rate(tsd->clk, speed);
|
||||
tsd->cur_speed = speed;
|
||||
}
|
||||
|
||||
tsd->cur_spi = spi;
|
||||
tsd->cur_pos = 0;
|
||||
tsd->cur_rx_pos = 0;
|
||||
tsd->cur_tx_pos = 0;
|
||||
tsd->curr_xfer = t;
|
||||
tegra_sflash_calculate_curr_xfer_param(spi, tsd, t);
|
||||
if (is_first_of_msg) {
|
||||
command = tsd->def_command_reg;
|
||||
command |= SPI_BIT_LENGTH(t->bits_per_word - 1);
|
||||
command |= SPI_CS_VAL_HIGH;
|
||||
|
||||
command &= ~SPI_MODES;
|
||||
if (spi->mode & SPI_CPHA)
|
||||
command |= SPI_CK_SDA_FALLING;
|
||||
|
||||
if (spi->mode & SPI_CPOL)
|
||||
command |= SPI_ACTIVE_SCLK_DRIVE_HIGH;
|
||||
else
|
||||
command |= SPI_ACTIVE_SCLK_DRIVE_LOW;
|
||||
command |= SPI_CS0_EN << spi->chip_select;
|
||||
} else {
|
||||
command = tsd->command_reg;
|
||||
command &= ~SPI_BIT_LENGTH(~0);
|
||||
command |= SPI_BIT_LENGTH(t->bits_per_word - 1);
|
||||
command &= ~(SPI_RX_EN | SPI_TX_EN);
|
||||
}
|
||||
|
||||
tsd->cur_direction = 0;
|
||||
if (t->rx_buf) {
|
||||
command |= SPI_RX_EN;
|
||||
tsd->cur_direction |= DATA_DIR_RX;
|
||||
}
|
||||
if (t->tx_buf) {
|
||||
command |= SPI_TX_EN;
|
||||
tsd->cur_direction |= DATA_DIR_TX;
|
||||
}
|
||||
tegra_sflash_writel(tsd, command, SPI_COMMAND);
|
||||
tsd->command_reg = command;
|
||||
|
||||
return tegra_sflash_start_cpu_based_transfer(tsd, t);
|
||||
}
|
||||
|
||||
static int tegra_sflash_transfer_one_message(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
bool is_first_msg = true;
|
||||
int single_xfer;
|
||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
||||
struct spi_transfer *xfer;
|
||||
struct spi_device *spi = msg->spi;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(tsd->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(tsd->dev, "pm_runtime_get() failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msg->status = 0;
|
||||
msg->actual_length = 0;
|
||||
single_xfer = list_is_singular(&msg->transfers);
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
INIT_COMPLETION(tsd->xfer_completion);
|
||||
ret = tegra_sflash_start_transfer_one(spi, xfer,
|
||||
is_first_msg, single_xfer);
|
||||
if (ret < 0) {
|
||||
dev_err(tsd->dev,
|
||||
"spi can not start transfer, err %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
is_first_msg = false;
|
||||
ret = wait_for_completion_timeout(&tsd->xfer_completion,
|
||||
SPI_DMA_TIMEOUT);
|
||||
if (WARN_ON(ret == 0)) {
|
||||
dev_err(tsd->dev,
|
||||
"spi trasfer timeout, err %d\n", ret);
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (tsd->tx_status || tsd->rx_status) {
|
||||
dev_err(tsd->dev, "Error in Transfer\n");
|
||||
ret = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
msg->actual_length += xfer->len;
|
||||
if (xfer->cs_change && xfer->delay_usecs) {
|
||||
tegra_sflash_writel(tsd, tsd->def_command_reg,
|
||||
SPI_COMMAND);
|
||||
udelay(xfer->delay_usecs);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
exit:
|
||||
tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
|
||||
msg->status = ret;
|
||||
spi_finalize_current_message(master);
|
||||
pm_runtime_put(tsd->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t handle_cpu_based_xfer(struct tegra_sflash_data *tsd)
|
||||
{
|
||||
struct spi_transfer *t = tsd->curr_xfer;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tsd->lock, flags);
|
||||
if (tsd->tx_status || tsd->rx_status || (tsd->status_reg & SPI_BSY)) {
|
||||
dev_err(tsd->dev,
|
||||
"CpuXfer ERROR bit set 0x%x\n", tsd->status_reg);
|
||||
dev_err(tsd->dev,
|
||||
"CpuXfer 0x%08x:0x%08x\n", tsd->command_reg,
|
||||
tsd->dma_control_reg);
|
||||
tegra_periph_reset_assert(tsd->clk);
|
||||
udelay(2);
|
||||
tegra_periph_reset_deassert(tsd->clk);
|
||||
complete(&tsd->xfer_completion);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (tsd->cur_direction & DATA_DIR_RX)
|
||||
tegra_sflash_read_rx_fifo_to_client_rxbuf(tsd, t);
|
||||
|
||||
if (tsd->cur_direction & DATA_DIR_TX)
|
||||
tsd->cur_pos = tsd->cur_tx_pos;
|
||||
else
|
||||
tsd->cur_pos = tsd->cur_rx_pos;
|
||||
|
||||
if (tsd->cur_pos == t->len) {
|
||||
complete(&tsd->xfer_completion);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
tegra_sflash_calculate_curr_xfer_param(tsd->cur_spi, tsd, t);
|
||||
tegra_sflash_start_cpu_based_transfer(tsd, t);
|
||||
exit:
|
||||
spin_unlock_irqrestore(&tsd->lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
|
||||
{
|
||||
struct tegra_sflash_data *tsd = context_data;
|
||||
|
||||
tsd->status_reg = tegra_sflash_readl(tsd, SPI_STATUS);
|
||||
if (tsd->cur_direction & DATA_DIR_TX)
|
||||
tsd->tx_status = tsd->status_reg & SPI_TX_OVF;
|
||||
|
||||
if (tsd->cur_direction & DATA_DIR_RX)
|
||||
tsd->rx_status = tsd->status_reg & SPI_RX_UNF;
|
||||
tegra_sflash_clear_status(tsd);
|
||||
|
||||
return handle_cpu_based_xfer(tsd);
|
||||
}
|
||||
|
||||
static struct tegra_spi_platform_data *tegra_sflash_parse_dt(
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_spi_platform_data *pdata;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 max_freq;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "Memory alloc for pdata failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
|
||||
pdata->spi_max_frequency = max_freq;
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
static struct of_device_id tegra_sflash_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra20-sflash", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_sflash_of_match);
|
||||
|
||||
static int tegra_sflash_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct tegra_sflash_data *tsd;
|
||||
struct resource *r;
|
||||
struct tegra_spi_platform_data *pdata = pdev->dev.platform_data;
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_device(of_match_ptr(tegra_sflash_of_match),
|
||||
&pdev->dev);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!pdata && pdev->dev.of_node)
|
||||
pdata = tegra_sflash_parse_dt(pdev);
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data, exiting\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!pdata->spi_max_frequency)
|
||||
pdata->spi_max_frequency = 25000000; /* 25MHz */
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*tsd));
|
||||
if (!master) {
|
||||
dev_err(&pdev->dev, "master allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* the spi->mode bits understood by this driver: */
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||
master->transfer_one_message = tegra_sflash_transfer_one_message;
|
||||
master->num_chipselect = MAX_CHIP_SELECT;
|
||||
master->bus_num = -1;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, master);
|
||||
tsd = spi_master_get_devdata(master);
|
||||
tsd->master = master;
|
||||
tsd->dev = &pdev->dev;
|
||||
spin_lock_init(&tsd->lock);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
dev_err(&pdev->dev, "No IO memory resource\n");
|
||||
ret = -ENODEV;
|
||||
goto exit_free_master;
|
||||
}
|
||||
tsd->base = devm_request_and_ioremap(&pdev->dev, r);
|
||||
if (!tsd->base) {
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot request memregion/iomap dma address\n");
|
||||
ret = -EADDRNOTAVAIL;
|
||||
goto exit_free_master;
|
||||
}
|
||||
|
||||
tsd->irq = platform_get_irq(pdev, 0);
|
||||
ret = request_irq(tsd->irq, tegra_sflash_isr, 0,
|
||||
dev_name(&pdev->dev), tsd);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
|
||||
tsd->irq);
|
||||
goto exit_free_master;
|
||||
}
|
||||
|
||||
tsd->clk = devm_clk_get(&pdev->dev, "spi");
|
||||
if (IS_ERR(tsd->clk)) {
|
||||
dev_err(&pdev->dev, "can not get clock\n");
|
||||
ret = PTR_ERR(tsd->clk);
|
||||
goto exit_free_irq;
|
||||
}
|
||||
|
||||
tsd->spi_max_frequency = pdata->spi_max_frequency;
|
||||
init_completion(&tsd->xfer_completion);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
ret = tegra_sflash_runtime_resume(&pdev->dev);
|
||||
if (ret)
|
||||
goto exit_pm_disable;
|
||||
}
|
||||
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
|
||||
goto exit_pm_disable;
|
||||
}
|
||||
|
||||
/* Reset controller */
|
||||
tegra_periph_reset_assert(tsd->clk);
|
||||
udelay(2);
|
||||
tegra_periph_reset_deassert(tsd->clk);
|
||||
|
||||
tsd->def_command_reg = SPI_M_S | SPI_CS_SW;
|
||||
tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
|
||||
pm_runtime_put(&pdev->dev);
|
||||
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
ret = spi_register_master(master);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "can not register to master err %d\n", ret);
|
||||
goto exit_pm_disable;
|
||||
}
|
||||
return ret;
|
||||
|
||||
exit_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
tegra_sflash_runtime_suspend(&pdev->dev);
|
||||
exit_free_irq:
|
||||
free_irq(tsd->irq, tsd);
|
||||
exit_free_master:
|
||||
spi_master_put(master);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_sflash_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(&pdev->dev);
|
||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
||||
|
||||
free_irq(tsd->irq, tsd);
|
||||
spi_unregister_master(master);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
tegra_sflash_runtime_suspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tegra_sflash_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
|
||||
return spi_master_suspend(master);
|
||||
}
|
||||
|
||||
static int tegra_sflash_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "pm runtime failed, e = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
tegra_sflash_writel(tsd, tsd->command_reg, SPI_COMMAND);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return spi_master_resume(master);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tegra_sflash_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
||||
|
||||
/* Flush all write which are in PPSB queue by reading back */
|
||||
tegra_sflash_readl(tsd, SPI_COMMAND);
|
||||
|
||||
clk_disable_unprepare(tsd->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_sflash_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(tsd->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(tsd->dev, "clk_prepare failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops slink_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(tegra_sflash_runtime_suspend,
|
||||
tegra_sflash_runtime_resume, NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tegra_sflash_suspend, tegra_sflash_resume)
|
||||
};
|
||||
static struct platform_driver tegra_sflash_driver = {
|
||||
.driver = {
|
||||
.name = "spi-tegra-sflash",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &slink_pm_ops,
|
||||
.of_match_table = of_match_ptr(tegra_sflash_of_match),
|
||||
},
|
||||
.probe = tegra_sflash_probe,
|
||||
.remove = tegra_sflash_remove,
|
||||
};
|
||||
module_platform_driver(tegra_sflash_driver);
|
||||
|
||||
MODULE_ALIAS("platform:spi-tegra-sflash");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra20 Serial Flash Controller Driver");
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
1358
drivers/spi/spi-tegra20-slink.c
Normal file
1358
drivers/spi/spi-tegra20-slink.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -289,7 +289,7 @@ error_unlock:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devinit ti_ssp_spi_probe(struct platform_device *pdev)
|
||||
static int ti_ssp_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct ti_ssp_spi_data *pdata;
|
||||
struct ti_ssp_spi *hw;
|
||||
@ -357,7 +357,7 @@ error_wq:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
|
||||
static int ti_ssp_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
|
||||
int error;
|
||||
@ -378,7 +378,7 @@ static int __devexit ti_ssp_spi_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver ti_ssp_spi_driver = {
|
||||
.probe = ti_ssp_spi_probe,
|
||||
.remove = __devexit_p(ti_ssp_spi_remove),
|
||||
.remove = ti_ssp_spi_remove,
|
||||
.driver = {
|
||||
.name = "ti-ssp-spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -240,7 +240,7 @@ static int to_gpio_num(struct device_attribute *attr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __devinit tle62x0_probe(struct spi_device *spi)
|
||||
static int tle62x0_probe(struct spi_device *spi)
|
||||
{
|
||||
struct tle62x0_state *st;
|
||||
struct tle62x0_pdata *pdata;
|
||||
@ -294,7 +294,7 @@ static int __devinit tle62x0_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit tle62x0_remove(struct spi_device *spi)
|
||||
static int tle62x0_remove(struct spi_device *spi)
|
||||
{
|
||||
struct tle62x0_state *st = spi_get_drvdata(spi);
|
||||
int ptr;
|
||||
@ -313,7 +313,7 @@ static struct spi_driver tle62x0_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tle62x0_probe,
|
||||
.remove = __devexit_p(tle62x0_remove),
|
||||
.remove = tle62x0_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(tle62x0_driver);
|
||||
|
@ -1401,7 +1401,7 @@ static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
|
||||
PCH_BUF_SIZE, &dma->rx_buf_dma, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev)
|
||||
static int pch_spi_pd_probe(struct platform_device *plat_dev)
|
||||
{
|
||||
int ret;
|
||||
struct spi_master *master;
|
||||
@ -1498,7 +1498,7 @@ err_pci_iomap:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit pch_spi_pd_remove(struct platform_device *plat_dev)
|
||||
static int pch_spi_pd_remove(struct platform_device *plat_dev)
|
||||
{
|
||||
struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev);
|
||||
struct pch_spi_data *data = platform_get_drvdata(plat_dev);
|
||||
@ -1619,12 +1619,12 @@ static struct platform_driver pch_spi_pd_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = pch_spi_pd_probe,
|
||||
.remove = __devexit_p(pch_spi_pd_remove),
|
||||
.remove = pch_spi_pd_remove,
|
||||
.suspend = pch_spi_pd_suspend,
|
||||
.resume = pch_spi_pd_resume
|
||||
};
|
||||
|
||||
static int __devinit pch_spi_probe(struct pci_dev *pdev,
|
||||
static int pch_spi_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct pch_spi_board_data *board_dat;
|
||||
@ -1705,7 +1705,7 @@ err_no_mem:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __devexit pch_spi_remove(struct pci_dev *pdev)
|
||||
static void pch_spi_remove(struct pci_dev *pdev)
|
||||
{
|
||||
int i;
|
||||
struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev);
|
||||
@ -1776,7 +1776,7 @@ static struct pci_driver pch_spi_pcidev_driver = {
|
||||
.name = "pch_spi",
|
||||
.id_table = pch_spi_pcidev_id,
|
||||
.probe = pch_spi_probe,
|
||||
.remove = __devexit_p(pch_spi_remove),
|
||||
.remove = pch_spi_remove,
|
||||
.suspend = pch_spi_suspend,
|
||||
.resume = pch_spi_resume,
|
||||
};
|
||||
|
@ -217,7 +217,7 @@ static int spi_xcomm_setup(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit spi_xcomm_probe(struct i2c_client *i2c,
|
||||
static int spi_xcomm_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct spi_xcomm *spi_xcomm;
|
||||
@ -246,7 +246,7 @@ static int __devinit spi_xcomm_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit spi_xcomm_remove(struct i2c_client *i2c)
|
||||
static int spi_xcomm_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct spi_master *master = i2c_get_clientdata(i2c);
|
||||
|
||||
@ -267,7 +267,7 @@ static struct i2c_driver spi_xcomm_driver = {
|
||||
},
|
||||
.id_table = spi_xcomm_ids,
|
||||
.probe = spi_xcomm_probe,
|
||||
.remove = __devexit_p(spi_xcomm_remove),
|
||||
.remove = spi_xcomm_remove,
|
||||
};
|
||||
module_i2c_driver(spi_xcomm_driver);
|
||||
|
||||
|
@ -462,7 +462,7 @@ void xilinx_spi_deinit(struct spi_master *master)
|
||||
}
|
||||
EXPORT_SYMBOL(xilinx_spi_deinit);
|
||||
|
||||
static int __devinit xilinx_spi_probe(struct platform_device *dev)
|
||||
static int xilinx_spi_probe(struct platform_device *dev)
|
||||
{
|
||||
struct xspi_platform_data *pdata;
|
||||
struct resource *r;
|
||||
@ -518,7 +518,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit xilinx_spi_remove(struct platform_device *dev)
|
||||
static int xilinx_spi_remove(struct platform_device *dev)
|
||||
{
|
||||
xilinx_spi_deinit(platform_get_drvdata(dev));
|
||||
platform_set_drvdata(dev, 0);
|
||||
@ -531,7 +531,7 @@ MODULE_ALIAS("platform:" XILINX_SPI_NAME);
|
||||
|
||||
static struct platform_driver xilinx_spi_driver = {
|
||||
.probe = xilinx_spi_probe,
|
||||
.remove = __devexit_p(xilinx_spi_remove),
|
||||
.remove = xilinx_spi_remove,
|
||||
.driver = {
|
||||
.name = XILINX_SPI_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/sched.h>
|
||||
@ -333,6 +334,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master)
|
||||
spi->dev.parent = &master->dev;
|
||||
spi->dev.bus = &spi_bus_type;
|
||||
spi->dev.release = spidev_release;
|
||||
spi->cs_gpio = -EINVAL;
|
||||
device_initialize(&spi->dev);
|
||||
return spi;
|
||||
}
|
||||
@ -350,15 +352,16 @@ EXPORT_SYMBOL_GPL(spi_alloc_device);
|
||||
int spi_add_device(struct spi_device *spi)
|
||||
{
|
||||
static DEFINE_MUTEX(spi_add_lock);
|
||||
struct device *dev = spi->master->dev.parent;
|
||||
struct spi_master *master = spi->master;
|
||||
struct device *dev = master->dev.parent;
|
||||
struct device *d;
|
||||
int status;
|
||||
|
||||
/* Chipselects are numbered 0..max; validate. */
|
||||
if (spi->chip_select >= spi->master->num_chipselect) {
|
||||
if (spi->chip_select >= master->num_chipselect) {
|
||||
dev_err(dev, "cs%d >= max %d\n",
|
||||
spi->chip_select,
|
||||
spi->master->num_chipselect);
|
||||
master->num_chipselect);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -382,6 +385,9 @@ int spi_add_device(struct spi_device *spi)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (master->cs_gpios)
|
||||
spi->cs_gpio = master->cs_gpios[spi->chip_select];
|
||||
|
||||
/* Drivers may modify this initial i/o setup, but will
|
||||
* normally rely on the device being setup. Devices
|
||||
* using SPI_CS_HIGH can't coexist well otherwise...
|
||||
@ -492,8 +498,7 @@ static void spi_match_master_to_boardinfo(struct spi_master *master,
|
||||
* The board info passed can safely be __initdata ... but be careful of
|
||||
* any embedded pointers (platform_data, etc), they're copied as-is.
|
||||
*/
|
||||
int __devinit
|
||||
spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
||||
int spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
||||
{
|
||||
struct boardinfo *bi;
|
||||
int i;
|
||||
@ -806,7 +811,7 @@ err_init_queue:
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_OF) && !defined(CONFIG_SPARC)
|
||||
#if defined(CONFIG_OF)
|
||||
/**
|
||||
* of_register_spi_devices() - Register child devices onto the SPI bus
|
||||
* @master: Pointer to spi_master device
|
||||
@ -861,6 +866,8 @@ static void of_register_spi_devices(struct spi_master *master)
|
||||
spi->mode |= SPI_CPOL;
|
||||
if (of_find_property(nc, "spi-cs-high", NULL))
|
||||
spi->mode |= SPI_CS_HIGH;
|
||||
if (of_find_property(nc, "spi-3wire", NULL))
|
||||
spi->mode |= SPI_3WIRE;
|
||||
|
||||
/* Device speed */
|
||||
prop = of_get_property(nc, "spi-max-frequency", &len);
|
||||
@ -1046,6 +1053,44 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_alloc_master);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int of_spi_register_master(struct spi_master *master)
|
||||
{
|
||||
u16 nb;
|
||||
int i, *cs;
|
||||
struct device_node *np = master->dev.of_node;
|
||||
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
nb = of_gpio_named_count(np, "cs-gpios");
|
||||
master->num_chipselect = max(nb, master->num_chipselect);
|
||||
|
||||
if (nb < 1)
|
||||
return 0;
|
||||
|
||||
cs = devm_kzalloc(&master->dev,
|
||||
sizeof(int) * master->num_chipselect,
|
||||
GFP_KERNEL);
|
||||
master->cs_gpios = cs;
|
||||
|
||||
if (!master->cs_gpios)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(cs, -EINVAL, master->num_chipselect);
|
||||
|
||||
for (i = 0; i < nb; i++)
|
||||
cs[i] = of_get_named_gpio(np, "cs-gpios", i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int of_spi_register_master(struct spi_master *master)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* spi_register_master - register SPI master controller
|
||||
* @master: initialized master, originally from spi_alloc_master()
|
||||
@ -1077,6 +1122,10 @@ int spi_register_master(struct spi_master *master)
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
status = of_spi_register_master(master);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* even if it's just one always-selected device, there must
|
||||
* be at least one chipselect
|
||||
*/
|
||||
@ -1257,7 +1306,7 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master);
|
||||
int spi_setup(struct spi_device *spi)
|
||||
{
|
||||
unsigned bad_bits;
|
||||
int status;
|
||||
int status = 0;
|
||||
|
||||
/* help drivers fail *cleanly* when they need options
|
||||
* that aren't supported with their current master
|
||||
@ -1272,7 +1321,8 @@ int spi_setup(struct spi_device *spi)
|
||||
if (!spi->bits_per_word)
|
||||
spi->bits_per_word = 8;
|
||||
|
||||
status = spi->master->setup(spi);
|
||||
if (spi->master->setup)
|
||||
status = spi->master->setup(spi);
|
||||
|
||||
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
|
||||
"%u bits/w, %u Hz max --> %d\n",
|
||||
@ -1291,6 +1341,7 @@ EXPORT_SYMBOL_GPL(spi_setup);
|
||||
static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
{
|
||||
struct spi_master *master = spi->master;
|
||||
struct spi_transfer *xfer;
|
||||
|
||||
/* Half-duplex links include original MicroWire, and ones with
|
||||
* only one data pin like SPI_3WIRE (switches direction) or where
|
||||
@ -1299,7 +1350,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
*/
|
||||
if ((master->flags & SPI_MASTER_HALF_DUPLEX)
|
||||
|| (spi->mode & SPI_3WIRE)) {
|
||||
struct spi_transfer *xfer;
|
||||
unsigned flags = master->flags;
|
||||
|
||||
list_for_each_entry(xfer, &message->transfers, transfer_list) {
|
||||
@ -1312,6 +1362,15 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set transfer bits_per_word as spi device default if it is not
|
||||
* set for this transfer.
|
||||
*/
|
||||
list_for_each_entry(xfer, &message->transfers, transfer_list) {
|
||||
if (!xfer->bits_per_word)
|
||||
xfer->bits_per_word = spi->bits_per_word;
|
||||
}
|
||||
|
||||
message->spi = spi;
|
||||
message->status = -EINPROGRESS;
|
||||
return master->transfer(spi, message);
|
||||
@ -1588,12 +1647,18 @@ int spi_write_then_read(struct spi_device *spi,
|
||||
struct spi_transfer x[2];
|
||||
u8 *local_buf;
|
||||
|
||||
/* Use preallocated DMA-safe buffer. We can't avoid copying here,
|
||||
* (as a pure convenience thing), but we can keep heap costs
|
||||
* out of the hot path ...
|
||||
/* Use preallocated DMA-safe buffer if we can. We can't avoid
|
||||
* copying here, (as a pure convenience thing), but we can
|
||||
* keep heap costs out of the hot path unless someone else is
|
||||
* using the pre-allocated buffer or the transfer is too large.
|
||||
*/
|
||||
if ((n_tx + n_rx) > SPI_BUFSIZ)
|
||||
return -EINVAL;
|
||||
if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {
|
||||
local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx), GFP_KERNEL);
|
||||
if (!local_buf)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
local_buf = buf;
|
||||
}
|
||||
|
||||
spi_message_init(&message);
|
||||
memset(x, 0, sizeof x);
|
||||
@ -1606,14 +1671,6 @@ int spi_write_then_read(struct spi_device *spi,
|
||||
spi_message_add_tail(&x[1], &message);
|
||||
}
|
||||
|
||||
/* ... unless someone else is using the pre-allocated buffer */
|
||||
if (!mutex_trylock(&lock)) {
|
||||
local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
|
||||
if (!local_buf)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
local_buf = buf;
|
||||
|
||||
memcpy(local_buf, txbuf, n_tx);
|
||||
x[0].tx_buf = local_buf;
|
||||
x[1].rx_buf = local_buf + n_tx;
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
@ -571,7 +573,7 @@ static struct class *spidev_class;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __devinit spidev_probe(struct spi_device *spi)
|
||||
static int spidev_probe(struct spi_device *spi)
|
||||
{
|
||||
struct spidev_data *spidev;
|
||||
int status;
|
||||
@ -620,7 +622,7 @@ static int __devinit spidev_probe(struct spi_device *spi)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __devexit spidev_remove(struct spi_device *spi)
|
||||
static int spidev_remove(struct spi_device *spi)
|
||||
{
|
||||
struct spidev_data *spidev = spi_get_drvdata(spi);
|
||||
|
||||
@ -642,13 +644,21 @@ static int __devexit spidev_remove(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id spidev_dt_ids[] = {
|
||||
{ .compatible = "rohm,dh2228fv" },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
||||
|
||||
static struct spi_driver spidev_spi_driver = {
|
||||
.driver = {
|
||||
.name = "spidev",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(spidev_dt_ids),
|
||||
},
|
||||
.probe = spidev_probe,
|
||||
.remove = __devexit_p(spidev_remove),
|
||||
.remove = spidev_remove,
|
||||
|
||||
/* NOTE: suspend/resume methods are not necessary here.
|
||||
* We don't do anything except pass the requests to/from
|
||||
|
21
include/linux/platform_data/spi-clps711x.h
Normal file
21
include/linux/platform_data/spi-clps711x.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* CLPS711X SPI bus driver definitions
|
||||
*
|
||||
* Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H
|
||||
#define ____LINUX_PLATFORM_DATA_SPI_CLPS711X_H
|
||||
|
||||
/* Board specific platform_data */
|
||||
struct spi_clps711x_pdata {
|
||||
int *chipselect; /* Array of GPIO-numbers */
|
||||
int num_chipselect; /* Total count of GPIOs */
|
||||
};
|
||||
|
||||
#endif
|
@ -7,9 +7,13 @@
|
||||
|
||||
#define OMAP4_MCSPI_REG_OFFSET 0x100
|
||||
|
||||
#define MCSPI_PINDIR_D0_IN_D1_OUT 0
|
||||
#define MCSPI_PINDIR_D0_OUT_D1_IN 1
|
||||
|
||||
struct omap2_mcspi_platform_config {
|
||||
unsigned short num_cs;
|
||||
unsigned int regs_offset;
|
||||
unsigned int pin_dir:1;
|
||||
};
|
||||
|
||||
struct omap2_mcspi_dev_attr {
|
||||
|
40
include/linux/spi/spi-tegra.h
Normal file
40
include/linux/spi/spi-tegra.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* spi-tegra.h: SPI interface for Nvidia Tegra20 SLINK controller.
|
||||
*
|
||||
* Copyright (C) 2011 NVIDIA Corporation
|
||||
*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SPI_TEGRA_H
|
||||
#define _LINUX_SPI_TEGRA_H
|
||||
|
||||
struct tegra_spi_platform_data {
|
||||
int dma_req_sel;
|
||||
unsigned int spi_max_frequency;
|
||||
};
|
||||
|
||||
/*
|
||||
* Controller data from device to pass some info like
|
||||
* hw based chip select can be used or not and if yes
|
||||
* then CS hold and setup time.
|
||||
*/
|
||||
struct tegra_spi_device_controller_data {
|
||||
bool is_hw_based_cs;
|
||||
int cs_setup_clk_count;
|
||||
int cs_hold_clk_count;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_SPI_TEGRA_H */
|
@ -90,6 +90,7 @@ struct spi_device {
|
||||
void *controller_state;
|
||||
void *controller_data;
|
||||
char modalias[SPI_NAME_SIZE];
|
||||
int cs_gpio; /* chip select gpio */
|
||||
|
||||
/*
|
||||
* likely need more hooks for more protocol options affecting how
|
||||
@ -362,6 +363,8 @@ struct spi_master {
|
||||
int (*transfer_one_message)(struct spi_master *master,
|
||||
struct spi_message *mesg);
|
||||
int (*unprepare_transfer_hardware)(struct spi_master *master);
|
||||
/* gpio chip select */
|
||||
int *cs_gpios;
|
||||
};
|
||||
|
||||
static inline void *spi_master_get_devdata(struct spi_master *master)
|
||||
|
Loading…
Reference in New Issue
Block a user