Commit c9bfcb31 authored by Joakim Tjernlund's avatar Joakim Tjernlund Committed by Linus Torvalds

spi_mpc83xx: much improved driver

The current driver may cause glitches on SPI CLK line since one must disable
the SPI controller before changing any HW settings.  Fix this by implementing
a local spi_transfer function that won't change speed and/or word size while
CS is active.

While doing that heavy lifting a few other issues were addressed too:
 - Make word size 16 and 32 work too.
 - Honor bits_per_word and speed_hz in spi transaction.
 - Optimize the common path.

This also stops using the "bitbang" framework (except for a few constants).

[Roel Kluin <12o3l@tiscali.nl>: "irq" needs to be signed]
Signed-off-by: default avatarJoakim Tjernlund <Joakim.Tjernlund@transmode.se>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f4ed0dea
...@@ -126,7 +126,6 @@ config SPI_MPC52xx_PSC ...@@ -126,7 +126,6 @@ config SPI_MPC52xx_PSC
config SPI_MPC83xx config SPI_MPC83xx
tristate "Freescale MPC83xx/QUICC Engine SPI controller" tristate "Freescale MPC83xx/QUICC Engine SPI controller"
depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
select SPI_BITBANG
help help
This enables using the Freescale MPC83xx and QUICC Engine SPI This enables using the Freescale MPC83xx and QUICC Engine SPI
controllers in master mode. controllers in master mode.
......
...@@ -49,6 +49,7 @@ struct mpc83xx_spi_reg { ...@@ -49,6 +49,7 @@ struct mpc83xx_spi_reg {
#define SPMODE_LEN(x) ((x) << 20) #define SPMODE_LEN(x) ((x) << 20)
#define SPMODE_PM(x) ((x) << 16) #define SPMODE_PM(x) ((x) << 16)
#define SPMODE_OP (1 << 14) #define SPMODE_OP (1 << 14)
#define SPMODE_CG(x) ((x) << 7)
/* /*
* Default for SPI Mode: * Default for SPI Mode:
...@@ -67,10 +68,6 @@ struct mpc83xx_spi_reg { ...@@ -67,10 +68,6 @@ struct mpc83xx_spi_reg {
/* SPI Controller driver's private data. */ /* SPI Controller driver's private data. */
struct mpc83xx_spi { struct mpc83xx_spi {
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
struct mpc83xx_spi_reg __iomem *base; struct mpc83xx_spi_reg __iomem *base;
/* rx & tx bufs from the spi_transfer */ /* rx & tx bufs from the spi_transfer */
...@@ -82,7 +79,7 @@ struct mpc83xx_spi { ...@@ -82,7 +79,7 @@ struct mpc83xx_spi {
u32(*get_tx) (struct mpc83xx_spi *); u32(*get_tx) (struct mpc83xx_spi *);
unsigned int count; unsigned int count;
u32 irq; int irq;
unsigned nsecs; /* (clock cycle time)/2 */ unsigned nsecs; /* (clock cycle time)/2 */
...@@ -94,6 +91,25 @@ struct mpc83xx_spi { ...@@ -94,6 +91,25 @@ struct mpc83xx_spi {
void (*activate_cs) (u8 cs, u8 polarity); void (*activate_cs) (u8 cs, u8 polarity);
void (*deactivate_cs) (u8 cs, u8 polarity); void (*deactivate_cs) (u8 cs, u8 polarity);
u8 busy;
struct workqueue_struct *workqueue;
struct work_struct work;
struct list_head queue;
spinlock_t lock;
struct completion done;
};
struct spi_mpc83xx_cs {
/* functions to deal with different sized buffers */
void (*get_rx) (u32 rx_data, struct mpc83xx_spi *);
u32 (*get_tx) (struct mpc83xx_spi *);
u32 rx_shift; /* RX data reg shift when in qe mode */
u32 tx_shift; /* TX data reg shift when in qe mode */
u32 hw_mode; /* Holds HW mode register settings */
}; };
static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val) static inline void mpc83xx_spi_write_reg(__be32 __iomem * reg, u32 val)
...@@ -137,6 +153,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) ...@@ -137,6 +153,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
{ {
struct mpc83xx_spi *mpc83xx_spi; struct mpc83xx_spi *mpc83xx_spi;
u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0; u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0;
struct spi_mpc83xx_cs *cs = spi->controller_state;
mpc83xx_spi = spi_master_get_devdata(spi->master); mpc83xx_spi = spi_master_get_devdata(spi->master);
...@@ -147,50 +164,26 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) ...@@ -147,50 +164,26 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
if (value == BITBANG_CS_ACTIVE) { if (value == BITBANG_CS_ACTIVE) {
u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
u32 len = spi->bits_per_word;
u8 pm;
if (len == 32) mpc83xx_spi->rx_shift = cs->rx_shift;
len = 0; mpc83xx_spi->tx_shift = cs->tx_shift;
else mpc83xx_spi->get_rx = cs->get_rx;
len = len - 1; mpc83xx_spi->get_tx = cs->get_tx;
/* mask out bits we are going to set */ if (cs->hw_mode != regval) {
regval &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH unsigned long flags;
| SPMODE_LEN(0xF) | SPMODE_DIV16 void *tmp_ptr = &mpc83xx_spi->base->mode;
| SPMODE_PM(0xF) | SPMODE_REV | SPMODE_LOOP);
regval = cs->hw_mode;
if (spi->mode & SPI_CPHA) /* Turn off IRQs locally to minimize time that
regval |= SPMODE_CP_BEGIN_EDGECLK; * SPI is disabled
if (spi->mode & SPI_CPOL) */
regval |= SPMODE_CI_INACTIVEHIGH; local_irq_save(flags);
if (!(spi->mode & SPI_LSB_FIRST)) /* Turn off SPI unit prior changing mode */
regval |= SPMODE_REV; mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
if (spi->mode & SPI_LOOP) mpc83xx_spi_write_reg(tmp_ptr, regval);
regval |= SPMODE_LOOP; local_irq_restore(flags);
regval |= SPMODE_LEN(len);
if ((mpc83xx_spi->spibrg / spi->max_speed_hz) >= 64) {
pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 64) - 1;
if (pm > 0x0f) {
dev_err(&spi->dev, "Requested speed is too "
"low: %d Hz. Will use %d Hz instead.\n",
spi->max_speed_hz,
mpc83xx_spi->spibrg / 1024);
pm = 0x0f;
}
regval |= SPMODE_PM(pm) | SPMODE_DIV16;
} else {
pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4);
if (pm)
pm--;
regval |= SPMODE_PM(pm);
} }
/* Turn off SPI unit prior changing mode */
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
if (mpc83xx_spi->activate_cs) if (mpc83xx_spi->activate_cs)
mpc83xx_spi->activate_cs(spi->chip_select, pol); mpc83xx_spi->activate_cs(spi->chip_select, pol);
} }
...@@ -201,8 +194,9 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -201,8 +194,9 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{ {
struct mpc83xx_spi *mpc83xx_spi; struct mpc83xx_spi *mpc83xx_spi;
u32 regval; u32 regval;
u8 bits_per_word; u8 bits_per_word, pm;
u32 hz; u32 hz;
struct spi_mpc83xx_cs *cs = spi->controller_state;
mpc83xx_spi = spi_master_get_devdata(spi->master); mpc83xx_spi = spi_master_get_devdata(spi->master);
...@@ -223,61 +217,191 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -223,61 +217,191 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|| ((bits_per_word > 16) && (bits_per_word != 32))) || ((bits_per_word > 16) && (bits_per_word != 32)))
return -EINVAL; return -EINVAL;
mpc83xx_spi->rx_shift = 0; if (!hz)
mpc83xx_spi->tx_shift = 0; hz = spi->max_speed_hz;
cs->rx_shift = 0;
cs->tx_shift = 0;
if (bits_per_word <= 8) { if (bits_per_word <= 8) {
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8; cs->get_rx = mpc83xx_spi_rx_buf_u8;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8; cs->get_tx = mpc83xx_spi_tx_buf_u8;
if (mpc83xx_spi->qe_mode) { if (mpc83xx_spi->qe_mode) {
mpc83xx_spi->rx_shift = 16; cs->rx_shift = 16;
mpc83xx_spi->tx_shift = 24; cs->tx_shift = 24;
} }
} else if (bits_per_word <= 16) { } else if (bits_per_word <= 16) {
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u16; cs->get_rx = mpc83xx_spi_rx_buf_u16;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u16; cs->get_tx = mpc83xx_spi_tx_buf_u16;
if (mpc83xx_spi->qe_mode) { if (mpc83xx_spi->qe_mode) {
mpc83xx_spi->rx_shift = 16; cs->rx_shift = 16;
mpc83xx_spi->tx_shift = 16; cs->tx_shift = 16;
} }
} else if (bits_per_word <= 32) { } else if (bits_per_word <= 32) {
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u32; cs->get_rx = mpc83xx_spi_rx_buf_u32;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u32; cs->get_tx = mpc83xx_spi_tx_buf_u32;
} else } else
return -EINVAL; return -EINVAL;
if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) { if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
mpc83xx_spi->tx_shift = 0; cs->tx_shift = 0;
if (bits_per_word <= 8) if (bits_per_word <= 8)
mpc83xx_spi->rx_shift = 8; cs->rx_shift = 8;
else else
mpc83xx_spi->rx_shift = 0; cs->rx_shift = 0;
} }
/* nsecs = (clock period)/2 */ mpc83xx_spi->rx_shift = cs->rx_shift;
if (!hz) mpc83xx_spi->tx_shift = cs->tx_shift;
hz = spi->max_speed_hz; mpc83xx_spi->get_rx = cs->get_rx;
mpc83xx_spi->nsecs = (1000000000 / 2) / hz; mpc83xx_spi->get_tx = cs->get_tx;
if (mpc83xx_spi->nsecs > MAX_UDELAY_MS * 1000)
return -EINVAL;
if (bits_per_word == 32) if (bits_per_word == 32)
bits_per_word = 0; bits_per_word = 0;
else else
bits_per_word = bits_per_word - 1; bits_per_word = bits_per_word - 1;
regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
/* mask out bits we are going to set */ /* mask out bits we are going to set */
regval &= ~(SPMODE_LEN(0xF) | SPMODE_REV); cs->hw_mode &= ~(SPMODE_LEN(0xF) | SPMODE_DIV16
regval |= SPMODE_LEN(bits_per_word); | SPMODE_PM(0xF));
if (!(spi->mode & SPI_LSB_FIRST))
regval |= SPMODE_REV; cs->hw_mode |= SPMODE_LEN(bits_per_word);
if ((mpc83xx_spi->spibrg / hz) >= 64) {
pm = mpc83xx_spi->spibrg / (hz * 64) - 1;
if (pm > 0x0f) {
dev_err(&spi->dev, "Requested speed is too "
"low: %d Hz. Will use %d Hz instead.\n",
hz, mpc83xx_spi->spibrg / 1024);
pm = 0x0f;
}
cs->hw_mode |= SPMODE_PM(pm) | SPMODE_DIV16;
} else {
pm = mpc83xx_spi->spibrg / (hz * 4);
if (pm)
pm--;
cs->hw_mode |= SPMODE_PM(pm);
}
regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
if (cs->hw_mode != regval) {
unsigned long flags;
void *tmp_ptr = &mpc83xx_spi->base->mode;
regval = cs->hw_mode;
/* Turn off IRQs locally to minimize time
* that SPI is disabled
*/
local_irq_save(flags);
/* Turn off SPI unit prior changing mode */
mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE);
mpc83xx_spi_write_reg(tmp_ptr, regval);
local_irq_restore(flags);
}
return 0;
}
/* Turn off SPI unit prior changing mode */ static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0); {
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval); struct mpc83xx_spi *mpc83xx_spi;
u32 word, len, bits_per_word;
return 0; mpc83xx_spi = spi_master_get_devdata(spi->master);
mpc83xx_spi->tx = t->tx_buf;
mpc83xx_spi->rx = t->rx_buf;
bits_per_word = spi->bits_per_word;
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
len = t->len;
if (bits_per_word > 8)
len /= 2;
if (bits_per_word > 16)
len /= 2;
mpc83xx_spi->count = len;
INIT_COMPLETION(mpc83xx_spi->done);
/* enable rx ints */
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE);
/* transmit word */
word = mpc83xx_spi->get_tx(mpc83xx_spi);
mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
wait_for_completion(&mpc83xx_spi->done);
/* disable rx ints */
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
return mpc83xx_spi->count;
}
static void mpc83xx_spi_work(struct work_struct *work)
{
struct mpc83xx_spi *mpc83xx_spi =
container_of(work, struct mpc83xx_spi, work);
spin_lock_irq(&mpc83xx_spi->lock);
mpc83xx_spi->busy = 1;
while (!list_empty(&mpc83xx_spi->queue)) {
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
unsigned cs_change;
int status, nsecs = 50;
m = container_of(mpc83xx_spi->queue.next,
struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irq(&mpc83xx_spi->lock);
spi = m->spi;
cs_change = 1;
status = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->bits_per_word || t->speed_hz) {
/* Don't allow changes if CS is active */
status = -EINVAL;
if (cs_change)
status = mpc83xx_spi_setup_transfer(spi, t);
if (status < 0)
break;
}
if (cs_change)
mpc83xx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
cs_change = t->cs_change;
if (t->len)
status = mpc83xx_spi_bufs(spi, t);
if (status) {
status = -EMSGSIZE;
break;
}
m->actual_length += t->len;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (cs_change) {
ndelay(nsecs);
mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
}
m->status = status;
m->complete(m->context);
if (status || !cs_change) {
ndelay(nsecs);
mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
}
mpc83xx_spi_setup_transfer(spi, NULL);
spin_lock_irq(&mpc83xx_spi->lock);
}
mpc83xx_spi->busy = 0;
spin_unlock_irq(&mpc83xx_spi->lock);
} }
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
...@@ -286,9 +410,10 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -286,9 +410,10 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static int mpc83xx_spi_setup(struct spi_device *spi) static int mpc83xx_spi_setup(struct spi_device *spi)
{ {
struct spi_bitbang *bitbang;
struct mpc83xx_spi *mpc83xx_spi; struct mpc83xx_spi *mpc83xx_spi;
int retval; int retval;
u32 hw_mode;
struct spi_mpc83xx_cs *cs = spi->controller_state;
if (spi->mode & ~MODEBITS) { if (spi->mode & ~MODEBITS) {
dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
...@@ -299,63 +424,56 @@ static int mpc83xx_spi_setup(struct spi_device *spi) ...@@ -299,63 +424,56 @@ static int mpc83xx_spi_setup(struct spi_device *spi)
if (!spi->max_speed_hz) if (!spi->max_speed_hz)
return -EINVAL; return -EINVAL;
bitbang = spi_master_get_devdata(spi->master); if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
mpc83xx_spi = spi_master_get_devdata(spi->master); mpc83xx_spi = spi_master_get_devdata(spi->master);
if (!spi->bits_per_word) if (!spi->bits_per_word)
spi->bits_per_word = 8; spi->bits_per_word = 8;
hw_mode = cs->hw_mode; /* Save orginal settings */
cs->hw_mode = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
/* mask out bits we are going to set */
cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
| SPMODE_REV | SPMODE_LOOP);
if (spi->mode & SPI_CPHA)
cs->hw_mode |= SPMODE_CP_BEGIN_EDGECLK;
if (spi->mode & SPI_CPOL)
cs->hw_mode |= SPMODE_CI_INACTIVEHIGH;
if (!(spi->mode & SPI_LSB_FIRST))
cs->hw_mode |= SPMODE_REV;
if (spi->mode & SPI_LOOP)
cs->hw_mode |= SPMODE_LOOP;
retval = mpc83xx_spi_setup_transfer(spi, NULL); retval = mpc83xx_spi_setup_transfer(spi, NULL);
if (retval < 0) if (retval < 0) {
cs->hw_mode = hw_mode; /* Restore settings */
return retval; return retval;
}
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u Hz\n",
__func__, spi->mode & (SPI_CPOL | SPI_CPHA), __func__, spi->mode & (SPI_CPOL | SPI_CPHA),
spi->bits_per_word, 2 * mpc83xx_spi->nsecs); spi->bits_per_word, spi->max_speed_hz);
#if 0 /* Don't think this is needed */
/* NOTE we _need_ to call chipselect() early, ideally with adapter /* NOTE we _need_ to call chipselect() early, ideally with adapter
* setup, unless the hardware defaults cooperate to avoid confusion * setup, unless the hardware defaults cooperate to avoid confusion
* between normal (active low) and inverted chipselects. * between normal (active low) and inverted chipselects.
*/ */
/* deselect chip (low or high) */ /* deselect chip (low or high) */
spin_lock(&bitbang->lock); spin_lock(&mpc83xx_spi->lock);
if (!bitbang->busy) { if (!mpc83xx_spi->busy)
bitbang->chipselect(spi, BITBANG_CS_INACTIVE); mpc83xx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(mpc83xx_spi->nsecs); spin_unlock(&mpc83xx_spi->lock);
} #endif
spin_unlock(&bitbang->lock);
return 0; return 0;
} }
static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc83xx_spi *mpc83xx_spi;
u32 word;
mpc83xx_spi = spi_master_get_devdata(spi->master);
mpc83xx_spi->tx = t->tx_buf;
mpc83xx_spi->rx = t->rx_buf;
mpc83xx_spi->count = t->len;
INIT_COMPLETION(mpc83xx_spi->done);
/* enable rx ints */
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, SPIM_NE);
/* transmit word */
word = mpc83xx_spi->get_tx(mpc83xx_spi);
mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
wait_for_completion(&mpc83xx_spi->done);
/* disable rx ints */
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
return t->len - mpc83xx_spi->count;
}
irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
{ {
struct mpc83xx_spi *mpc83xx_spi = context_data; struct mpc83xx_spi *mpc83xx_spi = context_data;
...@@ -395,6 +513,28 @@ irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) ...@@ -395,6 +513,28 @@ irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
return ret; return ret;
} }
static int mpc83xx_spi_transfer(struct spi_device *spi,
struct spi_message *m)
{
struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master);
unsigned long flags;
m->actual_length = 0;
m->status = -EINPROGRESS;
spin_lock_irqsave(&mpc83xx_spi->lock, flags);
list_add_tail(&m->queue, &mpc83xx_spi->queue);
queue_work(mpc83xx_spi->workqueue, &mpc83xx_spi->work);
spin_unlock_irqrestore(&mpc83xx_spi->lock, flags);
return 0;
}
static void mpc83xx_spi_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static int __init mpc83xx_spi_probe(struct platform_device *dev) static int __init mpc83xx_spi_probe(struct platform_device *dev)
{ {
...@@ -426,11 +566,11 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev) ...@@ -426,11 +566,11 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
ret = -ENODEV; ret = -ENODEV;
goto free_master; goto free_master;
} }
master->setup = mpc83xx_spi_setup;
master->transfer = mpc83xx_spi_transfer;
master->cleanup = mpc83xx_spi_cleanup;
mpc83xx_spi = spi_master_get_devdata(master); mpc83xx_spi = spi_master_get_devdata(master);
mpc83xx_spi->bitbang.master = spi_master_get(master);
mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
mpc83xx_spi->activate_cs = pdata->activate_cs; mpc83xx_spi->activate_cs = pdata->activate_cs;
mpc83xx_spi->deactivate_cs = pdata->deactivate_cs; mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
mpc83xx_spi->qe_mode = pdata->qe_mode; mpc83xx_spi->qe_mode = pdata->qe_mode;
...@@ -445,7 +585,6 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev) ...@@ -445,7 +585,6 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
mpc83xx_spi->tx_shift = 24; mpc83xx_spi->tx_shift = 24;
} }
mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup;
init_completion(&mpc83xx_spi->done); init_completion(&mpc83xx_spi->done);
mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1); mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
...@@ -483,11 +622,21 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev) ...@@ -483,11 +622,21 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
regval |= SPMODE_OP; regval |= SPMODE_OP;
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval); mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
spin_lock_init(&mpc83xx_spi->lock);
init_completion(&mpc83xx_spi->done);
INIT_WORK(&mpc83xx_spi->work, mpc83xx_spi_work);
INIT_LIST_HEAD(&mpc83xx_spi->queue);
ret = spi_bitbang_start(&mpc83xx_spi->bitbang); mpc83xx_spi->workqueue = create_singlethread_workqueue(
master->dev.parent->bus_id);
if (ret != 0) if (mpc83xx_spi->workqueue == NULL) {
ret = -EBUSY;
goto free_irq; goto free_irq;
}
ret = spi_register_master(master);
if (ret < 0)
goto unreg_master;
printk(KERN_INFO printk(KERN_INFO
"%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n", "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n",
...@@ -495,6 +644,8 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev) ...@@ -495,6 +644,8 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
return ret; return ret;
unreg_master:
destroy_workqueue(mpc83xx_spi->workqueue);
free_irq: free_irq:
free_irq(mpc83xx_spi->irq, mpc83xx_spi); free_irq(mpc83xx_spi->irq, mpc83xx_spi);
unmap_io: unmap_io:
...@@ -515,10 +666,12 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev) ...@@ -515,10 +666,12 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev)
master = platform_get_drvdata(dev); master = platform_get_drvdata(dev);
mpc83xx_spi = spi_master_get_devdata(master); mpc83xx_spi = spi_master_get_devdata(master);
spi_bitbang_stop(&mpc83xx_spi->bitbang); flush_workqueue(mpc83xx_spi->workqueue);
destroy_workqueue(mpc83xx_spi->workqueue);
spi_unregister_master(master);
free_irq(mpc83xx_spi->irq, mpc83xx_spi); free_irq(mpc83xx_spi->irq, mpc83xx_spi);
iounmap(mpc83xx_spi->base); iounmap(mpc83xx_spi->base);
spi_master_put(mpc83xx_spi->bitbang.master);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment