Merge remote-tracking branch 'spi/topic/bitbang' into spi-next
This commit is contained in:
commit
b29bc3df37
|
@ -103,16 +103,6 @@ static void altera_spi_chipsel(struct spi_device *spi, int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int altera_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int altera_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
|
static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
|
||||||
{
|
{
|
||||||
if (hw->tx) {
|
if (hw->tx) {
|
||||||
|
@ -224,7 +214,6 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = 16;
|
master->num_chipselect = 16;
|
||||||
master->mode_bits = SPI_CS_HIGH;
|
master->mode_bits = SPI_CS_HIGH;
|
||||||
master->setup = altera_spi_setup;
|
|
||||||
|
|
||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
platform_set_drvdata(pdev, hw);
|
platform_set_drvdata(pdev, hw);
|
||||||
|
@ -233,7 +222,6 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||||
hw->bitbang.master = spi_master_get(master);
|
hw->bitbang.master = spi_master_get(master);
|
||||||
if (!hw->bitbang.master)
|
if (!hw->bitbang.master)
|
||||||
return err;
|
return err;
|
||||||
hw->bitbang.setup_transfer = altera_spi_setupxfer;
|
|
||||||
hw->bitbang.chipselect = altera_spi_chipsel;
|
hw->bitbang.chipselect = altera_spi_chipsel;
|
||||||
hw->bitbang.txrx_bufs = altera_spi_txrx;
|
hw->bitbang.txrx_bufs = altera_spi_txrx;
|
||||||
|
|
||||||
|
|
|
@ -255,26 +255,33 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||||
* Drivers can provide word-at-a-time i/o primitives, or provide
|
* Drivers can provide word-at-a-time i/o primitives, or provide
|
||||||
* transfer-at-a-time ones to leverage dma or fifo hardware.
|
* transfer-at-a-time ones to leverage dma or fifo hardware.
|
||||||
*/
|
*/
|
||||||
static void bitbang_work(struct work_struct *work)
|
|
||||||
|
static int spi_bitbang_prepare_hardware(struct spi_master *spi)
|
||||||
{
|
{
|
||||||
struct spi_bitbang *bitbang =
|
struct spi_bitbang *bitbang;
|
||||||
container_of(work, struct spi_bitbang, work);
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct spi_message *m, *_m;
|
|
||||||
|
bitbang = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
spin_lock_irqsave(&bitbang->lock, flags);
|
spin_lock_irqsave(&bitbang->lock, flags);
|
||||||
bitbang->busy = 1;
|
bitbang->busy = 1;
|
||||||
list_for_each_entry_safe(m, _m, &bitbang->queue, queue) {
|
spin_unlock_irqrestore(&bitbang->lock, flags);
|
||||||
struct spi_device *spi;
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_bitbang_transfer_one(struct spi_master *master,
|
||||||
|
struct spi_message *m)
|
||||||
|
{
|
||||||
|
struct spi_bitbang *bitbang;
|
||||||
unsigned nsecs;
|
unsigned nsecs;
|
||||||
struct spi_transfer *t = NULL;
|
struct spi_transfer *t = NULL;
|
||||||
unsigned tmp;
|
|
||||||
unsigned cs_change;
|
unsigned cs_change;
|
||||||
int status;
|
int status;
|
||||||
int do_setup = -1;
|
int do_setup = -1;
|
||||||
|
struct spi_device *spi = m->spi;
|
||||||
|
|
||||||
list_del(&m->queue);
|
bitbang = spi_master_get_devdata(master);
|
||||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
|
||||||
|
|
||||||
/* FIXME this is made-up ... the correct value is known to
|
/* FIXME this is made-up ... the correct value is known to
|
||||||
* word-at-a-time bitbang code, and presumably chipselect()
|
* word-at-a-time bitbang code, and presumably chipselect()
|
||||||
|
@ -282,8 +289,6 @@ static void bitbang_work(struct work_struct *work)
|
||||||
*/
|
*/
|
||||||
nsecs = 100;
|
nsecs = 100;
|
||||||
|
|
||||||
spi = m->spi;
|
|
||||||
tmp = 0;
|
|
||||||
cs_change = 1;
|
cs_change = 1;
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
|
@ -355,7 +360,6 @@ static void bitbang_work(struct work_struct *work)
|
||||||
}
|
}
|
||||||
|
|
||||||
m->status = status;
|
m->status = status;
|
||||||
m->complete(m->context);
|
|
||||||
|
|
||||||
/* normally deactivate chipselect ... unless no error and
|
/* normally deactivate chipselect ... unless no error and
|
||||||
* cs_change has hinted that the next message will probably
|
* cs_change has hinted that the next message will probably
|
||||||
|
@ -367,38 +371,24 @@ static void bitbang_work(struct work_struct *work)
|
||||||
ndelay(nsecs);
|
ndelay(nsecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&bitbang->lock, flags);
|
spi_finalize_current_message(master);
|
||||||
}
|
|
||||||
bitbang->busy = 0;
|
|
||||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spi_bitbang_transfer - default submit to transfer queue
|
|
||||||
*/
|
|
||||||
int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
|
|
||||||
{
|
|
||||||
struct spi_bitbang *bitbang;
|
|
||||||
unsigned long flags;
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
m->actual_length = 0;
|
|
||||||
m->status = -EINPROGRESS;
|
|
||||||
|
|
||||||
bitbang = spi_master_get_devdata(spi->master);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&bitbang->lock, flags);
|
|
||||||
if (!spi->max_speed_hz)
|
|
||||||
status = -ENETDOWN;
|
|
||||||
else {
|
|
||||||
list_add_tail(&m->queue, &bitbang->queue);
|
|
||||||
queue_work(bitbang->workqueue, &bitbang->work);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
|
|
||||||
|
static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
|
||||||
|
{
|
||||||
|
struct spi_bitbang *bitbang;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
bitbang = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&bitbang->lock, flags);
|
||||||
|
bitbang->busy = 0;
|
||||||
|
spin_unlock_irqrestore(&bitbang->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -428,20 +418,22 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
|
||||||
int spi_bitbang_start(struct spi_bitbang *bitbang)
|
int spi_bitbang_start(struct spi_bitbang *bitbang)
|
||||||
{
|
{
|
||||||
struct spi_master *master = bitbang->master;
|
struct spi_master *master = bitbang->master;
|
||||||
int status;
|
|
||||||
|
|
||||||
if (!master || !bitbang->chipselect)
|
if (!master || !bitbang->chipselect)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
INIT_WORK(&bitbang->work, bitbang_work);
|
|
||||||
spin_lock_init(&bitbang->lock);
|
spin_lock_init(&bitbang->lock);
|
||||||
INIT_LIST_HEAD(&bitbang->queue);
|
|
||||||
|
|
||||||
if (!master->mode_bits)
|
if (!master->mode_bits)
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
|
||||||
|
|
||||||
if (!master->transfer)
|
if (master->transfer || master->transfer_one_message)
|
||||||
master->transfer = spi_bitbang_transfer;
|
return -EINVAL;
|
||||||
|
|
||||||
|
master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
|
||||||
|
master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
|
||||||
|
master->transfer_one_message = spi_bitbang_transfer_one;
|
||||||
|
|
||||||
if (!bitbang->txrx_bufs) {
|
if (!bitbang->txrx_bufs) {
|
||||||
bitbang->use_dma = 0;
|
bitbang->use_dma = 0;
|
||||||
bitbang->txrx_bufs = spi_bitbang_bufs;
|
bitbang->txrx_bufs = spi_bitbang_bufs;
|
||||||
|
@ -452,34 +444,12 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
|
||||||
master->setup = spi_bitbang_setup;
|
master->setup = spi_bitbang_setup;
|
||||||
master->cleanup = spi_bitbang_cleanup;
|
master->cleanup = spi_bitbang_cleanup;
|
||||||
}
|
}
|
||||||
} else if (!master->setup)
|
|
||||||
return -EINVAL;
|
|
||||||
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(master->dev.parent));
|
|
||||||
if (bitbang->workqueue == NULL) {
|
|
||||||
status = -EBUSY;
|
|
||||||
goto err1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* driver may get busy before register() returns, especially
|
/* driver may get busy before register() returns, especially
|
||||||
* if someone registered boardinfo for devices
|
* if someone registered boardinfo for devices
|
||||||
*/
|
*/
|
||||||
status = spi_register_master(master);
|
return spi_register_master(master);
|
||||||
if (status < 0)
|
|
||||||
goto err2;
|
|
||||||
|
|
||||||
return status;
|
|
||||||
|
|
||||||
err2:
|
|
||||||
destroy_workqueue(bitbang->workqueue);
|
|
||||||
err1:
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_bitbang_start);
|
EXPORT_SYMBOL_GPL(spi_bitbang_start);
|
||||||
|
|
||||||
|
@ -490,10 +460,6 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang)
|
||||||
{
|
{
|
||||||
spi_unregister_master(bitbang->master);
|
spi_unregister_master(bitbang->master);
|
||||||
|
|
||||||
WARN_ON(!list_empty(&bitbang->queue));
|
|
||||||
|
|
||||||
destroy_workqueue(bitbang->workqueue);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
|
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
|
||||||
|
|
|
@ -174,17 +174,6 @@ static void nuc900_spi_gobusy(struct nuc900_spi *hw)
|
||||||
spin_unlock_irqrestore(&hw->lock, flags);
|
spin_unlock_irqrestore(&hw->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nuc900_spi_setupxfer(struct spi_device *spi,
|
|
||||||
struct spi_transfer *t)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nuc900_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
|
static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
|
||||||
{
|
{
|
||||||
return hw->tx ? hw->tx[count] : 0;
|
return hw->tx ? hw->tx[count] : 0;
|
||||||
|
@ -377,10 +366,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
|
||||||
master->num_chipselect = hw->pdata->num_cs;
|
master->num_chipselect = hw->pdata->num_cs;
|
||||||
master->bus_num = hw->pdata->bus_num;
|
master->bus_num = hw->pdata->bus_num;
|
||||||
hw->bitbang.master = hw->master;
|
hw->bitbang.master = hw->master;
|
||||||
hw->bitbang.setup_transfer = nuc900_spi_setupxfer;
|
|
||||||
hw->bitbang.chipselect = nuc900_spi_chipsel;
|
hw->bitbang.chipselect = nuc900_spi_chipsel;
|
||||||
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
|
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
|
||||||
hw->bitbang.master->setup = nuc900_spi_setup;
|
|
||||||
|
|
||||||
hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (hw->res == NULL) {
|
if (hw->res == NULL) {
|
||||||
|
|
|
@ -233,21 +233,6 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xilinx_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
/* always return 0, we can not check the number of bits.
|
|
||||||
* There are cases when SPI setup is called before any driver is
|
|
||||||
* there, in that case the SPI core defaults to 8 bits, which we
|
|
||||||
* do not support in some cases. But if we return an error, the
|
|
||||||
* SPI device would not be registered and no driver can get hold of it
|
|
||||||
* When the driver is there, it will call SPI setup again with the
|
|
||||||
* correct number of bits per transfer.
|
|
||||||
* If a driver setups with the wrong bit number, it will fail when
|
|
||||||
* it tries to do a transfer
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
|
static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
|
||||||
{
|
{
|
||||||
u8 sr;
|
u8 sr;
|
||||||
|
@ -375,7 +360,6 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
|
||||||
xspi->bitbang.chipselect = xilinx_spi_chipselect;
|
xspi->bitbang.chipselect = xilinx_spi_chipselect;
|
||||||
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
|
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
|
||||||
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
|
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
|
||||||
xspi->bitbang.master->setup = xilinx_spi_setup;
|
|
||||||
init_completion(&xspi->done);
|
init_completion(&xspi->done);
|
||||||
|
|
||||||
if (!request_mem_region(mem->start, resource_size(mem),
|
if (!request_mem_region(mem->start, resource_size(mem),
|
||||||
|
|
|
@ -4,11 +4,7 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
struct spi_bitbang {
|
struct spi_bitbang {
|
||||||
struct workqueue_struct *workqueue;
|
|
||||||
struct work_struct work;
|
|
||||||
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct list_head queue;
|
|
||||||
u8 busy;
|
u8 busy;
|
||||||
u8 use_dma;
|
u8 use_dma;
|
||||||
u8 flags; /* extra spi->mode support */
|
u8 flags; /* extra spi->mode support */
|
||||||
|
@ -41,7 +37,6 @@ struct spi_bitbang {
|
||||||
*/
|
*/
|
||||||
extern int spi_bitbang_setup(struct spi_device *spi);
|
extern int spi_bitbang_setup(struct spi_device *spi);
|
||||||
extern void spi_bitbang_cleanup(struct spi_device *spi);
|
extern void spi_bitbang_cleanup(struct spi_device *spi);
|
||||||
extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
|
|
||||||
extern int spi_bitbang_setup_transfer(struct spi_device *spi,
|
extern int spi_bitbang_setup_transfer(struct spi_device *spi,
|
||||||
struct spi_transfer *t);
|
struct spi_transfer *t);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue