You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next-spi' of git://git.secretlab.ca/git/linux-2.6
* 'next-spi' of git://git.secretlab.ca/git/linux-2.6: spi: spi_txx9.c: use resource_size() spi: spi_sh_sci.c: use resource_size() spi: spi_mpc8xxx.c: use resource_size() spi: spi_bfin5xx.c: use resource_size() spi: atmel_spi.c: use resource_size() spi: Add s3c64xx SPI Controller driver atmel_spi: fix dma addr calculation for len > BUFFER_SIZE spi_s3c24xx: add FIQ pseudo-DMA support spi: controller driver for Designware SPI core spidev: add proper section markers spidev: use DECLARE_BITMAP instead of declaring the array
This commit is contained in:
@@ -216,6 +216,17 @@ config SPI_S3C24XX
|
||||
help
|
||||
SPI driver for Samsung S3C24XX series ARM SoCs
|
||||
|
||||
config SPI_S3C24XX_FIQ
|
||||
bool "S3C24XX driver with FIQ pseudo-DMA"
|
||||
depends on SPI_S3C24XX
|
||||
select FIQ
|
||||
help
|
||||
Enable FIQ support for the S3C24XX SPI driver to provide pseudo
|
||||
DMA by using the fast-interrupt request framework, This allows
|
||||
the driver to get DMA-like performance when there are either
|
||||
no free DMA channels, or when doing transfers that required both
|
||||
TX and RX data paths.
|
||||
|
||||
config SPI_S3C24XX_GPIO
|
||||
tristate "Samsung S3C24XX series SPI by GPIO"
|
||||
depends on ARCH_S3C2410 && EXPERIMENTAL
|
||||
@@ -226,6 +237,13 @@ config SPI_S3C24XX_GPIO
|
||||
the inbuilt hardware cannot provide the transfer mode, or
|
||||
where the board is using non hardware connected pins.
|
||||
|
||||
config SPI_S3C64XX
|
||||
tristate "Samsung S3C64XX series type SPI"
|
||||
depends on ARCH_S3C64XX && EXPERIMENTAL
|
||||
select S3C64XX_DMA
|
||||
help
|
||||
SPI driver for Samsung S3C64XX and newer SoCs.
|
||||
|
||||
config SPI_SH_MSIOF
|
||||
tristate "SuperH MSIOF SPI controller"
|
||||
depends on SUPERH && HAVE_CLK
|
||||
@@ -289,6 +307,16 @@ config SPI_NUC900
|
||||
# Add new SPI master controllers in alphabetical order above this line
|
||||
#
|
||||
|
||||
config SPI_DESIGNWARE
|
||||
bool "DesignWare SPI controller core support"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
general driver for SPI controller core from DesignWare
|
||||
|
||||
config SPI_DW_PCI
|
||||
tristate "PCI interface driver for DW SPI core"
|
||||
depends on SPI_DESIGNWARE && PCI
|
||||
|
||||
#
|
||||
# There are lots of SPI device types, with sensors and memory
|
||||
# being probably the most widely used ones.
|
||||
|
||||
@@ -16,6 +16,8 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
|
||||
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
|
||||
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
|
||||
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
|
||||
obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o
|
||||
obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
|
||||
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
|
||||
obj-$(CONFIG_SPI_IMX) += spi_imx.o
|
||||
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
|
||||
@@ -30,7 +32,8 @@ obj-$(CONFIG_SPI_MPC52xx) += mpc52xx_spi.o
|
||||
obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o
|
||||
obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
|
||||
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
|
||||
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
|
||||
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o
|
||||
obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o
|
||||
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
|
||||
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
|
||||
obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
|
||||
@@ -39,6 +42,11 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
|
||||
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
|
||||
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
|
||||
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
|
||||
|
||||
# special build for s3c24xx spi driver with fiq support
|
||||
spi_s3c24xx_hw-y := spi_s3c24xx.o
|
||||
spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi_s3c24xx_fiq.o
|
||||
|
||||
# ... add above this line ...
|
||||
|
||||
# SPI protocol drivers (device/link on bus)
|
||||
|
||||
@@ -189,14 +189,14 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
|
||||
|
||||
/* use scratch buffer only when rx or tx data is unspecified */
|
||||
if (xfer->rx_buf)
|
||||
*rx_dma = xfer->rx_dma + xfer->len - len;
|
||||
*rx_dma = xfer->rx_dma + xfer->len - *plen;
|
||||
else {
|
||||
*rx_dma = as->buffer_dma;
|
||||
if (len > BUFFER_SIZE)
|
||||
len = BUFFER_SIZE;
|
||||
}
|
||||
if (xfer->tx_buf)
|
||||
*tx_dma = xfer->tx_dma + xfer->len - len;
|
||||
*tx_dma = xfer->tx_dma + xfer->len - *plen;
|
||||
else {
|
||||
*tx_dma = as->buffer_dma;
|
||||
if (len > BUFFER_SIZE)
|
||||
@@ -788,7 +788,7 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&as->lock);
|
||||
INIT_LIST_HEAD(&as->queue);
|
||||
as->pdev = pdev;
|
||||
as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
|
||||
as->regs = ioremap(regs->start, resource_size(regs));
|
||||
if (!as->regs)
|
||||
goto out_free_buffer;
|
||||
as->irq = irq;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* mrst_spi_pci.c - PCI interface driver for DW SPI Core
|
||||
*
|
||||
* Copyright (c) 2009, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spi/dw_spi.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define DRIVER_NAME "dw_spi_pci"
|
||||
|
||||
struct dw_spi_pci {
|
||||
struct pci_dev *pdev;
|
||||
struct dw_spi dws;
|
||||
};
|
||||
|
||||
static int __devinit spi_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct dw_spi_pci *dwpci;
|
||||
struct dw_spi *dws;
|
||||
int pci_bar = 0;
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "DW: found PCI SPI controller(ID: %04x:%04x)\n",
|
||||
pdev->vendor, pdev->device);
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dwpci = kzalloc(sizeof(struct dw_spi_pci), GFP_KERNEL);
|
||||
if (!dwpci) {
|
||||
ret = -ENOMEM;
|
||||
goto err_disable;
|
||||
}
|
||||
|
||||
dwpci->pdev = pdev;
|
||||
dws = &dwpci->dws;
|
||||
|
||||
/* Get basic io resource and map it */
|
||||
dws->paddr = pci_resource_start(pdev, pci_bar);
|
||||
dws->iolen = pci_resource_len(pdev, pci_bar);
|
||||
|
||||
ret = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
|
||||
if (ret)
|
||||
goto err_kfree;
|
||||
|
||||
dws->regs = ioremap_nocache((unsigned long)dws->paddr,
|
||||
pci_resource_len(pdev, pci_bar));
|
||||
if (!dws->regs) {
|
||||
ret = -ENOMEM;
|
||||
goto err_release_reg;
|
||||
}
|
||||
|
||||
dws->parent_dev = &pdev->dev;
|
||||
dws->bus_num = 0;
|
||||
dws->num_cs = 4;
|
||||
dws->max_freq = 25000000; /* for Moorestwon */
|
||||
dws->irq = pdev->irq;
|
||||
|
||||
ret = dw_spi_add_host(dws);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
/* PCI hook and SPI hook use the same drv data */
|
||||
pci_set_drvdata(pdev, dwpci);
|
||||
return 0;
|
||||
|
||||
err_unmap:
|
||||
iounmap(dws->regs);
|
||||
err_release_reg:
|
||||
pci_release_region(pdev, pci_bar);
|
||||
err_kfree:
|
||||
kfree(dwpci);
|
||||
err_disable:
|
||||
pci_disable_device(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit spi_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
iounmap(dwpci->dws.regs);
|
||||
pci_release_region(pdev, 0);
|
||||
kfree(dwpci);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int spi_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = dw_spi_suspend_host(&dwpci->dws);
|
||||
if (ret)
|
||||
return ret;
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
return dw_spi_resume_host(&dwpci->dws);
|
||||
}
|
||||
#else
|
||||
#define spi_suspend NULL
|
||||
#define spi_resume NULL
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id pci_ids[] __devinitdata = {
|
||||
/* Intel Moorestown platform SPI controller 0 */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct pci_driver dw_spi_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pci_ids,
|
||||
.probe = spi_pci_probe,
|
||||
.remove = __devexit_p(spi_pci_remove),
|
||||
.suspend = spi_suspend,
|
||||
.resume = spi_resume,
|
||||
};
|
||||
|
||||
static int __init mrst_spi_init(void)
|
||||
{
|
||||
return pci_register_driver(&dw_spi_driver);
|
||||
}
|
||||
|
||||
static void __exit mrst_spi_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&dw_spi_driver);
|
||||
}
|
||||
|
||||
module_init(mrst_spi_init);
|
||||
module_exit(mrst_spi_exit);
|
||||
|
||||
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
|
||||
MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1294,7 +1294,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
|
||||
goto out_error_get_res;
|
||||
}
|
||||
|
||||
drv_data->regs_base = ioremap(res->start, (res->end - res->start + 1));
|
||||
drv_data->regs_base = ioremap(res->start, resource_size(res));
|
||||
if (drv_data->regs_base == NULL) {
|
||||
dev_err(dev, "Cannot map IO\n");
|
||||
status = -ENXIO;
|
||||
|
||||
@@ -1013,7 +1013,7 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
|
||||
|
||||
init_completion(&mpc8xxx_spi->done);
|
||||
|
||||
mpc8xxx_spi->base = ioremap(mem->start, mem->end - mem->start + 1);
|
||||
mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
|
||||
if (mpc8xxx_spi->base == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_ioremap;
|
||||
|
||||
+231
-13
@@ -1,7 +1,7 @@
|
||||
/* linux/drivers/spi/spi_s3c24xx.c
|
||||
*
|
||||
* Copyright (c) 2006 Ben Dooks
|
||||
* Copyright (c) 2006 Simtec Electronics
|
||||
* Copyright 2006-2009 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -28,6 +28,11 @@
|
||||
#include <plat/regs-spi.h>
|
||||
#include <mach/spi.h>
|
||||
|
||||
#include <plat/fiq.h>
|
||||
#include <asm/fiq.h>
|
||||
|
||||
#include "spi_s3c24xx_fiq.h"
|
||||
|
||||
/**
|
||||
* s3c24xx_spi_devstate - per device data
|
||||
* @hz: Last frequency calculated for @sppre field.
|
||||
@@ -42,6 +47,13 @@ struct s3c24xx_spi_devstate {
|
||||
u8 sppre;
|
||||
};
|
||||
|
||||
enum spi_fiq_mode {
|
||||
FIQ_MODE_NONE = 0,
|
||||
FIQ_MODE_TX = 1,
|
||||
FIQ_MODE_RX = 2,
|
||||
FIQ_MODE_TXRX = 3,
|
||||
};
|
||||
|
||||
struct s3c24xx_spi {
|
||||
/* bitbang has to be first */
|
||||
struct spi_bitbang bitbang;
|
||||
@@ -52,6 +64,11 @@ struct s3c24xx_spi {
|
||||
int len;
|
||||
int count;
|
||||
|
||||
struct fiq_handler fiq_handler;
|
||||
enum spi_fiq_mode fiq_mode;
|
||||
unsigned char fiq_inuse;
|
||||
unsigned char fiq_claimed;
|
||||
|
||||
void (*set_cs)(struct s3c2410_spi_info *spi,
|
||||
int cs, int pol);
|
||||
|
||||
@@ -67,6 +84,7 @@ struct s3c24xx_spi {
|
||||
struct s3c2410_spi_info *pdata;
|
||||
};
|
||||
|
||||
|
||||
#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
|
||||
#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
|
||||
|
||||
@@ -127,7 +145,7 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
|
||||
}
|
||||
|
||||
if (spi->mode != cs->mode) {
|
||||
u8 spcon = SPCON_DEFAULT;
|
||||
u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
|
||||
|
||||
if (spi->mode & SPI_CPHA)
|
||||
spcon |= S3C2410_SPCON_CPHA_FMTB;
|
||||
@@ -214,13 +232,196 @@ static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
|
||||
return hw->tx ? hw->tx[count] : 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_S3C24XX_FIQ
|
||||
/* Support for FIQ based pseudo-DMA to improve the transfer speed.
|
||||
*
|
||||
* This code uses the assembly helper in spi_s3c24xx_spi.S which is
|
||||
* used by the FIQ core to move data between main memory and the peripheral
|
||||
* block. Since this is code running on the processor, there is no problem
|
||||
* with cache coherency of the buffers, so we can use any buffer we like.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct spi_fiq_code - FIQ code and header
|
||||
* @length: The length of the code fragment, excluding this header.
|
||||
* @ack_offset: The offset from @data to the word to place the IRQ ACK bit at.
|
||||
* @data: The code itself to install as a FIQ handler.
|
||||
*/
|
||||
struct spi_fiq_code {
|
||||
u32 length;
|
||||
u32 ack_offset;
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
extern struct spi_fiq_code s3c24xx_spi_fiq_txrx;
|
||||
extern struct spi_fiq_code s3c24xx_spi_fiq_tx;
|
||||
extern struct spi_fiq_code s3c24xx_spi_fiq_rx;
|
||||
|
||||
/**
|
||||
* ack_bit - turn IRQ into IRQ acknowledgement bit
|
||||
* @irq: The interrupt number
|
||||
*
|
||||
* Returns the bit to write to the interrupt acknowledge register.
|
||||
*/
|
||||
static inline u32 ack_bit(unsigned int irq)
|
||||
{
|
||||
return 1 << (irq - IRQ_EINT0);
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer
|
||||
* @hw: The hardware state.
|
||||
*
|
||||
* Claim the FIQ handler (only one can be active at any one time) and
|
||||
* then setup the correct transfer code for this transfer.
|
||||
*
|
||||
* This call updates all the necessary state information if sucessful,
|
||||
* so the caller does not need to do anything more than start the transfer
|
||||
* as normal, since the IRQ will have been re-routed to the FIQ handler.
|
||||
*/
|
||||
void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
|
||||
{
|
||||
struct pt_regs regs;
|
||||
enum spi_fiq_mode mode;
|
||||
struct spi_fiq_code *code;
|
||||
int ret;
|
||||
|
||||
if (!hw->fiq_claimed) {
|
||||
/* try and claim fiq if we haven't got it, and if not
|
||||
* then return and simply use another transfer method */
|
||||
|
||||
ret = claim_fiq(&hw->fiq_handler);
|
||||
if (ret)
|
||||
return;
|
||||
}
|
||||
|
||||
if (hw->tx && !hw->rx)
|
||||
mode = FIQ_MODE_TX;
|
||||
else if (hw->rx && !hw->tx)
|
||||
mode = FIQ_MODE_RX;
|
||||
else
|
||||
mode = FIQ_MODE_TXRX;
|
||||
|
||||
regs.uregs[fiq_rspi] = (long)hw->regs;
|
||||
regs.uregs[fiq_rrx] = (long)hw->rx;
|
||||
regs.uregs[fiq_rtx] = (long)hw->tx + 1;
|
||||
regs.uregs[fiq_rcount] = hw->len - 1;
|
||||
regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ;
|
||||
|
||||
set_fiq_regs(®s);
|
||||
|
||||
if (hw->fiq_mode != mode) {
|
||||
u32 *ack_ptr;
|
||||
|
||||
hw->fiq_mode = mode;
|
||||
|
||||
switch (mode) {
|
||||
case FIQ_MODE_TX:
|
||||
code = &s3c24xx_spi_fiq_tx;
|
||||
break;
|
||||
case FIQ_MODE_RX:
|
||||
code = &s3c24xx_spi_fiq_rx;
|
||||
break;
|
||||
case FIQ_MODE_TXRX:
|
||||
code = &s3c24xx_spi_fiq_txrx;
|
||||
break;
|
||||
default:
|
||||
code = NULL;
|
||||
}
|
||||
|
||||
BUG_ON(!code);
|
||||
|
||||
ack_ptr = (u32 *)&code->data[code->ack_offset];
|
||||
*ack_ptr = ack_bit(hw->irq);
|
||||
|
||||
set_fiq_handler(&code->data, code->length);
|
||||
}
|
||||
|
||||
s3c24xx_set_fiq(hw->irq, true);
|
||||
|
||||
hw->fiq_mode = mode;
|
||||
hw->fiq_inuse = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c24xx_spi_fiqop - FIQ core code callback
|
||||
* @pw: Data registered with the handler
|
||||
* @release: Whether this is a release or a return.
|
||||
*
|
||||
* Called by the FIQ code when another module wants to use the FIQ, so
|
||||
* return whether we are currently using this or not and then update our
|
||||
* internal state.
|
||||
*/
|
||||
static int s3c24xx_spi_fiqop(void *pw, int release)
|
||||
{
|
||||
struct s3c24xx_spi *hw = pw;
|
||||
int ret = 0;
|
||||
|
||||
if (release) {
|
||||
if (hw->fiq_inuse)
|
||||
ret = -EBUSY;
|
||||
|
||||
/* note, we do not need to unroute the FIQ, as the FIQ
|
||||
* vector code de-routes it to signal the end of transfer */
|
||||
|
||||
hw->fiq_mode = FIQ_MODE_NONE;
|
||||
hw->fiq_claimed = 0;
|
||||
} else {
|
||||
hw->fiq_claimed = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c24xx_spi_initfiq - setup the information for the FIQ core
|
||||
* @hw: The hardware state.
|
||||
*
|
||||
* Setup the fiq_handler block to pass to the FIQ core.
|
||||
*/
|
||||
static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw)
|
||||
{
|
||||
hw->fiq_handler.dev_id = hw;
|
||||
hw->fiq_handler.name = dev_name(hw->dev);
|
||||
hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop;
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c24xx_spi_usefiq - return if we should be using FIQ.
|
||||
* @hw: The hardware state.
|
||||
*
|
||||
* Return true if the platform data specifies whether this channel is
|
||||
* allowed to use the FIQ.
|
||||
*/
|
||||
static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw)
|
||||
{
|
||||
return hw->pdata->use_fiq;
|
||||
}
|
||||
|
||||
/**
|
||||
* s3c24xx_spi_usingfiq - return if channel is using FIQ
|
||||
* @spi: The hardware state.
|
||||
*
|
||||
* Return whether the channel is currently using the FIQ (separate from
|
||||
* whether the FIQ is claimed).
|
||||
*/
|
||||
static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi)
|
||||
{
|
||||
return spi->fiq_inuse;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { }
|
||||
static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { }
|
||||
static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; }
|
||||
static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; }
|
||||
|
||||
#endif /* CONFIG_SPI_S3C24XX_FIQ */
|
||||
|
||||
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
|
||||
{
|
||||
struct s3c24xx_spi *hw = to_hw(spi);
|
||||
|
||||
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
|
||||
t->tx_buf, t->rx_buf, t->len);
|
||||
|
||||
hw->tx = t->tx_buf;
|
||||
hw->rx = t->rx_buf;
|
||||
hw->len = t->len;
|
||||
@@ -228,11 +429,14 @@ static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
|
||||
|
||||
init_completion(&hw->done);
|
||||
|
||||
hw->fiq_inuse = 0;
|
||||
if (s3c24xx_spi_usefiq(hw) && t->len >= 3)
|
||||
s3c24xx_spi_tryfiq(hw);
|
||||
|
||||
/* send the first byte */
|
||||
writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
|
||||
|
||||
wait_for_completion(&hw->done);
|
||||
|
||||
return hw->count;
|
||||
}
|
||||
|
||||
@@ -254,17 +458,27 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
|
||||
goto irq_done;
|
||||
}
|
||||
|
||||
hw->count++;
|
||||
if (!s3c24xx_spi_usingfiq(hw)) {
|
||||
hw->count++;
|
||||
|
||||
if (hw->rx)
|
||||
hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
|
||||
if (hw->rx)
|
||||
hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
|
||||
|
||||
count++;
|
||||
count++;
|
||||
|
||||
if (count < hw->len)
|
||||
writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
|
||||
else
|
||||
complete(&hw->done);
|
||||
} else {
|
||||
hw->count = hw->len;
|
||||
hw->fiq_inuse = 0;
|
||||
|
||||
if (hw->rx)
|
||||
hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT);
|
||||
|
||||
if (count < hw->len)
|
||||
writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
|
||||
else
|
||||
complete(&hw->done);
|
||||
}
|
||||
|
||||
irq_done:
|
||||
return IRQ_HANDLED;
|
||||
@@ -322,6 +536,10 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, hw);
|
||||
init_completion(&hw->done);
|
||||
|
||||
/* initialise fiq handler */
|
||||
|
||||
s3c24xx_spi_initfiq(hw);
|
||||
|
||||
/* setup the master state. */
|
||||
|
||||
/* the spi->mode bits understood by this driver: */
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/* linux/drivers/spi/spi_s3c24xx_fiq.S
|
||||
*
|
||||
* Copyright 2009 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C24XX SPI - FIQ pseudo-DMA transfer code
|
||||
*
|
||||
* 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/linkage.h>
|
||||
#include <asm/assembler.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/regs-irq.h>
|
||||
#include <plat/regs-spi.h>
|
||||
|
||||
#include "spi_s3c24xx_fiq.h"
|
||||
|
||||
.text
|
||||
|
||||
@ entry to these routines is as follows, with the register names
|
||||
@ defined in fiq.h so that they can be shared with the C files which
|
||||
@ setup the calling registers.
|
||||
@
|
||||
@ fiq_rirq The base of the IRQ registers to find S3C2410_SRCPND
|
||||
@ fiq_rtmp Temporary register to hold tx/rx data
|
||||
@ fiq_rspi The base of the SPI register block
|
||||
@ fiq_rtx The tx buffer pointer
|
||||
@ fiq_rrx The rx buffer pointer
|
||||
@ fiq_rcount The number of bytes to move
|
||||
|
||||
@ each entry starts with a word entry of how long it is
|
||||
@ and an offset to the irq acknowledgment word
|
||||
|
||||
ENTRY(s3c24xx_spi_fiq_rx)
|
||||
s3c24xx_spi_fix_rx:
|
||||
.word fiq_rx_end - fiq_rx_start
|
||||
.word fiq_rx_irq_ack - fiq_rx_start
|
||||
fiq_rx_start:
|
||||
ldr fiq_rtmp, fiq_rx_irq_ack
|
||||
str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
|
||||
|
||||
ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ]
|
||||
strb fiq_rtmp, [ fiq_rrx ], #1
|
||||
|
||||
mov fiq_rtmp, #0xff
|
||||
strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
|
||||
|
||||
subs fiq_rcount, fiq_rcount, #1
|
||||
subnes pc, lr, #4 @@ return, still have work to do
|
||||
|
||||
@@ set IRQ controller so that next op will trigger IRQ
|
||||
mov fiq_rtmp, #0
|
||||
str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ]
|
||||
subs pc, lr, #4
|
||||
|
||||
fiq_rx_irq_ack:
|
||||
.word 0
|
||||
fiq_rx_end:
|
||||
|
||||
ENTRY(s3c24xx_spi_fiq_txrx)
|
||||
s3c24xx_spi_fiq_txrx:
|
||||
.word fiq_txrx_end - fiq_txrx_start
|
||||
.word fiq_txrx_irq_ack - fiq_txrx_start
|
||||
fiq_txrx_start:
|
||||
|
||||
ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ]
|
||||
strb fiq_rtmp, [ fiq_rrx ], #1
|
||||
|
||||
ldr fiq_rtmp, fiq_txrx_irq_ack
|
||||
str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
|
||||
|
||||
ldrb fiq_rtmp, [ fiq_rtx ], #1
|
||||
strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
|
||||
|
||||
subs fiq_rcount, fiq_rcount, #1
|
||||
subnes pc, lr, #4 @@ return, still have work to do
|
||||
|
||||
mov fiq_rtmp, #0
|
||||
str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ]
|
||||
subs pc, lr, #4
|
||||
|
||||
fiq_txrx_irq_ack:
|
||||
.word 0
|
||||
|
||||
fiq_txrx_end:
|
||||
|
||||
ENTRY(s3c24xx_spi_fiq_tx)
|
||||
s3c24xx_spi_fix_tx:
|
||||
.word fiq_tx_end - fiq_tx_start
|
||||
.word fiq_tx_irq_ack - fiq_tx_start
|
||||
fiq_tx_start:
|
||||
ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ]
|
||||
|
||||
ldr fiq_rtmp, fiq_tx_irq_ack
|
||||
str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ]
|
||||
|
||||
ldrb fiq_rtmp, [ fiq_rtx ], #1
|
||||
strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ]
|
||||
|
||||
subs fiq_rcount, fiq_rcount, #1
|
||||
subnes pc, lr, #4 @@ return, still have work to do
|
||||
|
||||
mov fiq_rtmp, #0
|
||||
str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ]
|
||||
subs pc, lr, #4
|
||||
|
||||
fiq_tx_irq_ack:
|
||||
.word 0
|
||||
|
||||
fiq_tx_end:
|
||||
|
||||
.end
|
||||
@@ -0,0 +1,26 @@
|
||||
/* linux/drivers/spi/spi_s3c24xx_fiq.h
|
||||
*
|
||||
* Copyright 2009 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
*
|
||||
* S3C24XX SPI - FIQ pseudo-DMA transfer support
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* We have R8 through R13 to play with */
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#define __REG_NR(x) r##x
|
||||
#else
|
||||
#define __REG_NR(x) (x)
|
||||
#endif
|
||||
|
||||
#define fiq_rspi __REG_NR(8)
|
||||
#define fiq_rtmp __REG_NR(9)
|
||||
#define fiq_rrx __REG_NR(10)
|
||||
#define fiq_rtx __REG_NR(11)
|
||||
#define fiq_rcount __REG_NR(12)
|
||||
#define fiq_rirq __REG_NR(13)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -148,7 +148,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
|
||||
ret = -ENOENT;
|
||||
goto err1;
|
||||
}
|
||||
sp->membase = ioremap(r->start, r->end - r->start + 1);
|
||||
sp->membase = ioremap(r->start, resource_size(r));
|
||||
if (!sp->membase) {
|
||||
ret = -ENXIO;
|
||||
goto err1;
|
||||
|
||||
@@ -375,12 +375,10 @@ static int __init txx9spi_probe(struct platform_device *dev)
|
||||
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
goto exit_busy;
|
||||
if (!devm_request_mem_region(&dev->dev,
|
||||
res->start, res->end - res->start + 1,
|
||||
if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
|
||||
"spi_txx9"))
|
||||
goto exit_busy;
|
||||
c->membase = devm_ioremap(&dev->dev,
|
||||
res->start, res->end - res->start + 1);
|
||||
c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
|
||||
if (!c->membase)
|
||||
goto exit_busy;
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#define SPIDEV_MAJOR 153 /* assigned */
|
||||
#define N_SPI_MINORS 32 /* ... up to 256 */
|
||||
|
||||
static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
|
||||
static DECLARE_BITMAP(minors, N_SPI_MINORS);
|
||||
|
||||
|
||||
/* Bit masks for spi_device.mode management. Note that incorrect
|
||||
@@ -558,7 +558,7 @@ static struct class *spidev_class;
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int spidev_probe(struct spi_device *spi)
|
||||
static int __devinit spidev_probe(struct spi_device *spi)
|
||||
{
|
||||
struct spidev_data *spidev;
|
||||
int status;
|
||||
@@ -607,7 +607,7 @@ static int spidev_probe(struct spi_device *spi)
|
||||
return status;
|
||||
}
|
||||
|
||||
static int spidev_remove(struct spi_device *spi)
|
||||
static int __devexit spidev_remove(struct spi_device *spi)
|
||||
{
|
||||
struct spidev_data *spidev = spi_get_drvdata(spi);
|
||||
|
||||
@@ -629,7 +629,7 @@ static int spidev_remove(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver spidev_spi = {
|
||||
static struct spi_driver spidev_spi_driver = {
|
||||
.driver = {
|
||||
.name = "spidev",
|
||||
.owner = THIS_MODULE,
|
||||
@@ -661,14 +661,14 @@ static int __init spidev_init(void)
|
||||
|
||||
spidev_class = class_create(THIS_MODULE, "spidev");
|
||||
if (IS_ERR(spidev_class)) {
|
||||
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
|
||||
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
|
||||
return PTR_ERR(spidev_class);
|
||||
}
|
||||
|
||||
status = spi_register_driver(&spidev_spi);
|
||||
status = spi_register_driver(&spidev_spi_driver);
|
||||
if (status < 0) {
|
||||
class_destroy(spidev_class);
|
||||
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
|
||||
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -676,9 +676,9 @@ module_init(spidev_init);
|
||||
|
||||
static void __exit spidev_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&spidev_spi);
|
||||
spi_unregister_driver(&spidev_spi_driver);
|
||||
class_destroy(spidev_class);
|
||||
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
|
||||
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
|
||||
}
|
||||
module_exit(spidev_exit);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user