SPI changes for v3.9
Changes to both core spi code and spi device drivers. The driver changes are the usual set of bug fixes and platform enablement. Core code changes include: - More intelligent assignment of SPI bus numbers when using DT - Common mechanism for using gpios as CS lines - Pull checks for bits_per_word and transfer speed out of drivers and into core code - Ensure temporary DMA buffers are DMA safe -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRI3g7AAoJEEFnBt12D9kB0acQAIaAOqN0Hvae/EtIl7Z40k3q DgLuFh6lSzhp690rbM/ULYQtJwxEyIvl0dMRPzMGcw+/tfbZIVEc8VmKJKu6/Qlr eMadyxlOtMn/KOcp0e8Yirhgg9o7aeeBo/tpF0jptu6VnVA4eJRMC/Z1EceJaF0+ cWlwkd/53nzYyg+HLPHWRGiN0JjmC3qzFEBBosWRSBYH1qgjdkSXt7qCxQTHBM8x EfjSdIE2O5p4itJ+//M7qV1+MraPvjrFh3wdqIve+XCudqfjy/yUsxMu0TF2zkmd mim35J0q/2raxqtA4gc+kfhQsfmiSXXJ0gi054Z/PE9OnS0Ed4/+z5j2aIJDZ41W oOrac10Xs1Krdi1zMx0fMoRplKV7xsjXEJ/xDl4k/Gwa86q/3etyQbr+uAG0VCQb zN3a3iHx8TK+69sbMJwdImR8Wm5hWEqK0HGYFoV0F31oIeB1Z/pXoqUmpuI2J9Nb S2CZb2Ed1KEOokCQjF89m4eOjk8AwAqw6KHBGIY0oCqhvVbmKPXkG/pRZ8d11whV fm51MS4YWKgNw1+agExW+62bfJ0WQpu2CvSzgx7lXiEytxKcw7vCxW8Etp3+Ybs+ 1ZF95OnzhiCqwUfulfQ7br6Ax03ATMFJ/Xm63i8b4m2n1TOYLq3/Bn+POaL2K6o8 chFiIdp7GCGqwT/Tgahy =DR18 -----END PGP SIGNATURE----- Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux Pull SPI changes from Grant Likely: "Changes to both core spi code and spi device drivers. The driver changes are the usual set of bug fixes and platform enablement. Core code changes include: - More intelligent assignment of SPI bus numbers when using DT - Common mechanism for using gpios as CS lines - Pull checks for bits_per_word and transfer speed out of drivers and into core code - Ensure temporary DMA buffers are DMA safe" * tag 'spi-for-linus' of git://git.secretlab.ca/git/linux: (50 commits) spi: Document cs_gpios and cs_gpio in kernel-doc spi/of: Fix initialization of cs_gpios array spi/pxa2xx: add support for Lynxpoint SPI controllers spi/pxa2xx: add support for Intel Low Power Subsystem SPI spi/pxa2xx: add support for SPI_LOOP spi/pxa2xx: add support for runtime PM spi/pxa2xx: add support for DMA engine spi/pxa2xx: break out the private DMA API usage into a separate file spi/ath79: add shutdown handler spi/mips-lantiq: set SPI_MASTER_HALF_DUPLEX flag spi/mips-lantiq: make use of spi_finalize_current_message spi/bcm63xx: work around inability to keep CS up spi/davinci: use request_threaded_irq() to fix deadlock spi/orion: Use module_platform_driver() spi/bcm63xx: reject transfers unable to transfer spi: Ensure memory used for spi_write_then_read() is DMA safe spi/spi-mpc512x-psc: init mode bits supported by the driver spi/mpc512x-psc: don't use obsolet cell-index property spi: Remove erroneous __init, __exit and __exit_p() references in drivers spi/s3c64xx: fix checkpatch warnings and error ...
This commit is contained in:
Коммит
3aad3f03b2
|
@ -0,0 +1,12 @@
|
|||
Renesas MSIOF spi controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,sh-msiof" for SuperH or
|
||||
"renesas,sh-mobile-msiof" for SH Mobile series
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : interrupt line used by MSIOF
|
||||
|
||||
Optional properties:
|
||||
- num-cs : total number of chip-selects
|
||||
- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
|
||||
- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
|
|
@ -7168,6 +7168,7 @@ F: drivers/clk/spear/
|
|||
|
||||
SPI SUBSYSTEM
|
||||
M: Grant Likely <grant.likely@secretlab.ca>
|
||||
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
L: spi-devel-general@lists.sourceforge.net
|
||||
Q: http://patchwork.kernel.org/project/spi-devel-general/list/
|
||||
T: git git://git.secretlab.ca/git/linux-2.6.git
|
||||
|
|
|
@ -297,9 +297,20 @@ config SPI_PPC4xx
|
|||
help
|
||||
This selects a driver for the PPC4xx SPI Controller.
|
||||
|
||||
config SPI_PXA2XX_PXADMA
|
||||
bool "PXA2xx SSP legacy PXA DMA API support"
|
||||
depends on SPI_PXA2XX && ARCH_PXA
|
||||
help
|
||||
Enable PXA private legacy DMA API support. Note that this is
|
||||
deprecated in favor of generic DMA engine API.
|
||||
|
||||
config SPI_PXA2XX_DMA
|
||||
def_bool y
|
||||
depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA
|
||||
|
||||
config SPI_PXA2XX
|
||||
tristate "PXA2xx SSP SPI master"
|
||||
depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
|
||||
depends on ARCH_PXA || PCI || ACPI
|
||||
select PXA_SSP if ARCH_PXA
|
||||
help
|
||||
This enables using a PXA2xx or Sodaville SSP port as a SPI master
|
||||
|
@ -307,7 +318,7 @@ config SPI_PXA2XX
|
|||
additional documentation can be found a Documentation/spi/pxa2xx.
|
||||
|
||||
config SPI_PXA2XX_PCI
|
||||
def_bool SPI_PXA2XX && X86_32 && PCI
|
||||
def_tristate SPI_PXA2XX && PCI
|
||||
|
||||
config SPI_RSPI
|
||||
tristate "Renesas RSPI controller"
|
||||
|
|
|
@ -47,7 +47,10 @@ obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
|
|||
obj-$(CONFIG_SPI_ORION) += spi-orion.o
|
||||
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
|
||||
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
|
||||
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx.o
|
||||
spi-pxa2xx-platform-objs := spi-pxa2xx.o
|
||||
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
|
||||
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
|
||||
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
|
||||
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
|
||||
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
|
||||
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
|
||||
|
|
|
@ -134,7 +134,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
|
|||
hw->tx = t->tx_buf;
|
||||
hw->rx = t->rx_buf;
|
||||
hw->count = 0;
|
||||
hw->bytes_per_word = (t->bits_per_word ? : spi->bits_per_word) / 8;
|
||||
hw->bytes_per_word = t->bits_per_word / 8;
|
||||
hw->len = t->len / hw->bytes_per_word;
|
||||
|
||||
if (hw->irq >= 0) {
|
||||
|
|
|
@ -24,17 +24,24 @@
|
|||
#include <linux/spi/spi_bitbang.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
#include <asm/mach-ath79/ath79_spi_platform.h>
|
||||
|
||||
#define DRV_NAME "ath79-spi"
|
||||
|
||||
#define ATH79_SPI_RRW_DELAY_FACTOR 12000
|
||||
#define MHZ (1000 * 1000)
|
||||
|
||||
struct ath79_spi {
|
||||
struct spi_bitbang bitbang;
|
||||
u32 ioc_base;
|
||||
u32 reg_ctrl;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned rrw_delay;
|
||||
};
|
||||
|
||||
static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
|
||||
|
@ -52,6 +59,12 @@ static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
|
|||
return spi_master_get_devdata(spi->master);
|
||||
}
|
||||
|
||||
static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned nsecs)
|
||||
{
|
||||
if (nsecs > sp->rrw_delay)
|
||||
ndelay(nsecs - sp->rrw_delay);
|
||||
}
|
||||
|
||||
static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
|
@ -83,15 +96,8 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active)
|
|||
|
||||
}
|
||||
|
||||
static int ath79_spi_setup_cs(struct spi_device *spi)
|
||||
static void ath79_spi_enable(struct ath79_spi *sp)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
struct ath79_spi_controller_data *cdata;
|
||||
|
||||
cdata = spi->controller_data;
|
||||
if (spi->chip_select && !cdata)
|
||||
return -EINVAL;
|
||||
|
||||
/* enable GPIO mode */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
|
||||
|
||||
|
@ -101,46 +107,50 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
|
|||
|
||||
/* TODO: setup speed? */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
|
||||
|
||||
if (spi->chip_select) {
|
||||
int status = 0;
|
||||
|
||||
status = gpio_request(cdata->gpio, dev_name(&spi->dev));
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = gpio_direction_output(cdata->gpio,
|
||||
spi->mode & SPI_CS_HIGH);
|
||||
if (status) {
|
||||
gpio_free(cdata->gpio);
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
sp->ioc_base |= AR71XX_SPI_IOC_CS0;
|
||||
else
|
||||
sp->ioc_base &= ~AR71XX_SPI_IOC_CS0;
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath79_spi_cleanup_cs(struct spi_device *spi)
|
||||
static void ath79_spi_disable(struct ath79_spi *sp)
|
||||
{
|
||||
struct ath79_spi *sp = ath79_spidev_to_sp(spi);
|
||||
|
||||
if (spi->chip_select) {
|
||||
struct ath79_spi_controller_data *cdata = spi->controller_data;
|
||||
gpio_free(cdata->gpio);
|
||||
}
|
||||
|
||||
/* restore CTRL register */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, sp->reg_ctrl);
|
||||
/* disable GPIO mode */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
|
||||
}
|
||||
|
||||
static int ath79_spi_setup_cs(struct spi_device *spi)
|
||||
{
|
||||
struct ath79_spi_controller_data *cdata;
|
||||
int status;
|
||||
|
||||
cdata = spi->controller_data;
|
||||
if (spi->chip_select && !cdata)
|
||||
return -EINVAL;
|
||||
|
||||
status = 0;
|
||||
if (spi->chip_select) {
|
||||
unsigned long flags;
|
||||
|
||||
flags = GPIOF_DIR_OUT;
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
flags |= GPIOF_INIT_HIGH;
|
||||
else
|
||||
flags |= GPIOF_INIT_LOW;
|
||||
|
||||
status = gpio_request_one(cdata->gpio, flags,
|
||||
dev_name(&spi->dev));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void ath79_spi_cleanup_cs(struct spi_device *spi)
|
||||
{
|
||||
if (spi->chip_select) {
|
||||
struct ath79_spi_controller_data *cdata = spi->controller_data;
|
||||
gpio_free(cdata->gpio);
|
||||
}
|
||||
}
|
||||
|
||||
static int ath79_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
int status = 0;
|
||||
|
@ -184,7 +194,11 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
|
|||
|
||||
/* setup MSB (to slave) on trailing edge */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
|
||||
ath79_spi_delay(sp, nsecs);
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
|
||||
ath79_spi_delay(sp, nsecs);
|
||||
if (bits == 1)
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
|
||||
|
||||
word <<= 1;
|
||||
}
|
||||
|
@ -198,6 +212,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
|||
struct ath79_spi *sp;
|
||||
struct ath79_spi_platform_data *pdata;
|
||||
struct resource *r;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
|
@ -236,12 +251,39 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
|||
goto err_put_master;
|
||||
}
|
||||
|
||||
sp->clk = clk_get(&pdev->dev, "ahb");
|
||||
if (IS_ERR(sp->clk)) {
|
||||
ret = PTR_ERR(sp->clk);
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
ret = clk_enable(sp->clk);
|
||||
if (ret)
|
||||
goto err_clk_put;
|
||||
|
||||
rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
|
||||
if (!rate) {
|
||||
ret = -EINVAL;
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
|
||||
dev_dbg(&pdev->dev, "register read/write delay is %u nsecs\n",
|
||||
sp->rrw_delay);
|
||||
|
||||
ath79_spi_enable(sp);
|
||||
ret = spi_bitbang_start(&sp->bitbang);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
goto err_disable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable:
|
||||
ath79_spi_disable(sp);
|
||||
err_clk_disable:
|
||||
clk_disable(sp->clk);
|
||||
err_clk_put:
|
||||
clk_put(sp->clk);
|
||||
err_unmap:
|
||||
iounmap(sp->base);
|
||||
err_put_master:
|
||||
|
@ -256,6 +298,9 @@ static int ath79_spi_remove(struct platform_device *pdev)
|
|||
struct ath79_spi *sp = platform_get_drvdata(pdev);
|
||||
|
||||
spi_bitbang_stop(&sp->bitbang);
|
||||
ath79_spi_disable(sp);
|
||||
clk_disable(sp->clk);
|
||||
clk_put(sp->clk);
|
||||
iounmap(sp->base);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
spi_master_put(sp->bitbang.master);
|
||||
|
@ -263,9 +308,15 @@ static int ath79_spi_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ath79_spi_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
ath79_spi_remove(pdev);
|
||||
}
|
||||
|
||||
static struct platform_driver ath79_spi_driver = {
|
||||
.probe = ath79_spi_probe,
|
||||
.remove = ath79_spi_remove,
|
||||
.shutdown = ath79_spi_shutdown,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -1088,7 +1088,7 @@ static struct platform_driver atmel_spi_driver = {
|
|||
.suspend = atmel_spi_suspend,
|
||||
.resume = atmel_spi_resume,
|
||||
.probe = atmel_spi_probe,
|
||||
.remove = __exit_p(atmel_spi_remove),
|
||||
.remove = atmel_spi_remove,
|
||||
};
|
||||
module_platform_driver(atmel_spi_driver);
|
||||
|
||||
|
|
|
@ -717,7 +717,7 @@ static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw)
|
|||
}
|
||||
}
|
||||
|
||||
static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
|
||||
static void au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
|
||||
{
|
||||
u32 stat, cfg;
|
||||
|
||||
|
@ -766,7 +766,7 @@ static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
|
|||
}
|
||||
|
||||
|
||||
static int __init au1550_spi_probe(struct platform_device *pdev)
|
||||
static int au1550_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct au1550_spi *hw;
|
||||
struct spi_master *master;
|
||||
|
@ -968,7 +968,7 @@ err_nomem:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int __exit au1550_spi_remove(struct platform_device *pdev)
|
||||
static int au1550_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1550_spi *hw = platform_get_drvdata(pdev);
|
||||
|
||||
|
@ -997,7 +997,7 @@ static int __exit au1550_spi_remove(struct platform_device *pdev)
|
|||
MODULE_ALIAS("platform:au1550-spi");
|
||||
|
||||
static struct platform_driver au1550_spi_drv = {
|
||||
.remove = __exit_p(au1550_spi_remove),
|
||||
.remove = au1550_spi_remove,
|
||||
.driver = {
|
||||
.name = "au1550-spi",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
#define PFX KBUILD_MODNAME
|
||||
|
||||
#define BCM63XX_SPI_MAX_PREPEND 15
|
||||
|
||||
struct bcm63xx_spi {
|
||||
struct completion done;
|
||||
|
||||
|
@ -49,16 +51,10 @@ struct bcm63xx_spi {
|
|||
unsigned int msg_type_shift;
|
||||
unsigned int msg_ctl_width;
|
||||
|
||||
/* Data buffers */
|
||||
const unsigned char *tx_ptr;
|
||||
unsigned char *rx_ptr;
|
||||
|
||||
/* data iomem */
|
||||
u8 __iomem *tx_io;
|
||||
const u8 __iomem *rx_io;
|
||||
|
||||
int remaining_bytes;
|
||||
|
||||
struct clk *clk;
|
||||
struct platform_device *pdev;
|
||||
};
|
||||
|
@ -175,24 +171,17 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Fill the TX FIFO with as many bytes as possible */
|
||||
static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
|
||||
{
|
||||
u8 size;
|
||||
|
||||
/* Fill the Tx FIFO with as many bytes as possible */
|
||||
size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
|
||||
bs->fifo_size;
|
||||
memcpy_toio(bs->tx_io, bs->tx_ptr, size);
|
||||
bs->remaining_bytes -= size;
|
||||
}
|
||||
|
||||
static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
|
||||
unsigned int num_transfers)
|
||||
{
|
||||
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
|
||||
u16 msg_ctl;
|
||||
u16 cmd;
|
||||
u8 rx_tail;
|
||||
unsigned int i, timeout = 0, prepend_len = 0, len = 0;
|
||||
struct spi_transfer *t = first;
|
||||
bool do_rx = false;
|
||||
bool do_tx = false;
|
||||
|
||||
/* Disable the CMD_DONE interrupt */
|
||||
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
|
||||
|
@ -200,25 +189,45 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
|
|||
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
|
||||
t->tx_buf, t->rx_buf, t->len);
|
||||
|
||||
/* Transmitter is inhibited */
|
||||
bs->tx_ptr = t->tx_buf;
|
||||
bs->rx_ptr = t->rx_buf;
|
||||
if (num_transfers > 1 && t->tx_buf && t->len <= BCM63XX_SPI_MAX_PREPEND)
|
||||
prepend_len = t->len;
|
||||
|
||||
if (t->tx_buf) {
|
||||
bs->remaining_bytes = t->len;
|
||||
bcm63xx_spi_fill_tx_fifo(bs);
|
||||
/* prepare the buffer */
|
||||
for (i = 0; i < num_transfers; i++) {
|
||||
if (t->tx_buf) {
|
||||
do_tx = true;
|
||||
memcpy_toio(bs->tx_io + len, t->tx_buf, t->len);
|
||||
|
||||
/* don't prepend more than one tx */
|
||||
if (t != first)
|
||||
prepend_len = 0;
|
||||
}
|
||||
|
||||
if (t->rx_buf) {
|
||||
do_rx = true;
|
||||
/* prepend is half-duplex write only */
|
||||
if (t == first)
|
||||
prepend_len = 0;
|
||||
}
|
||||
|
||||
len += t->len;
|
||||
|
||||
t = list_entry(t->transfer_list.next, struct spi_transfer,
|
||||
transfer_list);
|
||||
}
|
||||
|
||||
len -= prepend_len;
|
||||
|
||||
init_completion(&bs->done);
|
||||
|
||||
/* Fill in the Message control register */
|
||||
msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
|
||||
msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
|
||||
|
||||
if (t->rx_buf && t->tx_buf)
|
||||
if (do_rx && do_tx && prepend_len == 0)
|
||||
msg_ctl |= (SPI_FD_RW << bs->msg_type_shift);
|
||||
else if (t->rx_buf)
|
||||
else if (do_rx)
|
||||
msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
|
||||
else if (t->tx_buf)
|
||||
else if (do_tx)
|
||||
msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
|
||||
|
||||
switch (bs->msg_ctl_width) {
|
||||
|
@ -232,14 +241,41 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
|
|||
|
||||
/* Issue the transfer */
|
||||
cmd = SPI_CMD_START_IMMEDIATE;
|
||||
cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
|
||||
cmd |= (prepend_len << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
|
||||
cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
|
||||
bcm_spi_writew(bs, cmd, SPI_CMD);
|
||||
|
||||
/* Enable the CMD_DONE interrupt */
|
||||
bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
|
||||
|
||||
return t->len - bs->remaining_bytes;
|
||||
timeout = wait_for_completion_timeout(&bs->done, HZ);
|
||||
if (!timeout)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* read out all data */
|
||||
rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
|
||||
|
||||
if (do_rx && rx_tail != len)
|
||||
return -EIO;
|
||||
|
||||
if (!rx_tail)
|
||||
return 0;
|
||||
|
||||
len = 0;
|
||||
t = first;
|
||||
/* Read out all the data */
|
||||
for (i = 0; i < num_transfers; i++) {
|
||||
if (t->rx_buf)
|
||||
memcpy_fromio(t->rx_buf, bs->rx_io + len, t->len);
|
||||
|
||||
if (t != first || prepend_len == 0)
|
||||
len += t->len;
|
||||
|
||||
t = list_entry(t->transfer_list.next, struct spi_transfer,
|
||||
transfer_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
|
||||
|
@ -264,41 +300,76 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
|
|||
struct spi_message *m)
|
||||
{
|
||||
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
|
||||
struct spi_transfer *t;
|
||||
struct spi_transfer *t, *first = NULL;
|
||||
struct spi_device *spi = m->spi;
|
||||
int status = 0;
|
||||
unsigned int timeout = 0;
|
||||
unsigned int n_transfers = 0, total_len = 0;
|
||||
bool can_use_prepend = false;
|
||||
|
||||
/*
|
||||
* This SPI controller does not support keeping CS active after a
|
||||
* transfer.
|
||||
* Work around this by merging as many transfers we can into one big
|
||||
* full-duplex transfers.
|
||||
*/
|
||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||
unsigned int len = t->len;
|
||||
u8 rx_tail;
|
||||
|
||||
status = bcm63xx_spi_check_transfer(spi, t);
|
||||
if (status < 0)
|
||||
goto exit;
|
||||
|
||||
/* configure adapter for a new transfer */
|
||||
bcm63xx_spi_setup_transfer(spi, t);
|
||||
if (!first)
|
||||
first = t;
|
||||
|
||||
while (len) {
|
||||
/* send the data */
|
||||
len -= bcm63xx_txrx_bufs(spi, t);
|
||||
n_transfers++;
|
||||
total_len += t->len;
|
||||
|
||||
timeout = wait_for_completion_timeout(&bs->done, HZ);
|
||||
if (!timeout) {
|
||||
status = -ETIMEDOUT;
|
||||
goto exit;
|
||||
}
|
||||
if (n_transfers == 2 && !first->rx_buf && !t->tx_buf &&
|
||||
first->len <= BCM63XX_SPI_MAX_PREPEND)
|
||||
can_use_prepend = true;
|
||||
else if (can_use_prepend && t->tx_buf)
|
||||
can_use_prepend = false;
|
||||
|
||||
/* read out all data */
|
||||
rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
|
||||
|
||||
/* Read out all the data */
|
||||
if (rx_tail)
|
||||
memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
|
||||
/* we can only transfer one fifo worth of data */
|
||||
if ((can_use_prepend &&
|
||||
total_len > (bs->fifo_size + BCM63XX_SPI_MAX_PREPEND)) ||
|
||||
(!can_use_prepend && total_len > bs->fifo_size)) {
|
||||
dev_err(&spi->dev, "unable to do transfers larger than FIFO size (%i > %i)\n",
|
||||
total_len, bs->fifo_size);
|
||||
status = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
m->actual_length += t->len;
|
||||
/* all combined transfers have to have the same speed */
|
||||
if (t->speed_hz != first->speed_hz) {
|
||||
dev_err(&spi->dev, "unable to change speed between transfers\n");
|
||||
status = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* CS will be deasserted directly after transfer */
|
||||
if (t->delay_usecs) {
|
||||
dev_err(&spi->dev, "unable to keep CS asserted after transfer\n");
|
||||
status = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (t->cs_change ||
|
||||
list_is_last(&t->transfer_list, &m->transfers)) {
|
||||
/* configure adapter for a new transfer */
|
||||
bcm63xx_spi_setup_transfer(spi, first);
|
||||
|
||||
/* send the data */
|
||||
status = bcm63xx_txrx_bufs(spi, first, n_transfers);
|
||||
if (status)
|
||||
goto exit;
|
||||
|
||||
m->actual_length += total_len;
|
||||
|
||||
first = NULL;
|
||||
n_transfers = 0;
|
||||
total_len = 0;
|
||||
can_use_prepend = false;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
m->status = status;
|
||||
|
|
|
@ -416,8 +416,7 @@ bfin_sport_spi_pump_transfers(unsigned long data)
|
|||
drv_data->cs_change = transfer->cs_change;
|
||||
|
||||
/* Bits per word setup */
|
||||
bits_per_word = transfer->bits_per_word ? :
|
||||
message->spi->bits_per_word ? : 8;
|
||||
bits_per_word = transfer->bits_per_word;
|
||||
if (bits_per_word % 16 == 0)
|
||||
drv_data->ops = &bfin_sport_transfer_ops_u16;
|
||||
else
|
||||
|
|
|
@ -642,8 +642,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
|
|||
drv_data->cs_change = transfer->cs_change;
|
||||
|
||||
/* Bits per word setup */
|
||||
bits_per_word = transfer->bits_per_word ? :
|
||||
message->spi->bits_per_word ? : 8;
|
||||
bits_per_word = transfer->bits_per_word;
|
||||
if (bits_per_word % 16 == 0) {
|
||||
drv_data->n_bytes = bits_per_word/8;
|
||||
drv_data->len = (transfer->len) >> 1;
|
||||
|
@ -1274,7 +1273,7 @@ static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init bfin_spi_probe(struct platform_device *pdev)
|
||||
static int bfin_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bfin5xx_spi_master *platform_info;
|
||||
|
|
|
@ -69,7 +69,7 @@ static unsigned bitbang_txrx_8(
|
|||
unsigned ns,
|
||||
struct spi_transfer *t
|
||||
) {
|
||||
unsigned bits = t->bits_per_word ? : spi->bits_per_word;
|
||||
unsigned bits = t->bits_per_word;
|
||||
unsigned count = t->len;
|
||||
const u8 *tx = t->tx_buf;
|
||||
u8 *rx = t->rx_buf;
|
||||
|
@ -95,7 +95,7 @@ static unsigned bitbang_txrx_16(
|
|||
unsigned ns,
|
||||
struct spi_transfer *t
|
||||
) {
|
||||
unsigned bits = t->bits_per_word ? : spi->bits_per_word;
|
||||
unsigned bits = t->bits_per_word;
|
||||
unsigned count = t->len;
|
||||
const u16 *tx = t->tx_buf;
|
||||
u16 *rx = t->rx_buf;
|
||||
|
@ -121,7 +121,7 @@ static unsigned bitbang_txrx_32(
|
|||
unsigned ns,
|
||||
struct spi_transfer *t
|
||||
) {
|
||||
unsigned bits = t->bits_per_word ? : spi->bits_per_word;
|
||||
unsigned bits = t->bits_per_word;
|
||||
unsigned count = t->len;
|
||||
const u32 *tx = t->tx_buf;
|
||||
u32 *rx = t->rx_buf;
|
||||
|
@ -427,40 +427,41 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
|
|||
*/
|
||||
int spi_bitbang_start(struct spi_bitbang *bitbang)
|
||||
{
|
||||
int status;
|
||||
struct spi_master *master = bitbang->master;
|
||||
int status;
|
||||
|
||||
if (!bitbang->master || !bitbang->chipselect)
|
||||
if (!master || !bitbang->chipselect)
|
||||
return -EINVAL;
|
||||
|
||||
INIT_WORK(&bitbang->work, bitbang_work);
|
||||
spin_lock_init(&bitbang->lock);
|
||||
INIT_LIST_HEAD(&bitbang->queue);
|
||||
|
||||
if (!bitbang->master->mode_bits)
|
||||
bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
|
||||
if (!master->mode_bits)
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
|
||||
|
||||
if (!bitbang->master->transfer)
|
||||
bitbang->master->transfer = spi_bitbang_transfer;
|
||||
if (!master->transfer)
|
||||
master->transfer = spi_bitbang_transfer;
|
||||
if (!bitbang->txrx_bufs) {
|
||||
bitbang->use_dma = 0;
|
||||
bitbang->txrx_bufs = spi_bitbang_bufs;
|
||||
if (!bitbang->master->setup) {
|
||||
if (!master->setup) {
|
||||
if (!bitbang->setup_transfer)
|
||||
bitbang->setup_transfer =
|
||||
spi_bitbang_setup_transfer;
|
||||
bitbang->master->setup = spi_bitbang_setup;
|
||||
bitbang->master->cleanup = spi_bitbang_cleanup;
|
||||
master->setup = spi_bitbang_setup;
|
||||
master->cleanup = spi_bitbang_cleanup;
|
||||
}
|
||||
} else if (!bitbang->master->setup)
|
||||
} else if (!master->setup)
|
||||
return -EINVAL;
|
||||
if (bitbang->master->transfer == spi_bitbang_transfer &&
|
||||
if (master->transfer == spi_bitbang_transfer &&
|
||||
!bitbang->setup_transfer)
|
||||
return -EINVAL;
|
||||
|
||||
/* this task is the only thing to touch the SPI bits */
|
||||
bitbang->busy = 0;
|
||||
bitbang->workqueue = create_singlethread_workqueue(
|
||||
dev_name(bitbang->master->dev.parent));
|
||||
dev_name(master->dev.parent));
|
||||
if (bitbang->workqueue == NULL) {
|
||||
status = -EBUSY;
|
||||
goto err1;
|
||||
|
@ -469,7 +470,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
|
|||
/* driver may get busy before register() returns, especially
|
||||
* if someone registered boardinfo for devices
|
||||
*/
|
||||
status = spi_register_master(bitbang->master);
|
||||
status = spi_register_master(master);
|
||||
if (status < 0)
|
||||
goto err2;
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ 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;
|
||||
u8 bpw = xfer->bits_per_word;
|
||||
struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (bpw != 8) {
|
||||
|
|
|
@ -329,8 +329,7 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
|
|||
mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
|
||||
|
||||
mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
|
||||
if ((t->bits_per_word ? t->bits_per_word :
|
||||
spi->bits_per_word) == 8)
|
||||
if (t->bits_per_word == 8)
|
||||
mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
|
||||
t->rx_buf);
|
||||
else
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/edma.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_bitbang.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -135,7 +137,7 @@ struct davinci_spi {
|
|||
int dma_rx_chnum;
|
||||
int dma_tx_chnum;
|
||||
|
||||
struct davinci_spi_platform_data *pdata;
|
||||
struct davinci_spi_platform_data pdata;
|
||||
|
||||
void (*get_rx)(u32 rx_data, struct davinci_spi *);
|
||||
u32 (*get_tx)(struct davinci_spi *);
|
||||
|
@ -213,7 +215,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
|
|||
bool gpio_chipsel = false;
|
||||
|
||||
dspi = spi_master_get_devdata(spi->master);
|
||||
pdata = dspi->pdata;
|
||||
pdata = &dspi->pdata;
|
||||
|
||||
if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&
|
||||
pdata->chip_sel[chip_sel] != SPI_INTERN_CS)
|
||||
|
@ -392,7 +394,7 @@ static int davinci_spi_setup(struct spi_device *spi)
|
|||
struct davinci_spi_platform_data *pdata;
|
||||
|
||||
dspi = spi_master_get_devdata(spi->master);
|
||||
pdata = dspi->pdata;
|
||||
pdata = &dspi->pdata;
|
||||
|
||||
/* if bits per word length is zero then set it default 8 */
|
||||
if (!spi->bits_per_word)
|
||||
|
@ -534,7 +536,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
|||
struct scatterlist sg_rx, sg_tx;
|
||||
|
||||
dspi = spi_master_get_devdata(spi->master);
|
||||
pdata = dspi->pdata;
|
||||
pdata = &dspi->pdata;
|
||||
spicfg = (struct davinci_spi_config *)spi->controller_data;
|
||||
if (!spicfg)
|
||||
spicfg = &davinci_spi_default_cfg;
|
||||
|
@ -699,6 +701,19 @@ err_alloc_dummy_buf:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dummy_thread_fn - dummy thread function
|
||||
* @irq: IRQ number for this SPI Master
|
||||
* @context_data: structure for SPI Master controller davinci_spi
|
||||
*
|
||||
* This is to satisfy the request_threaded_irq() API so that the irq
|
||||
* handler is called in interrupt context.
|
||||
*/
|
||||
static irqreturn_t dummy_thread_fn(s32 irq, void *data)
|
||||
{
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* davinci_spi_irq - Interrupt handler for SPI Master Controller
|
||||
* @irq: IRQ number for this SPI Master
|
||||
|
@ -758,6 +773,70 @@ rx_dma_failed:
|
|||
return r;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id davinci_spi_of_match[] = {
|
||||
{
|
||||
.compatible = "ti,dm644x-spi",
|
||||
},
|
||||
{
|
||||
.compatible = "ti,da8xx-spi",
|
||||
.data = (void *)SPI_VERSION_2,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, davini_spi_of_match);
|
||||
|
||||
/**
|
||||
* spi_davinci_get_pdata - Get platform data from DTS binding
|
||||
* @pdev: ptr to platform data
|
||||
* @dspi: ptr to driver data
|
||||
*
|
||||
* Parses and populates pdata in dspi from device tree bindings.
|
||||
*
|
||||
* NOTE: Not all platform data params are supported currently.
|
||||
*/
|
||||
static int spi_davinci_get_pdata(struct platform_device *pdev,
|
||||
struct davinci_spi *dspi)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct davinci_spi_platform_data *pdata;
|
||||
unsigned int num_cs, intr_line = 0;
|
||||
const struct of_device_id *match;
|
||||
|
||||
pdata = &dspi->pdata;
|
||||
|
||||
pdata->version = SPI_VERSION_1;
|
||||
match = of_match_device(of_match_ptr(davinci_spi_of_match),
|
||||
&pdev->dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
/* match data has the SPI version number for SPI_VERSION_2 */
|
||||
if (match->data == (void *)SPI_VERSION_2)
|
||||
pdata->version = SPI_VERSION_2;
|
||||
|
||||
/*
|
||||
* default num_cs is 1 and all chipsel are internal to the chip
|
||||
* indicated by chip_sel being NULL. GPIO based CS is not
|
||||
* supported yet in DT bindings.
|
||||
*/
|
||||
num_cs = 1;
|
||||
of_property_read_u32(node, "num-cs", &num_cs);
|
||||
pdata->num_chipselect = num_cs;
|
||||
of_property_read_u32(node, "ti,davinci-spi-intr-line", &intr_line);
|
||||
pdata->intr_line = intr_line;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define davinci_spi_of_match NULL
|
||||
static struct davinci_spi_platform_data
|
||||
*spi_davinci_get_pdata(struct platform_device *pdev,
|
||||
struct davinci_spi *dspi)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* davinci_spi_probe - probe function for SPI Master Controller
|
||||
* @pdev: platform_device structure which contains plateform specific data
|
||||
|
@ -780,12 +859,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
|||
int i = 0, ret = 0;
|
||||
u32 spipc0;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
|
||||
if (master == NULL) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -800,6 +873,19 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
|||
goto free_master;
|
||||
}
|
||||
|
||||
if (pdev->dev.platform_data) {
|
||||
pdata = pdev->dev.platform_data;
|
||||
dspi->pdata = *pdata;
|
||||
} else {
|
||||
/* update dspi pdata with that from the DT */
|
||||
ret = spi_davinci_get_pdata(pdev, dspi);
|
||||
if (ret < 0)
|
||||
goto free_master;
|
||||
}
|
||||
|
||||
/* pdata in dspi is now updated and point pdata to that */
|
||||
pdata = &dspi->pdata;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (r == NULL) {
|
||||
ret = -ENOENT;
|
||||
|
@ -807,7 +893,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
dspi->pbase = r->start;
|
||||
dspi->pdata = pdata;
|
||||
|
||||
mem = request_mem_region(r->start, resource_size(r), pdev->name);
|
||||
if (mem == NULL) {
|
||||
|
@ -827,8 +912,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
|||
goto unmap_io;
|
||||
}
|
||||
|
||||
ret = request_irq(dspi->irq, davinci_spi_irq, 0, dev_name(&pdev->dev),
|
||||
dspi);
|
||||
ret = request_threaded_irq(dspi->irq, davinci_spi_irq, dummy_thread_fn,
|
||||
0, dev_name(&pdev->dev), dspi);
|
||||
if (ret)
|
||||
goto unmap_io;
|
||||
|
||||
|
@ -843,8 +928,9 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
|||
ret = -ENODEV;
|
||||
goto put_master;
|
||||
}
|
||||
clk_enable(dspi->clk);
|
||||
clk_prepare_enable(dspi->clk);
|
||||
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
master->bus_num = pdev->id;
|
||||
master->num_chipselect = pdata->num_chipselect;
|
||||
master->setup = davinci_spi_setup;
|
||||
|
@ -927,7 +1013,7 @@ free_dma:
|
|||
dma_release_channel(dspi->dma_rx);
|
||||
dma_release_channel(dspi->dma_tx);
|
||||
free_clk:
|
||||
clk_disable(dspi->clk);
|
||||
clk_disable_unprepare(dspi->clk);
|
||||
clk_put(dspi->clk);
|
||||
put_master:
|
||||
spi_master_put(master);
|
||||
|
@ -963,7 +1049,7 @@ static int davinci_spi_remove(struct platform_device *pdev)
|
|||
|
||||
spi_bitbang_stop(&dspi->bitbang);
|
||||
|
||||
clk_disable(dspi->clk);
|
||||
clk_disable_unprepare(dspi->clk);
|
||||
clk_put(dspi->clk);
|
||||
spi_master_put(master);
|
||||
free_irq(dspi->irq, dspi);
|
||||
|
@ -978,6 +1064,7 @@ static struct platform_driver davinci_spi_driver = {
|
|||
.driver = {
|
||||
.name = "spi_davinci",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = davinci_spi_of_match,
|
||||
},
|
||||
.probe = davinci_spi_probe,
|
||||
.remove = davinci_spi_remove,
|
||||
|
|
|
@ -446,7 +446,7 @@ static inline int bits_per_word(const struct ep93xx_spi *espi)
|
|||
struct spi_message *msg = espi->current_msg;
|
||||
struct spi_transfer *t = msg->state;
|
||||
|
||||
return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
|
||||
return t->bits_per_word;
|
||||
}
|
||||
|
||||
static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
|
||||
|
|
|
@ -398,7 +398,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
|
|||
}
|
||||
|
||||
m->status = ret;
|
||||
m->complete(m->context);
|
||||
spi_finalize_current_message(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -423,6 +423,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
|
|||
|
||||
master->mode_bits = SPI_MODE_3;
|
||||
master->num_chipselect = 1;
|
||||
master->flags = SPI_MASTER_HALF_DUPLEX;
|
||||
master->bus_num = -1;
|
||||
master->setup = falcon_sflash_setup;
|
||||
master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
|
||||
|
|
|
@ -365,9 +365,26 @@ static int spi_gpio_probe_dt(struct platform_device *pdev)
|
|||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata->sck = of_get_named_gpio(np, "gpio-sck", 0);
|
||||
pdata->miso = of_get_named_gpio(np, "gpio-miso", 0);
|
||||
pdata->mosi = of_get_named_gpio(np, "gpio-mosi", 0);
|
||||
ret = of_get_named_gpio(np, "gpio-sck", 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "gpio-sck property not found\n");
|
||||
goto error_free;
|
||||
}
|
||||
pdata->sck = ret;
|
||||
|
||||
ret = of_get_named_gpio(np, "gpio-miso", 0);
|
||||
if (ret < 0) {
|
||||
dev_info(&pdev->dev, "gpio-miso property not found, switching to no-rx mode\n");
|
||||
pdata->miso = SPI_GPIO_NO_MISO;
|
||||
} else
|
||||
pdata->miso = ret;
|
||||
|
||||
ret = of_get_named_gpio(np, "gpio-mosi", 0);
|
||||
if (ret < 0) {
|
||||
dev_info(&pdev->dev, "gpio-mosi property not found, switching to no-tx mode\n");
|
||||
pdata->mosi = SPI_GPIO_NO_MOSI;
|
||||
} else
|
||||
pdata->mosi = ret;
|
||||
|
||||
ret = of_property_read_u32(np, "num-chipselects", &tmp);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -949,3 +949,4 @@ module_platform_driver(spi_imx_driver);
|
|||
MODULE_DESCRIPTION("SPI Master Controller driver");
|
||||
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
|
|
|
@ -438,6 +438,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
|||
master->num_chipselect = pdata->max_chipselect;
|
||||
}
|
||||
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
|
||||
master->setup = mpc512x_psc_spi_setup;
|
||||
master->transfer = mpc512x_psc_spi_transfer;
|
||||
master->cleanup = mpc512x_psc_spi_cleanup;
|
||||
|
@ -522,17 +523,11 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
|
|||
regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
|
||||
|
||||
/* get PSC id (0..11, used by port_config) */
|
||||
if (op->dev.platform_data == NULL) {
|
||||
const u32 *psc_nump;
|
||||
|
||||
psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL);
|
||||
if (!psc_nump || *psc_nump > 11) {
|
||||
dev_err(&op->dev, "mpc512x_psc_spi: Device node %s "
|
||||
"has invalid cell-index property\n",
|
||||
op->dev.of_node->full_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
id = *psc_nump;
|
||||
id = of_alias_get_id(op->dev.of_node, "spi");
|
||||
if (id < 0) {
|
||||
dev_err(&op->dev, "no alias id for %s\n",
|
||||
op->dev.of_node->full_name);
|
||||
return id;
|
||||
}
|
||||
|
||||
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
|
||||
|
|
|
@ -241,6 +241,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
|
|||
INIT_COMPLETION(spi->c);
|
||||
|
||||
ctrl0 = readl(ssp->base + HW_SSP_CTRL0);
|
||||
ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT;
|
||||
ctrl0 |= BM_SSP_CTRL0_DATA_XFER | mxs_spi_cs_to_reg(cs);
|
||||
|
||||
if (*first)
|
||||
|
@ -256,8 +257,10 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
|
|||
if ((sg_count + 1 == sgs) && *last)
|
||||
ctrl0 |= BM_SSP_CTRL0_IGNORE_CRC;
|
||||
|
||||
if (ssp->devid == IMX23_SSP)
|
||||
if (ssp->devid == IMX23_SSP) {
|
||||
ctrl0 &= ~BM_SSP_CTRL0_XFER_COUNT;
|
||||
ctrl0 |= min;
|
||||
}
|
||||
|
||||
dma_xfer[sg_count].pio[0] = ctrl0;
|
||||
dma_xfer[sg_count].pio[3] = min;
|
||||
|
|
|
@ -481,7 +481,7 @@ static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init omap1_spi100k_reset(struct omap1_spi100k *spi100k)
|
||||
static int omap1_spi100k_reset(struct omap1_spi100k *spi100k)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -560,7 +560,7 @@ err1:
|
|||
return status;
|
||||
}
|
||||
|
||||
static int __exit omap1_spi100k_remove(struct platform_device *pdev)
|
||||
static int omap1_spi100k_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct omap1_spi100k *spi100k;
|
||||
|
@ -604,7 +604,7 @@ static struct platform_driver omap1_spi100k_driver = {
|
|||
.name = "omap1_spi100k",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.remove = __exit_p(omap1_spi100k_remove),
|
||||
.remove = omap1_spi100k_remove,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -476,7 +476,7 @@ static void uwire_off(struct uwire_spi *uwire)
|
|||
spi_master_put(uwire->bitbang.master);
|
||||
}
|
||||
|
||||
static int __init uwire_probe(struct platform_device *pdev)
|
||||
static int uwire_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct uwire_spi *uwire;
|
||||
|
@ -536,7 +536,7 @@ static int __init uwire_probe(struct platform_device *pdev)
|
|||
return status;
|
||||
}
|
||||
|
||||
static int __exit uwire_remove(struct platform_device *pdev)
|
||||
static int uwire_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev);
|
||||
int status;
|
||||
|
@ -557,7 +557,7 @@ static struct platform_driver uwire_driver = {
|
|||
.name = "omap_uwire",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.remove = __exit_p(uwire_remove),
|
||||
.remove = uwire_remove,
|
||||
// suspend ... unuse ck
|
||||
// resume ... use ck
|
||||
};
|
||||
|
|
|
@ -298,10 +298,10 @@ static void omap2_mcspi_rx_callback(void *data)
|
|||
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
|
||||
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
|
||||
complete(&mcspi_dma->dma_rx_completion);
|
||||
|
||||
/* We must disable the DMA RX request */
|
||||
omap2_mcspi_set_dma_req(spi, 1, 0);
|
||||
|
||||
complete(&mcspi_dma->dma_rx_completion);
|
||||
}
|
||||
|
||||
static void omap2_mcspi_tx_callback(void *data)
|
||||
|
@ -310,10 +310,10 @@ static void omap2_mcspi_tx_callback(void *data)
|
|||
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
|
||||
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
|
||||
complete(&mcspi_dma->dma_tx_completion);
|
||||
|
||||
/* We must disable the DMA TX request */
|
||||
omap2_mcspi_set_dma_req(spi, 0, 0);
|
||||
|
||||
complete(&mcspi_dma->dma_tx_completion);
|
||||
}
|
||||
|
||||
static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
||||
|
@ -927,6 +927,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
|||
|
||||
struct spi_device *spi;
|
||||
struct spi_transfer *t = NULL;
|
||||
struct spi_master *master;
|
||||
int cs_active = 0;
|
||||
struct omap2_mcspi_cs *cs;
|
||||
struct omap2_mcspi_device_config *cd;
|
||||
|
@ -935,6 +936,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
|||
u32 chconf;
|
||||
|
||||
spi = m->spi;
|
||||
master = spi->master;
|
||||
cs = spi->controller_state;
|
||||
cd = spi->controller_data;
|
||||
|
||||
|
@ -952,6 +954,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
|||
if (!t->speed_hz && !t->bits_per_word)
|
||||
par_override = 0;
|
||||
}
|
||||
if (cd && cd->cs_per_word) {
|
||||
chconf = mcspi->ctx.modulctrl;
|
||||
chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
|
||||
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
|
||||
mcspi->ctx.modulctrl =
|
||||
mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
|
||||
}
|
||||
|
||||
|
||||
if (!cs_active) {
|
||||
omap2_mcspi_force_cs(spi, 1);
|
||||
|
@ -1013,6 +1023,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
|||
if (cs_active)
|
||||
omap2_mcspi_force_cs(spi, 0);
|
||||
|
||||
if (cd && cd->cs_per_word) {
|
||||
chconf = mcspi->ctx.modulctrl;
|
||||
chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
|
||||
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
|
||||
mcspi->ctx.modulctrl =
|
||||
mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
|
||||
}
|
||||
|
||||
omap2_mcspi_set_enable(spi, 0);
|
||||
|
||||
m->status = status;
|
||||
|
@ -1020,7 +1038,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
|||
}
|
||||
|
||||
static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|
||||
struct spi_message *m)
|
||||
struct spi_message *m)
|
||||
{
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct spi_transfer *t;
|
||||
|
@ -1041,7 +1059,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|
|||
|| (len && !(rx_buf || tx_buf))
|
||||
|| (t->bits_per_word &&
|
||||
( t->bits_per_word < 4
|
||||
|| t->bits_per_word > 32))) {
|
||||
|| t->bits_per_word > 32))) {
|
||||
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
|
||||
t->speed_hz,
|
||||
len,
|
||||
|
@ -1052,8 +1070,8 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|
|||
}
|
||||
if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
|
||||
dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
|
||||
t->speed_hz,
|
||||
OMAP2_MCSPI_MAX_FREQ >> 15);
|
||||
t->speed_hz,
|
||||
OMAP2_MCSPI_MAX_FREQ >> 15);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1117,7 @@ static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
|
|||
return ret;
|
||||
|
||||
mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
|
||||
OMAP2_MCSPI_WAKEUPENABLE_WKEN);
|
||||
OMAP2_MCSPI_WAKEUPENABLE_WKEN);
|
||||
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
|
||||
|
||||
omap2_mcspi_set_master_mode(master);
|
||||
|
@ -1228,7 +1246,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
|||
|
||||
sprintf(dma_ch_name, "rx%d", i);
|
||||
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
|
||||
dma_ch_name);
|
||||
dma_ch_name);
|
||||
if (!dma_res) {
|
||||
dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
|
||||
status = -ENODEV;
|
||||
|
@ -1238,7 +1256,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
|||
mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
|
||||
sprintf(dma_ch_name, "tx%d", i);
|
||||
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
|
||||
dma_ch_name);
|
||||
dma_ch_name);
|
||||
if (!dma_res) {
|
||||
dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
|
||||
status = -ENODEV;
|
||||
|
@ -1254,7 +1272,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
|||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl))
|
||||
dev_warn(&pdev->dev,
|
||||
"pins are not configured from the driver\n");
|
||||
"pins are not configured from the driver\n");
|
||||
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
|
||||
|
|
|
@ -366,7 +366,7 @@ msg_done:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init orion_spi_reset(struct orion_spi *orion_spi)
|
||||
static int orion_spi_reset(struct orion_spi *orion_spi)
|
||||
{
|
||||
/* Verify that the CS is deasserted */
|
||||
orion_spi_set_cs(orion_spi, 0);
|
||||
|
@ -396,7 +396,7 @@ static int orion_spi_setup(struct spi_device *spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init orion_spi_probe(struct platform_device *pdev)
|
||||
static int orion_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct orion_spi *spi;
|
||||
|
@ -479,7 +479,7 @@ out:
|
|||
}
|
||||
|
||||
|
||||
static int __exit orion_spi_remove(struct platform_device *pdev)
|
||||
static int orion_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct resource *r;
|
||||
|
@ -513,20 +513,11 @@ static struct platform_driver orion_spi_driver = {
|
|||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(orion_spi_of_match_table),
|
||||
},
|
||||
.remove = __exit_p(orion_spi_remove),
|
||||
.probe = orion_spi_probe,
|
||||
.remove = orion_spi_remove,
|
||||
};
|
||||
|
||||
static int __init orion_spi_init(void)
|
||||
{
|
||||
return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
|
||||
}
|
||||
module_init(orion_spi_init);
|
||||
|
||||
static void __exit orion_spi_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&orion_spi_driver);
|
||||
}
|
||||
module_exit(orion_spi_exit);
|
||||
module_platform_driver(orion_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Orion SPI driver");
|
||||
MODULE_AUTHOR("Shadi Ammouri <shadi@marvell.com>");
|
||||
|
|
|
@ -389,7 +389,7 @@ static void free_gpios(struct ppc4xx_spi *hw)
|
|||
/*
|
||||
* platform_device layer stuff...
|
||||
*/
|
||||
static int __init spi_ppc4xx_of_probe(struct platform_device *op)
|
||||
static int spi_ppc4xx_of_probe(struct platform_device *op)
|
||||
{
|
||||
struct ppc4xx_spi *hw;
|
||||
struct spi_master *master;
|
||||
|
@ -560,7 +560,7 @@ free_master:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __exit spi_ppc4xx_of_remove(struct platform_device *op)
|
||||
static int spi_ppc4xx_of_remove(struct platform_device *op)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(&op->dev);
|
||||
struct ppc4xx_spi *hw = spi_master_get_devdata(master);
|
||||
|
@ -583,7 +583,7 @@ MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
|
|||
|
||||
static struct platform_driver spi_ppc4xx_of_driver = {
|
||||
.probe = spi_ppc4xx_of_probe,
|
||||
.remove = __exit_p(spi_ppc4xx_of_remove),
|
||||
.remove = spi_ppc4xx_of_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* PXA2xx SPI DMA engine support.
|
||||
*
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/pxa2xx_ssp.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
|
||||
#include "spi-pxa2xx.h"
|
||||
|
||||
static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
int i, nents, len = drv_data->len;
|
||||
struct scatterlist *sg;
|
||||
struct device *dmadev;
|
||||
struct sg_table *sgt;
|
||||
void *buf, *pbuf;
|
||||
|
||||
/*
|
||||
* Some DMA controllers have problems transferring buffers that are
|
||||
* not multiple of 4 bytes. So we truncate the transfer so that it
|
||||
* is suitable for such controllers, and handle the trailing bytes
|
||||
* manually after the DMA completes.
|
||||
*
|
||||
* REVISIT: It would be better if this information could be
|
||||
* retrieved directly from the DMA device in a similar way than
|
||||
* ->copy_align etc. is done.
|
||||
*/
|
||||
len = ALIGN(drv_data->len, 4);
|
||||
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
dmadev = drv_data->tx_chan->device->dev;
|
||||
sgt = &drv_data->tx_sgt;
|
||||
buf = drv_data->tx;
|
||||
drv_data->tx_map_len = len;
|
||||
} else {
|
||||
dmadev = drv_data->rx_chan->device->dev;
|
||||
sgt = &drv_data->rx_sgt;
|
||||
buf = drv_data->rx;
|
||||
drv_data->rx_map_len = len;
|
||||
}
|
||||
|
||||
nents = DIV_ROUND_UP(len, SZ_2K);
|
||||
if (nents != sgt->nents) {
|
||||
int ret;
|
||||
|
||||
sg_free_table(sgt);
|
||||
ret = sg_alloc_table(sgt, nents, GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pbuf = buf;
|
||||
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
|
||||
size_t bytes = min_t(size_t, len, SZ_2K);
|
||||
|
||||
if (buf)
|
||||
sg_set_buf(sg, pbuf, bytes);
|
||||
else
|
||||
sg_set_buf(sg, drv_data->dummy, bytes);
|
||||
|
||||
pbuf += bytes;
|
||||
len -= bytes;
|
||||
}
|
||||
|
||||
nents = dma_map_sg(dmadev, sgt->sgl, sgt->nents, dir);
|
||||
if (!nents)
|
||||
return -ENOMEM;
|
||||
|
||||
return nents;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_unmap_dma_buffer(struct driver_data *drv_data,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct device *dmadev;
|
||||
struct sg_table *sgt;
|
||||
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
dmadev = drv_data->tx_chan->device->dev;
|
||||
sgt = &drv_data->tx_sgt;
|
||||
} else {
|
||||
dmadev = drv_data->rx_chan->device->dev;
|
||||
sgt = &drv_data->rx_sgt;
|
||||
}
|
||||
|
||||
dma_unmap_sg(dmadev, sgt->sgl, sgt->nents, dir);
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
|
||||
{
|
||||
if (!drv_data->dma_mapped)
|
||||
return;
|
||||
|
||||
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_FROM_DEVICE);
|
||||
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
|
||||
|
||||
drv_data->dma_mapped = 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
|
||||
bool error)
|
||||
{
|
||||
struct spi_message *msg = drv_data->cur_msg;
|
||||
|
||||
/*
|
||||
* It is possible that one CPU is handling ROR interrupt and other
|
||||
* just gets DMA completion. Calling pump_transfers() twice for the
|
||||
* same transfer leads to problems thus we prevent concurrent calls
|
||||
* by using ->dma_running.
|
||||
*/
|
||||
if (atomic_dec_and_test(&drv_data->dma_running)) {
|
||||
void __iomem *reg = drv_data->ioaddr;
|
||||
|
||||
/*
|
||||
* If the other CPU is still handling the ROR interrupt we
|
||||
* might not know about the error yet. So we re-check the
|
||||
* ROR bit here before we clear the status register.
|
||||
*/
|
||||
if (!error) {
|
||||
u32 status = read_SSSR(reg) & drv_data->mask_sr;
|
||||
error = status & SSSR_ROR;
|
||||
}
|
||||
|
||||
/* Clear status & disable interrupts */
|
||||
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||
if (!pxa25x_ssp_comp(drv_data))
|
||||
write_SSTO(0, reg);
|
||||
|
||||
if (!error) {
|
||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||
|
||||
/* Handle the last bytes of unaligned transfer */
|
||||
drv_data->tx += drv_data->tx_map_len;
|
||||
drv_data->write(drv_data);
|
||||
|
||||
drv_data->rx += drv_data->rx_map_len;
|
||||
drv_data->read(drv_data);
|
||||
|
||||
msg->actual_length += drv_data->len;
|
||||
msg->state = pxa2xx_spi_next_transfer(drv_data);
|
||||
} else {
|
||||
/* In case we got an error we disable the SSP now */
|
||||
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
||||
|
||||
msg->state = ERROR_STATE;
|
||||
}
|
||||
|
||||
tasklet_schedule(&drv_data->pump_transfers);
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_dma_callback(void *data)
|
||||
{
|
||||
pxa2xx_spi_dma_transfer_complete(data, false);
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
|
||||
enum dma_transfer_direction dir)
|
||||
{
|
||||
struct pxa2xx_spi_master *pdata = drv_data->master_info;
|
||||
struct chip_data *chip = drv_data->cur_chip;
|
||||
enum dma_slave_buswidth width;
|
||||
struct dma_slave_config cfg;
|
||||
struct dma_chan *chan;
|
||||
struct sg_table *sgt;
|
||||
int nents, ret;
|
||||
|
||||
switch (drv_data->n_bytes) {
|
||||
case 1:
|
||||
width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
break;
|
||||
case 2:
|
||||
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
break;
|
||||
default:
|
||||
width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.direction = dir;
|
||||
|
||||
if (dir == DMA_MEM_TO_DEV) {
|
||||
cfg.dst_addr = drv_data->ssdr_physical;
|
||||
cfg.dst_addr_width = width;
|
||||
cfg.dst_maxburst = chip->dma_burst_size;
|
||||
cfg.slave_id = pdata->tx_slave_id;
|
||||
|
||||
sgt = &drv_data->tx_sgt;
|
||||
nents = drv_data->tx_nents;
|
||||
chan = drv_data->tx_chan;
|
||||
} else {
|
||||
cfg.src_addr = drv_data->ssdr_physical;
|
||||
cfg.src_addr_width = width;
|
||||
cfg.src_maxburst = chip->dma_burst_size;
|
||||
cfg.slave_id = pdata->rx_slave_id;
|
||||
|
||||
sgt = &drv_data->rx_sgt;
|
||||
nents = drv_data->rx_nents;
|
||||
chan = drv_data->rx_chan;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(chan, &cfg);
|
||||
if (ret) {
|
||||
dev_warn(&drv_data->pdev->dev, "DMA slave config failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
}
|
||||
|
||||
static bool pxa2xx_spi_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
const struct pxa2xx_spi_master *pdata = param;
|
||||
|
||||
return chan->chan_id == pdata->tx_chan_id ||
|
||||
chan->chan_id == pdata->rx_chan_id;
|
||||
}
|
||||
|
||||
bool pxa2xx_spi_dma_is_possible(size_t len)
|
||||
{
|
||||
return len <= MAX_DMA_LEN;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
|
||||
{
|
||||
const struct chip_data *chip = drv_data->cur_chip;
|
||||
int ret;
|
||||
|
||||
if (!chip->enable_dma)
|
||||
return 0;
|
||||
|
||||
/* Don't bother with DMA if we can't do even a single burst */
|
||||
if (drv_data->len < chip->dma_burst_size)
|
||||
return 0;
|
||||
|
||||
ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_TO_DEVICE);
|
||||
if (ret <= 0) {
|
||||
dev_warn(&drv_data->pdev->dev, "failed to DMA map TX\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
drv_data->tx_nents = ret;
|
||||
|
||||
ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_FROM_DEVICE);
|
||||
if (ret <= 0) {
|
||||
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
|
||||
dev_warn(&drv_data->pdev->dev, "failed to DMA map RX\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
drv_data->rx_nents = ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = read_SSSR(drv_data->ioaddr) & drv_data->mask_sr;
|
||||
if (status & SSSR_ROR) {
|
||||
dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
|
||||
|
||||
dmaengine_terminate_all(drv_data->rx_chan);
|
||||
dmaengine_terminate_all(drv_data->tx_chan);
|
||||
|
||||
pxa2xx_spi_dma_transfer_complete(drv_data, true);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
|
||||
{
|
||||
struct dma_async_tx_descriptor *tx_desc, *rx_desc;
|
||||
|
||||
tx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_MEM_TO_DEV);
|
||||
if (!tx_desc) {
|
||||
dev_err(&drv_data->pdev->dev,
|
||||
"failed to get DMA TX descriptor\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
rx_desc = pxa2xx_spi_dma_prepare_one(drv_data, DMA_DEV_TO_MEM);
|
||||
if (!rx_desc) {
|
||||
dev_err(&drv_data->pdev->dev,
|
||||
"failed to get DMA RX descriptor\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* We are ready when RX completes */
|
||||
rx_desc->callback = pxa2xx_spi_dma_callback;
|
||||
rx_desc->callback_param = drv_data;
|
||||
|
||||
dmaengine_submit(rx_desc);
|
||||
dmaengine_submit(tx_desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_start(struct driver_data *drv_data)
|
||||
{
|
||||
dma_async_issue_pending(drv_data->rx_chan);
|
||||
dma_async_issue_pending(drv_data->tx_chan);
|
||||
|
||||
atomic_set(&drv_data->dma_running, 1);
|
||||
}
|
||||
|
||||
int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
|
||||
{
|
||||
struct pxa2xx_spi_master *pdata = drv_data->master_info;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
drv_data->dummy = devm_kzalloc(&drv_data->pdev->dev, SZ_2K, GFP_KERNEL);
|
||||
if (!drv_data->dummy)
|
||||
return -ENOMEM;
|
||||
|
||||
drv_data->tx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
|
||||
pdata);
|
||||
if (!drv_data->tx_chan)
|
||||
return -ENODEV;
|
||||
|
||||
drv_data->rx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
|
||||
pdata);
|
||||
if (!drv_data->rx_chan) {
|
||||
dma_release_channel(drv_data->tx_chan);
|
||||
drv_data->tx_chan = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_release(struct driver_data *drv_data)
|
||||
{
|
||||
if (drv_data->rx_chan) {
|
||||
dmaengine_terminate_all(drv_data->rx_chan);
|
||||
dma_release_channel(drv_data->rx_chan);
|
||||
sg_free_table(&drv_data->rx_sgt);
|
||||
drv_data->rx_chan = NULL;
|
||||
}
|
||||
if (drv_data->tx_chan) {
|
||||
dmaengine_terminate_all(drv_data->tx_chan);
|
||||
dma_release_channel(drv_data->tx_chan);
|
||||
sg_free_table(&drv_data->tx_sgt);
|
||||
drv_data->tx_chan = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_resume(struct driver_data *drv_data)
|
||||
{
|
||||
}
|
||||
|
||||
int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
|
||||
struct spi_device *spi,
|
||||
u8 bits_per_word, u32 *burst_code,
|
||||
u32 *threshold)
|
||||
{
|
||||
struct pxa2xx_spi_chip *chip_info = spi->controller_data;
|
||||
|
||||
/*
|
||||
* If the DMA burst size is given in chip_info we use that,
|
||||
* otherwise we use the default. Also we use the default FIFO
|
||||
* thresholds for now.
|
||||
*/
|
||||
*burst_code = chip_info ? chip_info->dma_burst_size : 16;
|
||||
*threshold = SSCR1_RxTresh(RX_THRESH_DFLT)
|
||||
| SSCR1_TxTresh(TX_THRESH_DFLT);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -8,147 +8,58 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
|
||||
struct ce4100_info {
|
||||
struct ssp_device ssp;
|
||||
struct platform_device *spi_pdev;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(ssp_lock);
|
||||
static LIST_HEAD(ssp_list);
|
||||
|
||||
struct ssp_device *pxa_ssp_request(int port, const char *label)
|
||||
{
|
||||
struct ssp_device *ssp = NULL;
|
||||
|
||||
mutex_lock(&ssp_lock);
|
||||
|
||||
list_for_each_entry(ssp, &ssp_list, node) {
|
||||
if (ssp->port_id == port && ssp->use_count == 0) {
|
||||
ssp->use_count++;
|
||||
ssp->label = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ssp_lock);
|
||||
|
||||
if (&ssp->node == &ssp_list)
|
||||
return NULL;
|
||||
|
||||
return ssp;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pxa_ssp_request);
|
||||
|
||||
void pxa_ssp_free(struct ssp_device *ssp)
|
||||
{
|
||||
mutex_lock(&ssp_lock);
|
||||
if (ssp->use_count) {
|
||||
ssp->use_count--;
|
||||
ssp->label = NULL;
|
||||
} else
|
||||
dev_err(&ssp->pdev->dev, "device already free\n");
|
||||
mutex_unlock(&ssp_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pxa_ssp_free);
|
||||
|
||||
static int ce4100_spi_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct platform_device_info pi;
|
||||
int ret;
|
||||
resource_size_t phys_beg;
|
||||
resource_size_t phys_len;
|
||||
struct ce4100_info *spi_info;
|
||||
struct platform_device *pdev;
|
||||
struct pxa2xx_spi_master spi_pdata;
|
||||
struct ssp_device *ssp;
|
||||
|
||||
ret = pci_enable_device(dev);
|
||||
ret = pcim_enable_device(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phys_beg = pci_resource_start(dev, 0);
|
||||
phys_len = pci_resource_len(dev, 0);
|
||||
|
||||
if (!request_mem_region(phys_beg, phys_len,
|
||||
"CE4100 SPI")) {
|
||||
dev_err(&dev->dev, "Can't request register space.\n");
|
||||
ret = -EBUSY;
|
||||
ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
|
||||
if (!ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
|
||||
spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
|
||||
if (!pdev || !spi_info ) {
|
||||
ret = -ENOMEM;
|
||||
goto err_nomem;
|
||||
}
|
||||
memset(&spi_pdata, 0, sizeof(spi_pdata));
|
||||
spi_pdata.num_chipselect = dev->devfn;
|
||||
|
||||
ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
|
||||
if (ret)
|
||||
goto err_nomem;
|
||||
|
||||
pdev->dev.parent = &dev->dev;
|
||||
pdev->dev.of_node = dev->dev.of_node;
|
||||
ssp = &spi_info->ssp;
|
||||
ssp = &spi_pdata.ssp;
|
||||
ssp->phys_base = pci_resource_start(dev, 0);
|
||||
ssp->mmio_base = ioremap(phys_beg, phys_len);
|
||||
ssp->mmio_base = pcim_iomap_table(dev)[0];
|
||||
if (!ssp->mmio_base) {
|
||||
dev_err(&pdev->dev, "failed to ioremap() registers\n");
|
||||
ret = -EIO;
|
||||
goto err_nomem;
|
||||
dev_err(&dev->dev, "failed to ioremap() registers\n");
|
||||
return -EIO;
|
||||
}
|
||||
ssp->irq = dev->irq;
|
||||
ssp->port_id = pdev->id;
|
||||
ssp->port_id = dev->devfn;
|
||||
ssp->type = PXA25x_SSP;
|
||||
|
||||
mutex_lock(&ssp_lock);
|
||||
list_add(&ssp->node, &ssp_list);
|
||||
mutex_unlock(&ssp_lock);
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
pi.parent = &dev->dev;
|
||||
pi.name = "pxa2xx-spi";
|
||||
pi.id = ssp->port_id;
|
||||
pi.data = &spi_pdata;
|
||||
pi.size_data = sizeof(spi_pdata);
|
||||
|
||||
pci_set_drvdata(dev, spi_info);
|
||||
pdev = platform_device_register_full(&pi);
|
||||
if (!pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto err_dev_add;
|
||||
pci_set_drvdata(dev, pdev);
|
||||
|
||||
return ret;
|
||||
|
||||
err_dev_add:
|
||||
pci_set_drvdata(dev, NULL);
|
||||
mutex_lock(&ssp_lock);
|
||||
list_del(&ssp->node);
|
||||
mutex_unlock(&ssp_lock);
|
||||
iounmap(ssp->mmio_base);
|
||||
|
||||
err_nomem:
|
||||
release_mem_region(phys_beg, phys_len);
|
||||
platform_device_put(pdev);
|
||||
kfree(spi_info);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ce4100_spi_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct ce4100_info *spi_info;
|
||||
struct ssp_device *ssp;
|
||||
struct platform_device *pdev = pci_get_drvdata(dev);
|
||||
|
||||
spi_info = pci_get_drvdata(dev);
|
||||
ssp = &spi_info->ssp;
|
||||
platform_device_unregister(spi_info->spi_pdev);
|
||||
|
||||
iounmap(ssp->mmio_base);
|
||||
release_mem_region(pci_resource_start(dev, 0),
|
||||
pci_resource_len(dev, 0));
|
||||
|
||||
mutex_lock(&ssp_lock);
|
||||
list_del(&ssp->node);
|
||||
mutex_unlock(&ssp_lock);
|
||||
|
||||
pci_set_drvdata(dev, NULL);
|
||||
pci_disable_device(dev);
|
||||
kfree(spi_info);
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = {
|
||||
|
|
|
@ -0,0 +1,490 @@
|
|||
/*
|
||||
* PXA2xx SPI private DMA support.
|
||||
*
|
||||
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pxa2xx_ssp.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
|
||||
#include "spi-pxa2xx.h"
|
||||
|
||||
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
|
||||
#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
|
||||
|
||||
bool pxa2xx_spi_dma_is_possible(size_t len)
|
||||
{
|
||||
/* Try to map dma buffer and do a dma transfer if successful, but
|
||||
* only if the length is non-zero and less than MAX_DMA_LEN.
|
||||
*
|
||||
* Zero-length non-descriptor DMA is illegal on PXA2xx; force use
|
||||
* of PIO instead. Care is needed above because the transfer may
|
||||
* have have been passed with buffers that are already dma mapped.
|
||||
* A zero-length transfer in PIO mode will not try to write/read
|
||||
* to/from the buffers
|
||||
*
|
||||
* REVISIT large transfers are exactly where we most want to be
|
||||
* using DMA. If this happens much, split those transfers into
|
||||
* multiple DMA segments rather than forcing PIO.
|
||||
*/
|
||||
return len > 0 && len <= MAX_DMA_LEN;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
|
||||
{
|
||||
struct spi_message *msg = drv_data->cur_msg;
|
||||
struct device *dev = &msg->spi->dev;
|
||||
|
||||
if (!drv_data->cur_chip->enable_dma)
|
||||
return 0;
|
||||
|
||||
if (msg->is_dma_mapped)
|
||||
return drv_data->rx_dma && drv_data->tx_dma;
|
||||
|
||||
if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
|
||||
return 0;
|
||||
|
||||
/* Modify setup if rx buffer is null */
|
||||
if (drv_data->rx == NULL) {
|
||||
*drv_data->null_dma_buf = 0;
|
||||
drv_data->rx = drv_data->null_dma_buf;
|
||||
drv_data->rx_map_len = 4;
|
||||
} else
|
||||
drv_data->rx_map_len = drv_data->len;
|
||||
|
||||
|
||||
/* Modify setup if tx buffer is null */
|
||||
if (drv_data->tx == NULL) {
|
||||
*drv_data->null_dma_buf = 0;
|
||||
drv_data->tx = drv_data->null_dma_buf;
|
||||
drv_data->tx_map_len = 4;
|
||||
} else
|
||||
drv_data->tx_map_len = drv_data->len;
|
||||
|
||||
/* Stream map the tx buffer. Always do DMA_TO_DEVICE first
|
||||
* so we flush the cache *before* invalidating it, in case
|
||||
* the tx and rx buffers overlap.
|
||||
*/
|
||||
drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
|
||||
drv_data->tx_map_len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dev, drv_data->tx_dma))
|
||||
return 0;
|
||||
|
||||
/* Stream map the rx buffer */
|
||||
drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
|
||||
drv_data->rx_map_len, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, drv_data->rx_dma)) {
|
||||
dma_unmap_single(dev, drv_data->tx_dma,
|
||||
drv_data->tx_map_len, DMA_TO_DEVICE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (!drv_data->dma_mapped)
|
||||
return;
|
||||
|
||||
if (!drv_data->cur_msg->is_dma_mapped) {
|
||||
dev = &drv_data->cur_msg->spi->dev;
|
||||
dma_unmap_single(dev, drv_data->rx_dma,
|
||||
drv_data->rx_map_len, DMA_FROM_DEVICE);
|
||||
dma_unmap_single(dev, drv_data->tx_dma,
|
||||
drv_data->tx_map_len, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
drv_data->dma_mapped = 0;
|
||||
}
|
||||
|
||||
static int wait_ssp_rx_stall(void const __iomem *ioaddr)
|
||||
{
|
||||
unsigned long limit = loops_per_jiffy << 1;
|
||||
|
||||
while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
|
||||
cpu_relax();
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
||||
static int wait_dma_channel_stop(int channel)
|
||||
{
|
||||
unsigned long limit = loops_per_jiffy << 1;
|
||||
|
||||
while (!(DCSR(channel) & DCSR_STOPSTATE) && --limit)
|
||||
cpu_relax();
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
|
||||
const char *msg)
|
||||
{
|
||||
void __iomem *reg = drv_data->ioaddr;
|
||||
|
||||
/* Stop and reset */
|
||||
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
||||
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
||||
if (!pxa25x_ssp_comp(drv_data))
|
||||
write_SSTO(0, reg);
|
||||
pxa2xx_spi_flush(drv_data);
|
||||
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
||||
|
||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||
|
||||
dev_err(&drv_data->pdev->dev, "%s\n", msg);
|
||||
|
||||
drv_data->cur_msg->state = ERROR_STATE;
|
||||
tasklet_schedule(&drv_data->pump_transfers);
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data)
|
||||
{
|
||||
void __iomem *reg = drv_data->ioaddr;
|
||||
struct spi_message *msg = drv_data->cur_msg;
|
||||
|
||||
/* Clear and disable interrupts on SSP and DMA channels*/
|
||||
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
||||
write_SSSR_CS(drv_data, drv_data->clear_sr);
|
||||
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
||||
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
||||
|
||||
if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
|
||||
dev_err(&drv_data->pdev->dev,
|
||||
"dma_handler: dma rx channel stop failed\n");
|
||||
|
||||
if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
|
||||
dev_err(&drv_data->pdev->dev,
|
||||
"dma_transfer: ssp rx stall failed\n");
|
||||
|
||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||
|
||||
/* update the buffer pointer for the amount completed in dma */
|
||||
drv_data->rx += drv_data->len -
|
||||
(DCMD(drv_data->rx_channel) & DCMD_LENGTH);
|
||||
|
||||
/* read trailing data from fifo, it does not matter how many
|
||||
* bytes are in the fifo just read until buffer is full
|
||||
* or fifo is empty, which ever occurs first */
|
||||
drv_data->read(drv_data);
|
||||
|
||||
/* return count of what was actually read */
|
||||
msg->actual_length += drv_data->len -
|
||||
(drv_data->rx_end - drv_data->rx);
|
||||
|
||||
/* Transfer delays and chip select release are
|
||||
* handled in pump_transfers or giveback
|
||||
*/
|
||||
|
||||
/* Move to next transfer */
|
||||
msg->state = pxa2xx_spi_next_transfer(drv_data);
|
||||
|
||||
/* Schedule transfer tasklet */
|
||||
tasklet_schedule(&drv_data->pump_transfers);
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_handler(int channel, void *data)
|
||||
{
|
||||
struct driver_data *drv_data = data;
|
||||
u32 irq_status = DCSR(channel) & DMA_INT_MASK;
|
||||
|
||||
if (irq_status & DCSR_BUSERR) {
|
||||
|
||||
if (channel == drv_data->tx_channel)
|
||||
pxa2xx_spi_dma_error_stop(drv_data,
|
||||
"dma_handler: bad bus address on tx channel");
|
||||
else
|
||||
pxa2xx_spi_dma_error_stop(drv_data,
|
||||
"dma_handler: bad bus address on rx channel");
|
||||
return;
|
||||
}
|
||||
|
||||
/* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
|
||||
if ((channel == drv_data->tx_channel)
|
||||
&& (irq_status & DCSR_ENDINTR)
|
||||
&& (drv_data->ssp_type == PXA25x_SSP)) {
|
||||
|
||||
/* Wait for rx to stall */
|
||||
if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
|
||||
dev_err(&drv_data->pdev->dev,
|
||||
"dma_handler: ssp rx stall failed\n");
|
||||
|
||||
/* finish this transfer, start the next */
|
||||
pxa2xx_spi_dma_transfer_complete(drv_data);
|
||||
}
|
||||
}
|
||||
|
||||
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
||||
{
|
||||
u32 irq_status;
|
||||
void __iomem *reg = drv_data->ioaddr;
|
||||
|
||||
irq_status = read_SSSR(reg) & drv_data->mask_sr;
|
||||
if (irq_status & SSSR_ROR) {
|
||||
pxa2xx_spi_dma_error_stop(drv_data,
|
||||
"dma_transfer: fifo overrun");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Check for false positive timeout */
|
||||
if ((irq_status & SSSR_TINT)
|
||||
&& (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
|
||||
write_SSSR(SSSR_TINT, reg);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
|
||||
|
||||
/* Clear and disable timeout interrupt, do the rest in
|
||||
* dma_transfer_complete */
|
||||
if (!pxa25x_ssp_comp(drv_data))
|
||||
write_SSTO(0, reg);
|
||||
|
||||
/* finish this transfer, start the next */
|
||||
pxa2xx_spi_dma_transfer_complete(drv_data);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Opps problem detected */
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
|
||||
{
|
||||
u32 dma_width;
|
||||
|
||||
switch (drv_data->n_bytes) {
|
||||
case 1:
|
||||
dma_width = DCMD_WIDTH1;
|
||||
break;
|
||||
case 2:
|
||||
dma_width = DCMD_WIDTH2;
|
||||
break;
|
||||
default:
|
||||
dma_width = DCMD_WIDTH4;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Setup rx DMA Channel */
|
||||
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
||||
DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
|
||||
DTADR(drv_data->rx_channel) = drv_data->rx_dma;
|
||||
if (drv_data->rx == drv_data->null_dma_buf)
|
||||
/* No target address increment */
|
||||
DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
|
||||
| dma_width
|
||||
| dma_burst
|
||||
| drv_data->len;
|
||||
else
|
||||
DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
|
||||
| DCMD_FLOWSRC
|
||||
| dma_width
|
||||
| dma_burst
|
||||
| drv_data->len;
|
||||
|
||||
/* Setup tx DMA Channel */
|
||||
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
||||
DSADR(drv_data->tx_channel) = drv_data->tx_dma;
|
||||
DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
|
||||
if (drv_data->tx == drv_data->null_dma_buf)
|
||||
/* No source address increment */
|
||||
DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
|
||||
| dma_width
|
||||
| dma_burst
|
||||
| drv_data->len;
|
||||
else
|
||||
DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
|
||||
| DCMD_FLOWTRG
|
||||
| dma_width
|
||||
| dma_burst
|
||||
| drv_data->len;
|
||||
|
||||
/* Enable dma end irqs on SSP to detect end of transfer */
|
||||
if (drv_data->ssp_type == PXA25x_SSP)
|
||||
DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_start(struct driver_data *drv_data)
|
||||
{
|
||||
DCSR(drv_data->rx_channel) |= DCSR_RUN;
|
||||
DCSR(drv_data->tx_channel) |= DCSR_RUN;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
|
||||
{
|
||||
struct device *dev = &drv_data->pdev->dev;
|
||||
struct ssp_device *ssp = drv_data->ssp;
|
||||
|
||||
/* Get two DMA channels (rx and tx) */
|
||||
drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
|
||||
DMA_PRIO_HIGH,
|
||||
pxa2xx_spi_dma_handler,
|
||||
drv_data);
|
||||
if (drv_data->rx_channel < 0) {
|
||||
dev_err(dev, "problem (%d) requesting rx channel\n",
|
||||
drv_data->rx_channel);
|
||||
return -ENODEV;
|
||||
}
|
||||
drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
|
||||
DMA_PRIO_MEDIUM,
|
||||
pxa2xx_spi_dma_handler,
|
||||
drv_data);
|
||||
if (drv_data->tx_channel < 0) {
|
||||
dev_err(dev, "problem (%d) requesting tx channel\n",
|
||||
drv_data->tx_channel);
|
||||
pxa_free_dma(drv_data->rx_channel);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
|
||||
DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_release(struct driver_data *drv_data)
|
||||
{
|
||||
struct ssp_device *ssp = drv_data->ssp;
|
||||
|
||||
DRCMR(ssp->drcmr_rx) = 0;
|
||||
DRCMR(ssp->drcmr_tx) = 0;
|
||||
|
||||
if (drv_data->tx_channel != 0)
|
||||
pxa_free_dma(drv_data->tx_channel);
|
||||
if (drv_data->rx_channel != 0)
|
||||
pxa_free_dma(drv_data->rx_channel);
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_resume(struct driver_data *drv_data)
|
||||
{
|
||||
if (drv_data->rx_channel != -1)
|
||||
DRCMR(drv_data->ssp->drcmr_rx) =
|
||||
DRCMR_MAPVLD | drv_data->rx_channel;
|
||||
if (drv_data->tx_channel != -1)
|
||||
DRCMR(drv_data->ssp->drcmr_tx) =
|
||||
DRCMR_MAPVLD | drv_data->tx_channel;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
|
||||
struct spi_device *spi,
|
||||
u8 bits_per_word, u32 *burst_code,
|
||||
u32 *threshold)
|
||||
{
|
||||
struct pxa2xx_spi_chip *chip_info =
|
||||
(struct pxa2xx_spi_chip *)spi->controller_data;
|
||||
int bytes_per_word;
|
||||
int burst_bytes;
|
||||
int thresh_words;
|
||||
int req_burst_size;
|
||||
int retval = 0;
|
||||
|
||||
/* Set the threshold (in registers) to equal the same amount of data
|
||||
* as represented by burst size (in bytes). The computation below
|
||||
* is (burst_size rounded up to nearest 8 byte, word or long word)
|
||||
* divided by (bytes/register); the tx threshold is the inverse of
|
||||
* the rx, so that there will always be enough data in the rx fifo
|
||||
* to satisfy a burst, and there will always be enough space in the
|
||||
* tx fifo to accept a burst (a tx burst will overwrite the fifo if
|
||||
* there is not enough space), there must always remain enough empty
|
||||
* space in the rx fifo for any data loaded to the tx fifo.
|
||||
* Whenever burst_size (in bytes) equals bits/word, the fifo threshold
|
||||
* will be 8, or half the fifo;
|
||||
* The threshold can only be set to 2, 4 or 8, but not 16, because
|
||||
* to burst 16 to the tx fifo, the fifo would have to be empty;
|
||||
* however, the minimum fifo trigger level is 1, and the tx will
|
||||
* request service when the fifo is at this level, with only 15 spaces.
|
||||
*/
|
||||
|
||||
/* find bytes/word */
|
||||
if (bits_per_word <= 8)
|
||||
bytes_per_word = 1;
|
||||
else if (bits_per_word <= 16)
|
||||
bytes_per_word = 2;
|
||||
else
|
||||
bytes_per_word = 4;
|
||||
|
||||
/* use struct pxa2xx_spi_chip->dma_burst_size if available */
|
||||
if (chip_info)
|
||||
req_burst_size = chip_info->dma_burst_size;
|
||||
else {
|
||||
switch (chip->dma_burst_size) {
|
||||
default:
|
||||
/* if the default burst size is not set,
|
||||
* do it now */
|
||||
chip->dma_burst_size = DCMD_BURST8;
|
||||
case DCMD_BURST8:
|
||||
req_burst_size = 8;
|
||||
break;
|
||||
case DCMD_BURST16:
|
||||
req_burst_size = 16;
|
||||
break;
|
||||
case DCMD_BURST32:
|
||||
req_burst_size = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (req_burst_size <= 8) {
|
||||
*burst_code = DCMD_BURST8;
|
||||
burst_bytes = 8;
|
||||
} else if (req_burst_size <= 16) {
|
||||
if (bytes_per_word == 1) {
|
||||
/* don't burst more than 1/2 the fifo */
|
||||
*burst_code = DCMD_BURST8;
|
||||
burst_bytes = 8;
|
||||
retval = 1;
|
||||
} else {
|
||||
*burst_code = DCMD_BURST16;
|
||||
burst_bytes = 16;
|
||||
}
|
||||
} else {
|
||||
if (bytes_per_word == 1) {
|
||||
/* don't burst more than 1/2 the fifo */
|
||||
*burst_code = DCMD_BURST8;
|
||||
burst_bytes = 8;
|
||||
retval = 1;
|
||||
} else if (bytes_per_word == 2) {
|
||||
/* don't burst more than 1/2 the fifo */
|
||||
*burst_code = DCMD_BURST16;
|
||||
burst_bytes = 16;
|
||||
retval = 1;
|
||||
} else {
|
||||
*burst_code = DCMD_BURST32;
|
||||
burst_bytes = 32;
|
||||
}
|
||||
}
|
||||
|
||||
thresh_words = burst_bytes / bytes_per_word;
|
||||
|
||||
/* thresh_words will be between 2 and 8 */
|
||||
*threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
|
||||
| (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);
|
||||
|
||||
return retval;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef SPI_PXA2XX_H
|
||||
#define SPI_PXA2XX_H
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pxa2xx_ssp.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
|
||||
struct driver_data {
|
||||
/* Driver model hookup */
|
||||
struct platform_device *pdev;
|
||||
|
||||
/* SSP Info */
|
||||
struct ssp_device *ssp;
|
||||
|
||||
/* SPI framework hookup */
|
||||
enum pxa_ssp_type ssp_type;
|
||||
struct spi_master *master;
|
||||
|
||||
/* PXA hookup */
|
||||
struct pxa2xx_spi_master *master_info;
|
||||
|
||||
/* PXA private DMA setup stuff */
|
||||
int rx_channel;
|
||||
int tx_channel;
|
||||
u32 *null_dma_buf;
|
||||
|
||||
/* SSP register addresses */
|
||||
void __iomem *ioaddr;
|
||||
u32 ssdr_physical;
|
||||
|
||||
/* SSP masks*/
|
||||
u32 dma_cr1;
|
||||
u32 int_cr1;
|
||||
u32 clear_sr;
|
||||
u32 mask_sr;
|
||||
|
||||
/* Maximun clock rate */
|
||||
unsigned long max_clk_rate;
|
||||
|
||||
/* Message Transfer pump */
|
||||
struct tasklet_struct pump_transfers;
|
||||
|
||||
/* DMA engine support */
|
||||
struct dma_chan *rx_chan;
|
||||
struct dma_chan *tx_chan;
|
||||
struct sg_table rx_sgt;
|
||||
struct sg_table tx_sgt;
|
||||
int rx_nents;
|
||||
int tx_nents;
|
||||
void *dummy;
|
||||
atomic_t dma_running;
|
||||
|
||||
/* Current message transfer state info */
|
||||
struct spi_message *cur_msg;
|
||||
struct spi_transfer *cur_transfer;
|
||||
struct chip_data *cur_chip;
|
||||
size_t len;
|
||||
void *tx;
|
||||
void *tx_end;
|
||||
void *rx;
|
||||
void *rx_end;
|
||||
int dma_mapped;
|
||||
dma_addr_t rx_dma;
|
||||
dma_addr_t tx_dma;
|
||||
size_t rx_map_len;
|
||||
size_t tx_map_len;
|
||||
u8 n_bytes;
|
||||
int (*write)(struct driver_data *drv_data);
|
||||
int (*read)(struct driver_data *drv_data);
|
||||
irqreturn_t (*transfer_handler)(struct driver_data *drv_data);
|
||||
void (*cs_control)(u32 command);
|
||||
|
||||
void __iomem *lpss_base;
|
||||
};
|
||||
|
||||
struct chip_data {
|
||||
u32 cr0;
|
||||
u32 cr1;
|
||||
u32 psp;
|
||||
u32 timeout;
|
||||
u8 n_bytes;
|
||||
u32 dma_burst_size;
|
||||
u32 threshold;
|
||||
u32 dma_threshold;
|
||||
u16 lpss_rx_threshold;
|
||||
u16 lpss_tx_threshold;
|
||||
u8 enable_dma;
|
||||
u8 bits_per_word;
|
||||
u32 speed_hz;
|
||||
union {
|
||||
int gpio_cs;
|
||||
unsigned int frm;
|
||||
};
|
||||
int gpio_cs_inverted;
|
||||
int (*write)(struct driver_data *drv_data);
|
||||
int (*read)(struct driver_data *drv_data);
|
||||
void (*cs_control)(u32 command);
|
||||
};
|
||||
|
||||
#define DEFINE_SSP_REG(reg, off) \
|
||||
static inline u32 read_##reg(void const __iomem *p) \
|
||||
{ return __raw_readl(p + (off)); } \
|
||||
\
|
||||
static inline void write_##reg(u32 v, void __iomem *p) \
|
||||
{ __raw_writel(v, p + (off)); }
|
||||
|
||||
DEFINE_SSP_REG(SSCR0, 0x00)
|
||||
DEFINE_SSP_REG(SSCR1, 0x04)
|
||||
DEFINE_SSP_REG(SSSR, 0x08)
|
||||
DEFINE_SSP_REG(SSITR, 0x0c)
|
||||
DEFINE_SSP_REG(SSDR, 0x10)
|
||||
DEFINE_SSP_REG(SSTO, 0x28)
|
||||
DEFINE_SSP_REG(SSPSP, 0x2c)
|
||||
DEFINE_SSP_REG(SSITF, SSITF)
|
||||
DEFINE_SSP_REG(SSIRF, SSIRF)
|
||||
|
||||
#define START_STATE ((void *)0)
|
||||
#define RUNNING_STATE ((void *)1)
|
||||
#define DONE_STATE ((void *)2)
|
||||
#define ERROR_STATE ((void *)-1)
|
||||
|
||||
#define IS_DMA_ALIGNED(x) IS_ALIGNED((unsigned long)(x), DMA_ALIGNMENT)
|
||||
#define DMA_ALIGNMENT 8
|
||||
|
||||
static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
|
||||
{
|
||||
if (drv_data->ssp_type == PXA25x_SSP)
|
||||
return 1;
|
||||
if (drv_data->ssp_type == CE4100_SSP)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
|
||||
{
|
||||
void __iomem *reg = drv_data->ioaddr;
|
||||
|
||||
if (drv_data->ssp_type == CE4100_SSP)
|
||||
val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
|
||||
|
||||
write_SSSR(val, reg);
|
||||
}
|
||||
|
||||
extern int pxa2xx_spi_flush(struct driver_data *drv_data);
|
||||
extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
|
||||
|
||||
/*
|
||||
* Select the right DMA implementation.
|
||||
*/
|
||||
#if defined(CONFIG_SPI_PXA2XX_PXADMA)
|
||||
#define SPI_PXA2XX_USE_DMA 1
|
||||
#define MAX_DMA_LEN 8191
|
||||
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TINTE)
|
||||
#elif defined(CONFIG_SPI_PXA2XX_DMA)
|
||||
#define SPI_PXA2XX_USE_DMA 1
|
||||
#define MAX_DMA_LEN SZ_64K
|
||||
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
|
||||
#else
|
||||
#undef SPI_PXA2XX_USE_DMA
|
||||
#define MAX_DMA_LEN 0
|
||||
#define DEFAULT_DMA_CR1 0
|
||||
#endif
|
||||
|
||||
#ifdef SPI_PXA2XX_USE_DMA
|
||||
extern bool pxa2xx_spi_dma_is_possible(size_t len);
|
||||
extern int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data);
|
||||
extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data);
|
||||
extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst);
|
||||
extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
|
||||
extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data);
|
||||
extern void pxa2xx_spi_dma_release(struct driver_data *drv_data);
|
||||
extern void pxa2xx_spi_dma_resume(struct driver_data *drv_data);
|
||||
extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
|
||||
struct spi_device *spi,
|
||||
u8 bits_per_word,
|
||||
u32 *burst_code,
|
||||
u32 *threshold);
|
||||
#else
|
||||
static inline bool pxa2xx_spi_dma_is_possible(size_t len) { return false; }
|
||||
static inline int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define pxa2xx_spi_dma_transfer NULL
|
||||
static inline void pxa2xx_spi_dma_prepare(struct driver_data *drv_data,
|
||||
u32 dma_burst) {}
|
||||
static inline void pxa2xx_spi_dma_start(struct driver_data *drv_data) {}
|
||||
static inline int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void pxa2xx_spi_dma_release(struct driver_data *drv_data) {}
|
||||
static inline void pxa2xx_spi_dma_resume(struct driver_data *drv_data) {}
|
||||
static inline int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
|
||||
struct spi_device *spi,
|
||||
u8 bits_per_word,
|
||||
u32 *burst_code,
|
||||
u32 *threshold)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SPI_PXA2XX_H */
|
|
@ -62,7 +62,7 @@
|
|||
#define S3C64XX_SPI_CLKSEL_SRCMSK (3<<9)
|
||||
#define S3C64XX_SPI_CLKSEL_SRCSHFT 9
|
||||
#define S3C64XX_SPI_ENCLK_ENABLE (1<<8)
|
||||
#define S3C64XX_SPI_PSR_MASK 0xff
|
||||
#define S3C64XX_SPI_PSR_MASK 0xff
|
||||
|
||||
#define S3C64XX_SPI_MODE_CH_TSZ_BYTE (0<<29)
|
||||
#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD (1<<29)
|
||||
|
@ -697,7 +697,7 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
|
|||
INIT_COMPLETION(sdd->xfer_completion);
|
||||
|
||||
/* Only BPW and Speed may change across transfers */
|
||||
bpw = xfer->bits_per_word ? : spi->bits_per_word;
|
||||
bpw = xfer->bits_per_word;
|
||||
speed = xfer->speed_hz ? : spi->max_speed_hz;
|
||||
|
||||
if (xfer->len % (bpw / 8)) {
|
||||
|
@ -743,8 +743,7 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
|
|||
sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
|
||||
if (status) {
|
||||
dev_err(&spi->dev, "I/O Error: "
|
||||
"rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
|
||||
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
|
||||
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
|
||||
(sdd->state & RXBUSY) ? 'f' : 'p',
|
||||
(sdd->state & TXBUSY) ? 'f' : 'p',
|
||||
|
@ -799,7 +798,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
|
|||
|
||||
/* Acquire DMA channels */
|
||||
while (!acquire_dma(sdd))
|
||||
msleep(10);
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
pm_runtime_get_sync(&sdd->pdev->dev);
|
||||
|
||||
|
@ -841,16 +840,14 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
|
|||
|
||||
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
|
||||
if (!cs) {
|
||||
dev_err(&spi->dev, "could not allocate memory for controller"
|
||||
" data\n");
|
||||
dev_err(&spi->dev, "could not allocate memory for controller data\n");
|
||||
of_node_put(data_np);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
|
||||
if (!gpio_is_valid(cs->line)) {
|
||||
dev_err(&spi->dev, "chip select gpio is not specified or "
|
||||
"invalid\n");
|
||||
dev_err(&spi->dev, "chip select gpio is not specified or invalid\n");
|
||||
kfree(cs);
|
||||
of_node_put(data_np);
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -957,6 +954,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
|||
if (spi->max_speed_hz >= speed) {
|
||||
spi->max_speed_hz = speed;
|
||||
} else {
|
||||
dev_err(&spi->dev, "Can't set %dHz transfer speed\n",
|
||||
spi->max_speed_hz);
|
||||
err = -EINVAL;
|
||||
goto setup_exit;
|
||||
}
|
||||
|
@ -1076,8 +1075,8 @@ static int s3c64xx_spi_get_dmares(
|
|||
if (!sdd->pdev->dev.of_node) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Unable to get SPI-%s dma "
|
||||
"resource\n", chan_str);
|
||||
dev_err(&pdev->dev, "Unable to get SPI-%s dma resource\n",
|
||||
chan_str);
|
||||
return -ENXIO;
|
||||
}
|
||||
dma_data->dmach = res->start;
|
||||
|
@ -1133,8 +1132,7 @@ static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
|
|||
gpio_free(sdd->gpios[idx]);
|
||||
}
|
||||
|
||||
static struct s3c64xx_spi_info * s3c64xx_spi_parse_dt(
|
||||
struct device *dev)
|
||||
static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
|
||||
{
|
||||
struct s3c64xx_spi_info *sci;
|
||||
u32 temp;
|
||||
|
@ -1146,16 +1144,14 @@ static struct s3c64xx_spi_info * s3c64xx_spi_parse_dt(
|
|||
}
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) {
|
||||
dev_warn(dev, "spi bus clock parent not specified, using "
|
||||
"clock at index 0 as parent\n");
|
||||
dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n");
|
||||
sci->src_clk_nr = 0;
|
||||
} else {
|
||||
sci->src_clk_nr = temp;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "num-cs", &temp)) {
|
||||
dev_warn(dev, "number of chip select lines not specified, "
|
||||
"assuming 1 chip select line\n");
|
||||
dev_warn(dev, "number of chip select lines not specified, assuming 1 chip select line\n");
|
||||
sci->num_cs = 1;
|
||||
} else {
|
||||
sci->num_cs = temp;
|
||||
|
@ -1195,7 +1191,7 @@ static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
|
|||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
||||
static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
||||
static int s3c64xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *mem_res;
|
||||
struct s3c64xx_spi_driver_data *sdd;
|
||||
|
@ -1245,8 +1241,8 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
if (pdev->dev.of_node) {
|
||||
ret = of_alias_get_id(pdev->dev.of_node, "spi");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id, "
|
||||
"errno %d\n", ret);
|
||||
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
|
||||
ret);
|
||||
goto err0;
|
||||
}
|
||||
sdd->port_id = ret;
|
||||
|
@ -1280,7 +1276,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
if (sdd->regs == NULL) {
|
||||
dev_err(&pdev->dev, "Unable to remap IO\n");
|
||||
ret = -ENXIO;
|
||||
goto err1;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (!sci->cfg_gpio && pdev->dev.of_node) {
|
||||
|
@ -1289,36 +1285,36 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
} else if (sci->cfg_gpio == NULL || sci->cfg_gpio()) {
|
||||
dev_err(&pdev->dev, "Unable to config gpio\n");
|
||||
ret = -EBUSY;
|
||||
goto err2;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* Setup clocks */
|
||||
sdd->clk = clk_get(&pdev->dev, "spi");
|
||||
sdd->clk = devm_clk_get(&pdev->dev, "spi");
|
||||
if (IS_ERR(sdd->clk)) {
|
||||
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
|
||||
ret = PTR_ERR(sdd->clk);
|
||||
goto err3;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (clk_prepare_enable(sdd->clk)) {
|
||||
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
|
||||
ret = -EBUSY;
|
||||
goto err4;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
|
||||
sdd->src_clk = clk_get(&pdev->dev, clk_name);
|
||||
sdd->src_clk = devm_clk_get(&pdev->dev, clk_name);
|
||||
if (IS_ERR(sdd->src_clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to acquire clock '%s'\n", clk_name);
|
||||
ret = PTR_ERR(sdd->src_clk);
|
||||
goto err5;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (clk_prepare_enable(sdd->src_clk)) {
|
||||
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
|
||||
ret = -EBUSY;
|
||||
goto err6;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* Setup Deufult Mode */
|
||||
|
@ -1328,11 +1324,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
init_completion(&sdd->xfer_completion);
|
||||
INIT_LIST_HEAD(&sdd->queue);
|
||||
|
||||
ret = request_irq(irq, s3c64xx_spi_irq, 0, "spi-s3c64xx", sdd);
|
||||
ret = devm_request_irq(&pdev->dev, irq, s3c64xx_spi_irq, 0,
|
||||
"spi-s3c64xx", sdd);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
goto err7;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
|
||||
|
@ -1342,11 +1339,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
if (spi_register_master(master)) {
|
||||
dev_err(&pdev->dev, "cannot register SPI master\n");
|
||||
ret = -EBUSY;
|
||||
goto err8;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
|
||||
"with %d Slaves attached\n",
|
||||
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
|
||||
sdd->port_id, master->num_chipselect);
|
||||
dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
|
||||
mem_res->end, mem_res->start,
|
||||
|
@ -1356,21 +1352,13 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err8:
|
||||
free_irq(irq, sdd);
|
||||
err7:
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
err6:
|
||||
clk_put(sdd->src_clk);
|
||||
err5:
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
err4:
|
||||
clk_put(sdd->clk);
|
||||
err3:
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
err2:
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
err1:
|
||||
if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
|
||||
s3c64xx_spi_dt_gpio_free(sdd);
|
||||
err2:
|
||||
err1:
|
||||
err0:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
spi_master_put(master);
|
||||
|
@ -1389,13 +1377,9 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
|
|||
|
||||
writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
|
||||
|
||||
free_irq(platform_get_irq(pdev, 0), sdd);
|
||||
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
clk_put(sdd->src_clk);
|
||||
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
clk_put(sdd->clk);
|
||||
|
||||
if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
|
||||
s3c64xx_spi_dt_gpio_free(sdd);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
|
@ -592,6 +593,37 @@ static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
|
||||
{
|
||||
struct sh_msiof_spi_info *info;
|
||||
struct device_node *np = dev->of_node;
|
||||
u32 num_cs = 0;
|
||||
|
||||
info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
dev_err(dev, "failed to allocate setup data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Parse the MSIOF properties */
|
||||
of_property_read_u32(np, "num-cs", &num_cs);
|
||||
of_property_read_u32(np, "renesas,tx-fifo-size",
|
||||
&info->tx_fifo_override);
|
||||
of_property_read_u32(np, "renesas,rx-fifo-size",
|
||||
&info->rx_fifo_override);
|
||||
|
||||
info->num_chipselect = num_cs;
|
||||
|
||||
return info;
|
||||
}
|
||||
#else
|
||||
static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sh_msiof_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
|
@ -610,7 +642,17 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
|
|||
p = spi_master_get_devdata(master);
|
||||
|
||||
platform_set_drvdata(pdev, p);
|
||||
p->info = pdev->dev.platform_data;
|
||||
if (pdev->dev.of_node)
|
||||
p->info = sh_msiof_spi_parse_dt(&pdev->dev);
|
||||
else
|
||||
p->info = pdev->dev.platform_data;
|
||||
|
||||
if (!p->info) {
|
||||
dev_err(&pdev->dev, "failed to obtain device info\n");
|
||||
ret = -ENXIO;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
init_completion(&p->done);
|
||||
|
||||
p->clk = clk_get(&pdev->dev, NULL);
|
||||
|
@ -715,6 +757,17 @@ static int sh_msiof_spi_runtime_nop(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id sh_msiof_match[] = {
|
||||
{ .compatible = "renesas,sh-msiof", },
|
||||
{ .compatible = "renesas,sh-mobile-msiof", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sh_msiof_match);
|
||||
#else
|
||||
#define sh_msiof_match NULL
|
||||
#endif
|
||||
|
||||
static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
|
||||
.runtime_suspend = sh_msiof_spi_runtime_nop,
|
||||
.runtime_resume = sh_msiof_spi_runtime_nop,
|
||||
|
@ -727,6 +780,7 @@ static struct platform_driver sh_msiof_spi_drv = {
|
|||
.name = "spi_sh_msiof",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &sh_msiof_spi_dev_pm_ops,
|
||||
.of_match_table = sh_msiof_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(sh_msiof_spi_drv);
|
||||
|
|
|
@ -382,8 +382,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|||
|
||||
sspi = spi_master_get_devdata(spi->master);
|
||||
|
||||
bits_per_word = t && t->bits_per_word ? t->bits_per_word :
|
||||
spi->bits_per_word;
|
||||
bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
|
||||
hz = t && t->speed_hz ? t->speed_hz : spi->max_speed_hz;
|
||||
|
||||
/* Enable IO mode for RX, TX */
|
||||
|
@ -570,7 +569,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
|||
ret = -EINVAL;
|
||||
goto free_pin;
|
||||
}
|
||||
clk_enable(sspi->clk);
|
||||
clk_prepare_enable(sspi->clk);
|
||||
sspi->ctrl_freq = clk_get_rate(sspi->clk);
|
||||
|
||||
init_completion(&sspi->done);
|
||||
|
@ -594,7 +593,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
free_clk:
|
||||
clk_disable(sspi->clk);
|
||||
clk_disable_unprepare(sspi->clk);
|
||||
clk_put(sspi->clk);
|
||||
free_pin:
|
||||
pinctrl_put(sspi->p);
|
||||
|
@ -618,7 +617,7 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
|
|||
if (sspi->chipselect[i] > 0)
|
||||
gpio_free(sspi->chipselect[i]);
|
||||
}
|
||||
clk_disable(sspi->clk);
|
||||
clk_disable_unprepare(sspi->clk);
|
||||
clk_put(sspi->clk);
|
||||
pinctrl_put(sspi->p);
|
||||
spi_master_put(master);
|
||||
|
@ -659,6 +658,7 @@ static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
|
|||
|
||||
static const struct of_device_id spi_sirfsoc_of_match[] = {
|
||||
{ .compatible = "sirf,prima2-spi", },
|
||||
{ .compatible = "sirf,marco-spi", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_spi_of_match);
|
||||
|
|
|
@ -269,9 +269,7 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
|
|||
u32 speed;
|
||||
unsigned long command;
|
||||
|
||||
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
|
||||
if (!speed)
|
||||
speed = tsd->spi_max_frequency;
|
||||
speed = t->speed_hz;
|
||||
if (speed != tsd->cur_speed) {
|
||||
clk_set_rate(tsd->clk, speed);
|
||||
tsd->cur_speed = speed;
|
||||
|
@ -319,6 +317,15 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
|
|||
return tegra_sflash_start_cpu_based_transfer(tsd, t);
|
||||
}
|
||||
|
||||
static int tegra_sflash_setup(struct spi_device *spi)
|
||||
{
|
||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
|
||||
|
||||
/* Set speed to the spi max fequency if spi device has not set */
|
||||
spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_sflash_transfer_one_message(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
|
@ -492,6 +499,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
|
|||
|
||||
/* the spi->mode bits understood by this driver: */
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||
master->setup = tegra_sflash_setup;
|
||||
master->transfer_one_message = tegra_sflash_transfer_one_message;
|
||||
master->num_chipselect = MAX_CHIP_SELECT;
|
||||
master->bus_num = -1;
|
||||
|
|
|
@ -284,8 +284,7 @@ static unsigned tegra_slink_calculate_curr_xfer_param(
|
|||
unsigned max_len;
|
||||
unsigned total_fifo_words;
|
||||
|
||||
bits_per_word = t->bits_per_word ? t->bits_per_word :
|
||||
spi->bits_per_word;
|
||||
bits_per_word = t->bits_per_word;
|
||||
tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1;
|
||||
|
||||
if (bits_per_word == 8 || bits_per_word == 16) {
|
||||
|
@ -378,8 +377,7 @@ static unsigned int tegra_slink_read_rx_fifo_to_client_rxbuf(
|
|||
} else {
|
||||
unsigned int bits_per_word;
|
||||
|
||||
bits_per_word = t->bits_per_word ? t->bits_per_word :
|
||||
tspi->cur_spi->bits_per_word;
|
||||
bits_per_word = t->bits_per_word;
|
||||
for (count = 0; count < rx_full_count; count++) {
|
||||
x = tegra_slink_readl(tspi, SLINK_RX_FIFO);
|
||||
for (i = 0; (i < tspi->bytes_per_word); i++)
|
||||
|
@ -444,8 +442,7 @@ static void tegra_slink_copy_spi_rxbuf_to_client_rxbuf(
|
|||
unsigned int x;
|
||||
unsigned int rx_mask, bits_per_word;
|
||||
|
||||
bits_per_word = t->bits_per_word ? t->bits_per_word :
|
||||
tspi->cur_spi->bits_per_word;
|
||||
bits_per_word = t->bits_per_word;
|
||||
rx_mask = (1 << bits_per_word) - 1;
|
||||
for (count = 0; count < tspi->curr_dma_words; count++) {
|
||||
x = tspi->rx_dma_buf[count];
|
||||
|
@ -728,9 +725,7 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi,
|
|||
unsigned long command2;
|
||||
|
||||
bits_per_word = t->bits_per_word;
|
||||
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
|
||||
if (!speed)
|
||||
speed = tspi->spi_max_frequency;
|
||||
speed = t->speed_hz;
|
||||
if (speed != tspi->cur_speed) {
|
||||
clk_set_rate(tspi->clk, speed * 4);
|
||||
tspi->cur_speed = speed;
|
||||
|
@ -841,6 +836,8 @@ static int tegra_slink_setup(struct spi_device *spi)
|
|||
|
||||
BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
|
||||
|
||||
/* Set speed to the spi max fequency if spi device has not set */
|
||||
spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
|
||||
ret = pm_runtime_get_sync(tspi->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
|
||||
|
|
|
@ -189,9 +189,8 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
|
|||
unsigned int len = t->len;
|
||||
unsigned int wsize;
|
||||
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
|
||||
u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
|
||||
u8 bits_per_word = t->bits_per_word;
|
||||
|
||||
bits_per_word = bits_per_word ? : 8;
|
||||
wsize = bits_per_word >> 3; /* in bytes */
|
||||
|
||||
if (prev_speed_hz != speed_hz
|
||||
|
@ -316,9 +315,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
|
|||
/* check each transfer's parameters */
|
||||
list_for_each_entry (t, &m->transfers, transfer_list) {
|
||||
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
|
||||
u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
|
||||
u8 bits_per_word = t->bits_per_word;
|
||||
|
||||
bits_per_word = bits_per_word ? : 8;
|
||||
if (!t->tx_buf && !t->rx_buf && t->len)
|
||||
return -EINVAL;
|
||||
if (bits_per_word != 8 && bits_per_word != 16)
|
||||
|
@ -337,7 +335,7 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init txx9spi_probe(struct platform_device *dev)
|
||||
static int txx9spi_probe(struct platform_device *dev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct txx9spi *c;
|
||||
|
@ -432,7 +430,7 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __exit txx9spi_remove(struct platform_device *dev)
|
||||
static int txx9spi_remove(struct platform_device *dev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(platform_get_drvdata(dev));
|
||||
struct txx9spi *c = spi_master_get_devdata(master);
|
||||
|
@ -450,7 +448,7 @@ static int __exit txx9spi_remove(struct platform_device *dev)
|
|||
MODULE_ALIAS("platform:spi_txx9");
|
||||
|
||||
static struct platform_driver txx9spi_driver = {
|
||||
.remove = __exit_p(txx9spi_remove),
|
||||
.remove = txx9spi_remove,
|
||||
.driver = {
|
||||
.name = "spi_txx9",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -1080,7 +1080,8 @@ static int of_spi_register_master(struct spi_master *master)
|
|||
if (!master->cs_gpios)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(cs, -EINVAL, master->num_chipselect);
|
||||
for (i = 0; i < master->num_chipselect; i++)
|
||||
cs[i] = -EINVAL;
|
||||
|
||||
for (i = 0; i < nb; i++)
|
||||
cs[i] = of_get_named_gpio(np, "cs-gpios", i);
|
||||
|
@ -1135,6 +1136,9 @@ int spi_register_master(struct spi_master *master)
|
|||
if (master->num_chipselect == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((master->bus_num < 0) && master->dev.of_node)
|
||||
master->bus_num = of_alias_get_id(master->dev.of_node, "spi");
|
||||
|
||||
/* convention: dynamically assigned bus IDs count down from the max */
|
||||
if (master->bus_num < 0) {
|
||||
/* FIXME switch to an IDR based scheme, something like
|
||||
|
@ -1366,12 +1370,14 @@ 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.
|
||||
* Set transfer bits_per_word and max speed 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;
|
||||
if (!xfer->speed_hz)
|
||||
xfer->speed_hz = spi->max_speed_hz;
|
||||
}
|
||||
|
||||
message->spi = spi;
|
||||
|
@ -1656,7 +1662,8 @@ int spi_write_then_read(struct spi_device *spi,
|
|||
* using the pre-allocated buffer or the transfer is too large.
|
||||
*/
|
||||
if ((n_tx + n_rx) > SPI_BUFSIZ || !mutex_trylock(&lock)) {
|
||||
local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx), GFP_KERNEL);
|
||||
local_buf = kmalloc(max((unsigned)SPI_BUFSIZ, n_tx + n_rx),
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!local_buf)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
|
|
|
@ -22,6 +22,9 @@ struct omap2_mcspi_dev_attr {
|
|||
|
||||
struct omap2_mcspi_device_config {
|
||||
unsigned turbo_mode:1;
|
||||
|
||||
/* toggle chip select after every word */
|
||||
unsigned cs_per_word:1;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -155,6 +155,14 @@
|
|||
#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */
|
||||
#define SSACD_SCDX8 (1 << 7) /* SYSCLK division ratio select */
|
||||
|
||||
/* LPSS SSP */
|
||||
#define SSITF 0x44 /* TX FIFO trigger level */
|
||||
#define SSITF_TxLoThresh(x) (((x) - 1) << 8)
|
||||
#define SSITF_TxHiThresh(x) ((x) - 1)
|
||||
|
||||
#define SSIRF 0x48 /* RX FIFO trigger level */
|
||||
#define SSIRF_RxThresh(x) ((x) - 1)
|
||||
|
||||
enum pxa_ssp_type {
|
||||
SSP_UNDEFINED = 0,
|
||||
PXA25x_SSP, /* pxa 210, 250, 255, 26x */
|
||||
|
@ -164,6 +172,7 @@ enum pxa_ssp_type {
|
|||
PXA168_SSP,
|
||||
PXA910_SSP,
|
||||
CE4100_SSP,
|
||||
LPSS_SSP,
|
||||
};
|
||||
|
||||
struct ssp_device {
|
||||
|
@ -206,6 +215,15 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
|
|||
return __raw_readl(dev->mmio_base + reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_PXA
|
||||
struct ssp_device *pxa_ssp_request(int port, const char *label);
|
||||
void pxa_ssp_free(struct ssp_device *);
|
||||
#else
|
||||
static inline struct ssp_device *pxa_ssp_request(int port, const char *label)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void pxa_ssp_free(struct ssp_device *ssp) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,6 +28,15 @@ struct pxa2xx_spi_master {
|
|||
u32 clock_enable;
|
||||
u16 num_chipselect;
|
||||
u8 enable_dma;
|
||||
|
||||
/* DMA engine specific config */
|
||||
int rx_chan_id;
|
||||
int tx_chan_id;
|
||||
int rx_slave_id;
|
||||
int tx_slave_id;
|
||||
|
||||
/* For non-PXA arches */
|
||||
struct ssp_device ssp;
|
||||
};
|
||||
|
||||
/* spi_board_info.controller_data for SPI slave devices,
|
||||
|
@ -35,6 +44,7 @@ struct pxa2xx_spi_master {
|
|||
*/
|
||||
struct pxa2xx_spi_chip {
|
||||
u8 tx_threshold;
|
||||
u8 tx_hi_threshold;
|
||||
u8 rx_threshold;
|
||||
u8 dma_burst_size;
|
||||
u32 timeout;
|
||||
|
@ -50,103 +60,5 @@ struct pxa2xx_spi_chip {
|
|||
|
||||
extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
|
||||
|
||||
#else
|
||||
/*
|
||||
* This is the implemtation for CE4100 on x86. ARM defines them in mach/ or
|
||||
* plat/ include path.
|
||||
* The CE4100 does not provide DMA support. This bits are here to let the driver
|
||||
* compile and will never be used. Maybe we get DMA support at a later point in
|
||||
* time.
|
||||
*/
|
||||
|
||||
#define DCSR(n) (n)
|
||||
#define DSADR(n) (n)
|
||||
#define DTADR(n) (n)
|
||||
#define DCMD(n) (n)
|
||||
#define DRCMR(n) (n)
|
||||
|
||||
#define DCSR_RUN (1 << 31) /* Run Bit */
|
||||
#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch */
|
||||
#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable */
|
||||
#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */
|
||||
#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */
|
||||
#define DCSR_ENDINTR (1 << 2) /* End Interrupt */
|
||||
#define DCSR_STARTINTR (1 << 1) /* Start Interrupt */
|
||||
#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt */
|
||||
|
||||
#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable */
|
||||
#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */
|
||||
#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */
|
||||
#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */
|
||||
#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */
|
||||
#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */
|
||||
#define DCSR_EORINTR (1 << 9) /* The end of Receive */
|
||||
|
||||
#define DRCMR_MAPVLD (1 << 7) /* Map Valid */
|
||||
#define DRCMR_CHLNUM 0x1f /* mask for Channel Number */
|
||||
|
||||
#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor */
|
||||
#define DDADR_STOP (1 << 0) /* Stop */
|
||||
|
||||
#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */
|
||||
#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */
|
||||
#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */
|
||||
#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */
|
||||
#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */
|
||||
#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */
|
||||
#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */
|
||||
#define DCMD_BURST8 (1 << 16) /* 8 byte burst */
|
||||
#define DCMD_BURST16 (2 << 16) /* 16 byte burst */
|
||||
#define DCMD_BURST32 (3 << 16) /* 32 byte burst */
|
||||
#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */
|
||||
#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */
|
||||
#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */
|
||||
#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
|
||||
|
||||
/*
|
||||
* Descriptor structure for PXA's DMA engine
|
||||
* Note: this structure must always be aligned to a 16-byte boundary.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
DMA_PRIO_HIGH = 0,
|
||||
DMA_PRIO_MEDIUM = 1,
|
||||
DMA_PRIO_LOW = 2
|
||||
} pxa_dma_prio;
|
||||
|
||||
/*
|
||||
* DMA registration
|
||||
*/
|
||||
|
||||
static inline int pxa_request_dma(char *name,
|
||||
pxa_dma_prio prio,
|
||||
void (*irq_handler)(int, void *),
|
||||
void *data)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void pxa_free_dma(int dma_ch)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* The CE4100 does not have the clk framework implemented and SPI clock can
|
||||
* not be switched on/off or the divider changed.
|
||||
*/
|
||||
static inline void clk_disable(struct clk *clk)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int clk_enable(struct clk *clk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long clk_get_rate(struct clk *clk)
|
||||
{
|
||||
return 3686400;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -57,6 +57,8 @@ extern struct bus_type spi_bus_type;
|
|||
* @modalias: Name of the driver to use with this device, or an alias
|
||||
* for that name. This appears in the sysfs "modalias" attribute
|
||||
* for driver coldplugging, and in uevents used for hotplugging
|
||||
* @cs_gpio: gpio number of the chipselect line (optional, -EINVAL when
|
||||
* when not using a GPIO line)
|
||||
*
|
||||
* A @spi_device is used to interchange data between an SPI slave
|
||||
* (usually a discrete chip) and CPU memory.
|
||||
|
@ -258,6 +260,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
|||
* @unprepare_transfer_hardware: there are currently no more messages on the
|
||||
* queue so the subsystem notifies the driver that it may relax the
|
||||
* hardware by issuing this call
|
||||
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
|
||||
* number. Any individual value may be -EINVAL for CS lines that
|
||||
* are not GPIOs (driven by the SPI controller itself).
|
||||
*
|
||||
* Each SPI master controller can communicate with one or more @spi_device
|
||||
* children. These make a small bus, sharing MOSI, MISO and SCK signals
|
||||
|
|
|
@ -62,8 +62,8 @@
|
|||
*/
|
||||
struct spi_gpio_platform_data {
|
||||
unsigned sck;
|
||||
unsigned mosi;
|
||||
unsigned miso;
|
||||
unsigned long mosi;
|
||||
unsigned long miso;
|
||||
|
||||
u16 num_chipselect;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче