Merge remote-tracking branches 'spi/topic/bcm53xx', 'spi/topic/bcm63xx', 'spi/topic/bfin-sport', 'spi/topic/bfin5xx' and 'spi/topic/bitbang' into spi-next
This commit is contained in:
commit
c2da04dc21
|
@ -18,29 +18,6 @@
|
|||
#include <bcm63xx_dev_spi.h>
|
||||
#include <bcm63xx_regs.h>
|
||||
|
||||
/*
|
||||
* register offsets
|
||||
*/
|
||||
static const unsigned long bcm6348_regs_spi[] = {
|
||||
__GEN_SPI_REGS_TABLE(6348)
|
||||
};
|
||||
|
||||
static const unsigned long bcm6358_regs_spi[] = {
|
||||
__GEN_SPI_REGS_TABLE(6358)
|
||||
};
|
||||
|
||||
const unsigned long *bcm63xx_regs_spi;
|
||||
EXPORT_SYMBOL(bcm63xx_regs_spi);
|
||||
|
||||
static __init void bcm63xx_spi_regs_init(void)
|
||||
{
|
||||
if (BCMCPU_IS_6338() || BCMCPU_IS_6348())
|
||||
bcm63xx_regs_spi = bcm6348_regs_spi;
|
||||
if (BCMCPU_IS_3368() || BCMCPU_IS_6358() ||
|
||||
BCMCPU_IS_6362() || BCMCPU_IS_6368())
|
||||
bcm63xx_regs_spi = bcm6358_regs_spi;
|
||||
}
|
||||
|
||||
static struct resource spi_resources[] = {
|
||||
{
|
||||
.start = -1, /* filled at runtime */
|
||||
|
@ -53,19 +30,10 @@ static struct resource spi_resources[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct bcm63xx_spi_pdata spi_pdata = {
|
||||
.bus_num = 0,
|
||||
.num_chipselect = 8,
|
||||
};
|
||||
|
||||
static struct platform_device bcm63xx_spi_device = {
|
||||
.name = "bcm63xx-spi",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(spi_resources),
|
||||
.resource = spi_resources,
|
||||
.dev = {
|
||||
.platform_data = &spi_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
int __init bcm63xx_spi_register(void)
|
||||
|
@ -78,21 +46,15 @@ int __init bcm63xx_spi_register(void)
|
|||
spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
|
||||
|
||||
if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
|
||||
bcm63xx_spi_device.name = "bcm6348-spi",
|
||||
spi_resources[0].end += BCM_6348_RSET_SPI_SIZE - 1;
|
||||
spi_pdata.fifo_size = SPI_6348_MSG_DATA_SIZE;
|
||||
spi_pdata.msg_type_shift = SPI_6348_MSG_TYPE_SHIFT;
|
||||
spi_pdata.msg_ctl_width = SPI_6348_MSG_CTL_WIDTH;
|
||||
}
|
||||
|
||||
if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6362() ||
|
||||
BCMCPU_IS_6368()) {
|
||||
bcm63xx_spi_device.name = "bcm6358-spi",
|
||||
spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
|
||||
spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE;
|
||||
spi_pdata.msg_type_shift = SPI_6358_MSG_TYPE_SHIFT;
|
||||
spi_pdata.msg_ctl_width = SPI_6358_MSG_CTL_WIDTH;
|
||||
}
|
||||
|
||||
bcm63xx_spi_regs_init();
|
||||
|
||||
return platform_device_register(&bcm63xx_spi_device);
|
||||
}
|
||||
|
|
|
@ -7,48 +7,4 @@
|
|||
|
||||
int __init bcm63xx_spi_register(void);
|
||||
|
||||
struct bcm63xx_spi_pdata {
|
||||
unsigned int fifo_size;
|
||||
unsigned int msg_type_shift;
|
||||
unsigned int msg_ctl_width;
|
||||
int bus_num;
|
||||
int num_chipselect;
|
||||
};
|
||||
|
||||
enum bcm63xx_regs_spi {
|
||||
SPI_CMD,
|
||||
SPI_INT_STATUS,
|
||||
SPI_INT_MASK_ST,
|
||||
SPI_INT_MASK,
|
||||
SPI_ST,
|
||||
SPI_CLK_CFG,
|
||||
SPI_FILL_BYTE,
|
||||
SPI_MSG_TAIL,
|
||||
SPI_RX_TAIL,
|
||||
SPI_MSG_CTL,
|
||||
SPI_MSG_DATA,
|
||||
SPI_RX_DATA,
|
||||
};
|
||||
|
||||
#define __GEN_SPI_REGS_TABLE(__cpu) \
|
||||
[SPI_CMD] = SPI_## __cpu ##_CMD, \
|
||||
[SPI_INT_STATUS] = SPI_## __cpu ##_INT_STATUS, \
|
||||
[SPI_INT_MASK_ST] = SPI_## __cpu ##_INT_MASK_ST, \
|
||||
[SPI_INT_MASK] = SPI_## __cpu ##_INT_MASK, \
|
||||
[SPI_ST] = SPI_## __cpu ##_ST, \
|
||||
[SPI_CLK_CFG] = SPI_## __cpu ##_CLK_CFG, \
|
||||
[SPI_FILL_BYTE] = SPI_## __cpu ##_FILL_BYTE, \
|
||||
[SPI_MSG_TAIL] = SPI_## __cpu ##_MSG_TAIL, \
|
||||
[SPI_RX_TAIL] = SPI_## __cpu ##_RX_TAIL, \
|
||||
[SPI_MSG_CTL] = SPI_## __cpu ##_MSG_CTL, \
|
||||
[SPI_MSG_DATA] = SPI_## __cpu ##_MSG_DATA, \
|
||||
[SPI_RX_DATA] = SPI_## __cpu ##_RX_DATA,
|
||||
|
||||
static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg)
|
||||
{
|
||||
extern const unsigned long *bcm63xx_regs_spi;
|
||||
|
||||
return bcm63xx_regs_spi[reg];
|
||||
}
|
||||
|
||||
#endif /* BCM63XX_DEV_SPI_H */
|
||||
|
|
|
@ -136,7 +136,7 @@ config SPI_BCM53XX
|
|||
|
||||
config SPI_BCM63XX
|
||||
tristate "Broadcom BCM63xx SPI controller"
|
||||
depends on BCM63XX
|
||||
depends on BCM63XX || COMPILE_TEST
|
||||
help
|
||||
Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
|
||||
|
||||
|
|
|
@ -247,28 +247,19 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core)
|
|||
if (err) {
|
||||
spi_master_put(master);
|
||||
bcma_set_drvdata(core, NULL);
|
||||
goto out;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
|
||||
spi_new_device(master, &bcm53xx_info);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bcm53xxspi_bcma_remove(struct bcma_device *core)
|
||||
{
|
||||
struct bcm53xxspi *b53spi = bcma_get_drvdata(core);
|
||||
|
||||
spi_unregister_master(b53spi->master);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bcma_driver bcm53xxspi_bcma_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = bcm53xxspi_bcma_tbl,
|
||||
.probe = bcm53xxspi_bcma_probe,
|
||||
.remove = bcm53xxspi_bcma_remove,
|
||||
};
|
||||
|
||||
/**************************************************
|
||||
|
|
|
@ -27,10 +27,117 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <bcm63xx_dev_spi.h>
|
||||
/* BCM 6338/6348 SPI core */
|
||||
#define SPI_6348_RSET_SIZE 64
|
||||
#define SPI_6348_CMD 0x00 /* 16-bits register */
|
||||
#define SPI_6348_INT_STATUS 0x02
|
||||
#define SPI_6348_INT_MASK_ST 0x03
|
||||
#define SPI_6348_INT_MASK 0x04
|
||||
#define SPI_6348_ST 0x05
|
||||
#define SPI_6348_CLK_CFG 0x06
|
||||
#define SPI_6348_FILL_BYTE 0x07
|
||||
#define SPI_6348_MSG_TAIL 0x09
|
||||
#define SPI_6348_RX_TAIL 0x0b
|
||||
#define SPI_6348_MSG_CTL 0x40 /* 8-bits register */
|
||||
#define SPI_6348_MSG_CTL_WIDTH 8
|
||||
#define SPI_6348_MSG_DATA 0x41
|
||||
#define SPI_6348_MSG_DATA_SIZE 0x3f
|
||||
#define SPI_6348_RX_DATA 0x80
|
||||
#define SPI_6348_RX_DATA_SIZE 0x3f
|
||||
|
||||
/* BCM 3368/6358/6262/6368 SPI core */
|
||||
#define SPI_6358_RSET_SIZE 1804
|
||||
#define SPI_6358_MSG_CTL 0x00 /* 16-bits register */
|
||||
#define SPI_6358_MSG_CTL_WIDTH 16
|
||||
#define SPI_6358_MSG_DATA 0x02
|
||||
#define SPI_6358_MSG_DATA_SIZE 0x21e
|
||||
#define SPI_6358_RX_DATA 0x400
|
||||
#define SPI_6358_RX_DATA_SIZE 0x220
|
||||
#define SPI_6358_CMD 0x700 /* 16-bits register */
|
||||
#define SPI_6358_INT_STATUS 0x702
|
||||
#define SPI_6358_INT_MASK_ST 0x703
|
||||
#define SPI_6358_INT_MASK 0x704
|
||||
#define SPI_6358_ST 0x705
|
||||
#define SPI_6358_CLK_CFG 0x706
|
||||
#define SPI_6358_FILL_BYTE 0x707
|
||||
#define SPI_6358_MSG_TAIL 0x709
|
||||
#define SPI_6358_RX_TAIL 0x70B
|
||||
|
||||
/* Shared SPI definitions */
|
||||
|
||||
/* Message configuration */
|
||||
#define SPI_FD_RW 0x00
|
||||
#define SPI_HD_W 0x01
|
||||
#define SPI_HD_R 0x02
|
||||
#define SPI_BYTE_CNT_SHIFT 0
|
||||
#define SPI_6348_MSG_TYPE_SHIFT 6
|
||||
#define SPI_6358_MSG_TYPE_SHIFT 14
|
||||
|
||||
/* Command */
|
||||
#define SPI_CMD_NOOP 0x00
|
||||
#define SPI_CMD_SOFT_RESET 0x01
|
||||
#define SPI_CMD_HARD_RESET 0x02
|
||||
#define SPI_CMD_START_IMMEDIATE 0x03
|
||||
#define SPI_CMD_COMMAND_SHIFT 0
|
||||
#define SPI_CMD_COMMAND_MASK 0x000f
|
||||
#define SPI_CMD_DEVICE_ID_SHIFT 4
|
||||
#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT 8
|
||||
#define SPI_CMD_ONE_BYTE_SHIFT 11
|
||||
#define SPI_CMD_ONE_WIRE_SHIFT 12
|
||||
#define SPI_DEV_ID_0 0
|
||||
#define SPI_DEV_ID_1 1
|
||||
#define SPI_DEV_ID_2 2
|
||||
#define SPI_DEV_ID_3 3
|
||||
|
||||
/* Interrupt mask */
|
||||
#define SPI_INTR_CMD_DONE 0x01
|
||||
#define SPI_INTR_RX_OVERFLOW 0x02
|
||||
#define SPI_INTR_TX_UNDERFLOW 0x04
|
||||
#define SPI_INTR_TX_OVERFLOW 0x08
|
||||
#define SPI_INTR_RX_UNDERFLOW 0x10
|
||||
#define SPI_INTR_CLEAR_ALL 0x1f
|
||||
|
||||
/* Status */
|
||||
#define SPI_RX_EMPTY 0x02
|
||||
#define SPI_CMD_BUSY 0x04
|
||||
#define SPI_SERIAL_BUSY 0x08
|
||||
|
||||
/* Clock configuration */
|
||||
#define SPI_CLK_20MHZ 0x00
|
||||
#define SPI_CLK_0_391MHZ 0x01
|
||||
#define SPI_CLK_0_781MHZ 0x02 /* default */
|
||||
#define SPI_CLK_1_563MHZ 0x03
|
||||
#define SPI_CLK_3_125MHZ 0x04
|
||||
#define SPI_CLK_6_250MHZ 0x05
|
||||
#define SPI_CLK_12_50MHZ 0x06
|
||||
#define SPI_CLK_MASK 0x07
|
||||
#define SPI_SSOFFTIME_MASK 0x38
|
||||
#define SPI_SSOFFTIME_SHIFT 3
|
||||
#define SPI_BYTE_SWAP 0x80
|
||||
|
||||
enum bcm63xx_regs_spi {
|
||||
SPI_CMD,
|
||||
SPI_INT_STATUS,
|
||||
SPI_INT_MASK_ST,
|
||||
SPI_INT_MASK,
|
||||
SPI_ST,
|
||||
SPI_CLK_CFG,
|
||||
SPI_FILL_BYTE,
|
||||
SPI_MSG_TAIL,
|
||||
SPI_RX_TAIL,
|
||||
SPI_MSG_CTL,
|
||||
SPI_MSG_DATA,
|
||||
SPI_RX_DATA,
|
||||
SPI_MSG_TYPE_SHIFT,
|
||||
SPI_MSG_CTL_WIDTH,
|
||||
SPI_MSG_DATA_SIZE,
|
||||
};
|
||||
|
||||
#define BCM63XX_SPI_MAX_PREPEND 15
|
||||
|
||||
#define BCM63XX_SPI_MAX_CS 8
|
||||
#define BCM63XX_SPI_BUS_NUM 0
|
||||
|
||||
struct bcm63xx_spi {
|
||||
struct completion done;
|
||||
|
||||
|
@ -38,6 +145,7 @@ struct bcm63xx_spi {
|
|||
int irq;
|
||||
|
||||
/* Platform data */
|
||||
const unsigned long *reg_offsets;
|
||||
unsigned fifo_size;
|
||||
unsigned int msg_type_shift;
|
||||
unsigned int msg_ctl_width;
|
||||
|
@ -51,27 +159,35 @@ struct bcm63xx_spi {
|
|||
};
|
||||
|
||||
static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs,
|
||||
unsigned int offset)
|
||||
unsigned int offset)
|
||||
{
|
||||
return bcm_readb(bs->regs + bcm63xx_spireg(offset));
|
||||
return readb(bs->regs + bs->reg_offsets[offset]);
|
||||
}
|
||||
|
||||
static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs,
|
||||
unsigned int offset)
|
||||
{
|
||||
return bcm_readw(bs->regs + bcm63xx_spireg(offset));
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
return ioread16be(bs->regs + bs->reg_offsets[offset]);
|
||||
#else
|
||||
return readw(bs->regs + bs->reg_offsets[offset]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void bcm_spi_writeb(struct bcm63xx_spi *bs,
|
||||
u8 value, unsigned int offset)
|
||||
{
|
||||
bcm_writeb(value, bs->regs + bcm63xx_spireg(offset));
|
||||
writeb(value, bs->regs + bs->reg_offsets[offset]);
|
||||
}
|
||||
|
||||
static inline void bcm_spi_writew(struct bcm63xx_spi *bs,
|
||||
u16 value, unsigned int offset)
|
||||
{
|
||||
bcm_writew(value, bs->regs + bcm63xx_spireg(offset));
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
iowrite16be(value, bs->regs + bs->reg_offsets[offset]);
|
||||
#else
|
||||
writew(value, bs->regs + bs->reg_offsets[offset]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
|
||||
|
@ -122,7 +238,6 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
|
|||
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;
|
||||
|
@ -314,18 +429,71 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const unsigned long bcm6348_spi_reg_offsets[] = {
|
||||
[SPI_CMD] = SPI_6348_CMD,
|
||||
[SPI_INT_STATUS] = SPI_6348_INT_STATUS,
|
||||
[SPI_INT_MASK_ST] = SPI_6348_INT_MASK_ST,
|
||||
[SPI_INT_MASK] = SPI_6348_INT_MASK,
|
||||
[SPI_ST] = SPI_6348_ST,
|
||||
[SPI_CLK_CFG] = SPI_6348_CLK_CFG,
|
||||
[SPI_FILL_BYTE] = SPI_6348_FILL_BYTE,
|
||||
[SPI_MSG_TAIL] = SPI_6348_MSG_TAIL,
|
||||
[SPI_RX_TAIL] = SPI_6348_RX_TAIL,
|
||||
[SPI_MSG_CTL] = SPI_6348_MSG_CTL,
|
||||
[SPI_MSG_DATA] = SPI_6348_MSG_DATA,
|
||||
[SPI_RX_DATA] = SPI_6348_RX_DATA,
|
||||
[SPI_MSG_TYPE_SHIFT] = SPI_6348_MSG_TYPE_SHIFT,
|
||||
[SPI_MSG_CTL_WIDTH] = SPI_6348_MSG_CTL_WIDTH,
|
||||
[SPI_MSG_DATA_SIZE] = SPI_6348_MSG_DATA_SIZE,
|
||||
};
|
||||
|
||||
static const unsigned long bcm6358_spi_reg_offsets[] = {
|
||||
[SPI_CMD] = SPI_6358_CMD,
|
||||
[SPI_INT_STATUS] = SPI_6358_INT_STATUS,
|
||||
[SPI_INT_MASK_ST] = SPI_6358_INT_MASK_ST,
|
||||
[SPI_INT_MASK] = SPI_6358_INT_MASK,
|
||||
[SPI_ST] = SPI_6358_ST,
|
||||
[SPI_CLK_CFG] = SPI_6358_CLK_CFG,
|
||||
[SPI_FILL_BYTE] = SPI_6358_FILL_BYTE,
|
||||
[SPI_MSG_TAIL] = SPI_6358_MSG_TAIL,
|
||||
[SPI_RX_TAIL] = SPI_6358_RX_TAIL,
|
||||
[SPI_MSG_CTL] = SPI_6358_MSG_CTL,
|
||||
[SPI_MSG_DATA] = SPI_6358_MSG_DATA,
|
||||
[SPI_RX_DATA] = SPI_6358_RX_DATA,
|
||||
[SPI_MSG_TYPE_SHIFT] = SPI_6358_MSG_TYPE_SHIFT,
|
||||
[SPI_MSG_CTL_WIDTH] = SPI_6358_MSG_CTL_WIDTH,
|
||||
[SPI_MSG_DATA_SIZE] = SPI_6358_MSG_DATA_SIZE,
|
||||
};
|
||||
|
||||
static const struct platform_device_id bcm63xx_spi_dev_match[] = {
|
||||
{
|
||||
.name = "bcm6348-spi",
|
||||
.driver_data = (unsigned long)bcm6348_spi_reg_offsets,
|
||||
},
|
||||
{
|
||||
.name = "bcm6358-spi",
|
||||
.driver_data = (unsigned long)bcm6358_spi_reg_offsets,
|
||||
},
|
||||
{
|
||||
},
|
||||
};
|
||||
|
||||
static int bcm63xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
const unsigned long *bcm63xx_spireg;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm63xx_spi_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
int irq;
|
||||
struct spi_master *master;
|
||||
struct clk *clk;
|
||||
struct bcm63xx_spi *bs;
|
||||
int ret;
|
||||
|
||||
if (!pdev->id_entry->driver_data)
|
||||
return -EINVAL;
|
||||
|
||||
bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "no irq\n");
|
||||
|
@ -359,7 +527,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
|||
|
||||
bs->irq = irq;
|
||||
bs->clk = clk;
|
||||
bs->fifo_size = pdata->fifo_size;
|
||||
bs->reg_offsets = bcm63xx_spireg;
|
||||
bs->fifo_size = bs->reg_offsets[SPI_MSG_DATA_SIZE];
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0,
|
||||
pdev->name, master);
|
||||
|
@ -368,26 +537,16 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
master->bus_num = pdata->bus_num;
|
||||
master->num_chipselect = pdata->num_chipselect;
|
||||
master->bus_num = BCM63XX_SPI_BUS_NUM;
|
||||
master->num_chipselect = BCM63XX_SPI_MAX_CS;
|
||||
master->transfer_one_message = bcm63xx_spi_transfer_one;
|
||||
master->mode_bits = MODEBITS;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||
master->auto_runtime_pm = true;
|
||||
bs->msg_type_shift = pdata->msg_type_shift;
|
||||
bs->msg_ctl_width = pdata->msg_ctl_width;
|
||||
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
|
||||
bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
|
||||
|
||||
switch (bs->msg_ctl_width) {
|
||||
case 8:
|
||||
case 16:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported MSG_CTL width: %d\n",
|
||||
bs->msg_ctl_width);
|
||||
goto out_err;
|
||||
}
|
||||
bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
|
||||
bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
|
||||
bs->tx_io = (u8 *)(bs->regs + bs->reg_offsets[SPI_MSG_DATA]);
|
||||
bs->rx_io = (const u8 *)(bs->regs + bs->reg_offsets[SPI_RX_DATA]);
|
||||
|
||||
/* Initialize hardware */
|
||||
ret = clk_prepare_enable(bs->clk);
|
||||
|
@ -467,6 +626,7 @@ static struct platform_driver bcm63xx_spi_driver = {
|
|||
.name = "bcm63xx-spi",
|
||||
.pm = &bcm63xx_spi_pm_ops,
|
||||
},
|
||||
.id_table = bcm63xx_spi_dev_match,
|
||||
.probe = bcm63xx_spi_probe,
|
||||
.remove = bcm63xx_spi_remove,
|
||||
};
|
||||
|
|
|
@ -352,10 +352,7 @@ bfin_sport_spi_pump_transfers(unsigned long data)
|
|||
transfer = drv_data->cur_transfer;
|
||||
chip = drv_data->cur_chip;
|
||||
|
||||
if (transfer->speed_hz)
|
||||
transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz);
|
||||
else
|
||||
transfer_speed = chip->baud;
|
||||
transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz);
|
||||
bfin_write(&drv_data->regs->tclkdiv, transfer_speed);
|
||||
SSYNC();
|
||||
|
||||
|
|
|
@ -661,11 +661,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
|
|||
message->state = RUNNING_STATE;
|
||||
dma_config = 0;
|
||||
|
||||
/* Speed setup (surely valid because already checked) */
|
||||
if (transfer->speed_hz)
|
||||
bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz));
|
||||
else
|
||||
bfin_write(&drv_data->regs->baud, chip->baud);
|
||||
bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz));
|
||||
|
||||
bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
|
||||
bfin_spi_cs_active(drv_data, chip);
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_bitbang.h>
|
||||
|
||||
#define SPI_BITBANG_CS_DELAY 100
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
|
@ -180,7 +182,6 @@ int spi_bitbang_setup(struct spi_device *spi)
|
|||
{
|
||||
struct spi_bitbang_cs *cs = spi->controller_state;
|
||||
struct spi_bitbang *bitbang;
|
||||
unsigned long flags;
|
||||
|
||||
bitbang = spi_master_get_devdata(spi->master);
|
||||
|
||||
|
@ -210,12 +211,12 @@ int spi_bitbang_setup(struct spi_device *spi)
|
|||
*/
|
||||
|
||||
/* deselect chip (low or high) */
|
||||
spin_lock_irqsave(&bitbang->lock, flags);
|
||||
mutex_lock(&bitbang->lock);
|
||||
if (!bitbang->busy) {
|
||||
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
|
||||
ndelay(cs->nsecs);
|
||||
}
|
||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
||||
mutex_unlock(&bitbang->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -255,122 +256,39 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
|
|||
static int spi_bitbang_prepare_hardware(struct spi_master *spi)
|
||||
{
|
||||
struct spi_bitbang *bitbang;
|
||||
unsigned long flags;
|
||||
|
||||
bitbang = spi_master_get_devdata(spi);
|
||||
|
||||
spin_lock_irqsave(&bitbang->lock, flags);
|
||||
mutex_lock(&bitbang->lock);
|
||||
bitbang->busy = 1;
|
||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
||||
mutex_unlock(&bitbang->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spi_bitbang_transfer_one(struct spi_master *master,
|
||||
struct spi_message *m)
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *transfer)
|
||||
{
|
||||
struct spi_bitbang *bitbang;
|
||||
unsigned nsecs;
|
||||
struct spi_transfer *t = NULL;
|
||||
unsigned cs_change;
|
||||
int status;
|
||||
int do_setup = -1;
|
||||
struct spi_device *spi = m->spi;
|
||||
struct spi_bitbang *bitbang = spi_master_get_devdata(master);
|
||||
int status = 0;
|
||||
|
||||
bitbang = spi_master_get_devdata(master);
|
||||
if (bitbang->setup_transfer) {
|
||||
status = bitbang->setup_transfer(spi, transfer);
|
||||
if (status < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* FIXME this is made-up ... the correct value is known to
|
||||
* word-at-a-time bitbang code, and presumably chipselect()
|
||||
* should enforce these requirements too?
|
||||
*/
|
||||
nsecs = 100;
|
||||
if (transfer->len)
|
||||
status = bitbang->txrx_bufs(spi, transfer);
|
||||
|
||||
cs_change = 1;
|
||||
status = 0;
|
||||
|
||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||
|
||||
/* override speed or wordsize? */
|
||||
if (t->speed_hz || t->bits_per_word)
|
||||
do_setup = 1;
|
||||
|
||||
/* init (-1) or override (1) transfer params */
|
||||
if (do_setup != 0) {
|
||||
if (bitbang->setup_transfer) {
|
||||
status = bitbang->setup_transfer(spi, t);
|
||||
if (status < 0)
|
||||
break;
|
||||
}
|
||||
if (do_setup == -1)
|
||||
do_setup = 0;
|
||||
}
|
||||
|
||||
/* set up default clock polarity, and activate chip;
|
||||
* this implicitly updates clock and spi modes as
|
||||
* previously recorded for this device via setup().
|
||||
* (and also deselects any other chip that might be
|
||||
* selected ...)
|
||||
*/
|
||||
if (cs_change) {
|
||||
bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
|
||||
ndelay(nsecs);
|
||||
}
|
||||
cs_change = t->cs_change;
|
||||
if (!t->tx_buf && !t->rx_buf && t->len) {
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* transfer data. the lower level code handles any
|
||||
* new dma mappings it needs. our caller always gave
|
||||
* us dma-safe buffers.
|
||||
*/
|
||||
if (t->len) {
|
||||
/* REVISIT dma API still needs a designated
|
||||
* DMA_ADDR_INVALID; ~0 might be better.
|
||||
*/
|
||||
if (!m->is_dma_mapped)
|
||||
t->rx_dma = t->tx_dma = 0;
|
||||
status = bitbang->txrx_bufs(spi, t);
|
||||
}
|
||||
if (status > 0)
|
||||
m->actual_length += status;
|
||||
if (status != t->len) {
|
||||
/* always report some kind of error */
|
||||
if (status >= 0)
|
||||
status = -EREMOTEIO;
|
||||
break;
|
||||
}
|
||||
if (status == transfer->len)
|
||||
status = 0;
|
||||
else if (status >= 0)
|
||||
status = -EREMOTEIO;
|
||||
|
||||
/* protocol tweaks before next transfer */
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
|
||||
if (cs_change &&
|
||||
!list_is_last(&t->transfer_list, &m->transfers)) {
|
||||
/* sometimes a short mid-message deselect of the chip
|
||||
* may be needed to terminate a mode or command
|
||||
*/
|
||||
ndelay(nsecs);
|
||||
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
|
||||
ndelay(nsecs);
|
||||
}
|
||||
}
|
||||
|
||||
m->status = status;
|
||||
|
||||
/* normally deactivate chipselect ... unless no error and
|
||||
* cs_change has hinted that the next message will probably
|
||||
* be for this chip too.
|
||||
*/
|
||||
if (!(status == 0 && cs_change)) {
|
||||
ndelay(nsecs);
|
||||
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
|
||||
ndelay(nsecs);
|
||||
}
|
||||
|
||||
spi_finalize_current_message(master);
|
||||
out:
|
||||
spi_finalize_current_transfer(master);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -378,17 +296,32 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
|
|||
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);
|
||||
mutex_lock(&bitbang->lock);
|
||||
bitbang->busy = 0;
|
||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
||||
mutex_unlock(&bitbang->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spi_bitbang_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master);
|
||||
|
||||
/* SPI core provides CS high / low, but bitbang driver
|
||||
* expects CS active
|
||||
* spi device driver takes care of handling SPI_CS_HIGH
|
||||
*/
|
||||
enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
|
||||
|
||||
ndelay(SPI_BITBANG_CS_DELAY);
|
||||
bitbang->chipselect(spi, enable ? BITBANG_CS_ACTIVE :
|
||||
BITBANG_CS_INACTIVE);
|
||||
ndelay(SPI_BITBANG_CS_DELAY);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
|
@ -427,7 +360,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
|
|||
if (!master || !bitbang->chipselect)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_init(&bitbang->lock);
|
||||
mutex_init(&bitbang->lock);
|
||||
|
||||
if (!master->mode_bits)
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
|
||||
|
@ -437,7 +370,8 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
|
|||
|
||||
master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
|
||||
master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
|
||||
master->transfer_one_message = spi_bitbang_transfer_one;
|
||||
master->transfer_one = spi_bitbang_transfer_one;
|
||||
master->set_cs = spi_bitbang_set_cs;
|
||||
|
||||
if (!bitbang->txrx_bufs) {
|
||||
bitbang->use_dma = 0;
|
||||
|
|
|
@ -210,12 +210,12 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
|
|||
if (in_8(&hw->regs->cdm) != cdm)
|
||||
out_8(&hw->regs->cdm, cdm);
|
||||
|
||||
spin_lock(&hw->bitbang.lock);
|
||||
mutex_lock(&hw->bitbang.lock);
|
||||
if (!hw->bitbang.busy) {
|
||||
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
|
||||
/* Need to ndelay here? */
|
||||
}
|
||||
spin_unlock(&hw->bitbang.lock);
|
||||
mutex_unlock(&hw->bitbang.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -198,12 +198,12 @@ static int s3c24xx_spi_setup(struct spi_device *spi)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock(&hw->bitbang.lock);
|
||||
mutex_lock(&hw->bitbang.lock);
|
||||
if (!hw->bitbang.busy) {
|
||||
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
|
||||
/* need to ndelay for 0.5 clocktick ? */
|
||||
}
|
||||
spin_unlock(&hw->bitbang.lock);
|
||||
mutex_unlock(&hw->bitbang.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
|
||||
struct spi_bitbang {
|
||||
spinlock_t lock;
|
||||
struct mutex lock;
|
||||
u8 busy;
|
||||
u8 use_dma;
|
||||
u8 flags; /* extra spi->mode support */
|
||||
|
|
Loading…
Reference in New Issue