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:
@@ -18,29 +18,6 @@
|
|||||||
#include <bcm63xx_dev_spi.h>
|
#include <bcm63xx_dev_spi.h>
|
||||||
#include <bcm63xx_regs.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[] = {
|
static struct resource spi_resources[] = {
|
||||||
{
|
{
|
||||||
.start = -1, /* filled at runtime */
|
.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 = {
|
static struct platform_device bcm63xx_spi_device = {
|
||||||
.name = "bcm63xx-spi",
|
|
||||||
.id = -1,
|
.id = -1,
|
||||||
.num_resources = ARRAY_SIZE(spi_resources),
|
.num_resources = ARRAY_SIZE(spi_resources),
|
||||||
.resource = spi_resources,
|
.resource = spi_resources,
|
||||||
.dev = {
|
|
||||||
.platform_data = &spi_pdata,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int __init bcm63xx_spi_register(void)
|
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);
|
spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
|
||||||
|
|
||||||
if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
|
if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
|
||||||
|
bcm63xx_spi_device.name = "bcm6348-spi",
|
||||||
spi_resources[0].end += BCM_6348_RSET_SPI_SIZE - 1;
|
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() ||
|
if (BCMCPU_IS_3368() || BCMCPU_IS_6358() || BCMCPU_IS_6362() ||
|
||||||
BCMCPU_IS_6368()) {
|
BCMCPU_IS_6368()) {
|
||||||
|
bcm63xx_spi_device.name = "bcm6358-spi",
|
||||||
spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
|
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);
|
return platform_device_register(&bcm63xx_spi_device);
|
||||||
}
|
}
|
||||||
|
@@ -7,48 +7,4 @@
|
|||||||
|
|
||||||
int __init bcm63xx_spi_register(void);
|
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 */
|
#endif /* BCM63XX_DEV_SPI_H */
|
||||||
|
@@ -136,7 +136,7 @@ config SPI_BCM53XX
|
|||||||
|
|
||||||
config SPI_BCM63XX
|
config SPI_BCM63XX
|
||||||
tristate "Broadcom BCM63xx SPI controller"
|
tristate "Broadcom BCM63xx SPI controller"
|
||||||
depends on BCM63XX
|
depends on BCM63XX || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
|
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) {
|
if (err) {
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
bcma_set_drvdata(core, NULL);
|
bcma_set_drvdata(core, NULL);
|
||||||
goto out;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
|
/* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
|
||||||
spi_new_device(master, &bcm53xx_info);
|
spi_new_device(master, &bcm53xx_info);
|
||||||
|
|
||||||
out:
|
return 0;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bcm53xxspi_bcma_remove(struct bcma_device *core)
|
|
||||||
{
|
|
||||||
struct bcm53xxspi *b53spi = bcma_get_drvdata(core);
|
|
||||||
|
|
||||||
spi_unregister_master(b53spi->master);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bcma_driver bcm53xxspi_bcma_driver = {
|
static struct bcma_driver bcm53xxspi_bcma_driver = {
|
||||||
.name = KBUILD_MODNAME,
|
.name = KBUILD_MODNAME,
|
||||||
.id_table = bcm53xxspi_bcma_tbl,
|
.id_table = bcm53xxspi_bcma_tbl,
|
||||||
.probe = bcm53xxspi_bcma_probe,
|
.probe = bcm53xxspi_bcma_probe,
|
||||||
.remove = bcm53xxspi_bcma_remove,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
|
@@ -27,10 +27,117 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/pm_runtime.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_PREPEND 15
|
||||||
|
|
||||||
|
#define BCM63XX_SPI_MAX_CS 8
|
||||||
|
#define BCM63XX_SPI_BUS_NUM 0
|
||||||
|
|
||||||
struct bcm63xx_spi {
|
struct bcm63xx_spi {
|
||||||
struct completion done;
|
struct completion done;
|
||||||
|
|
||||||
@@ -38,6 +145,7 @@ struct bcm63xx_spi {
|
|||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
/* Platform data */
|
/* Platform data */
|
||||||
|
const unsigned long *reg_offsets;
|
||||||
unsigned fifo_size;
|
unsigned fifo_size;
|
||||||
unsigned int msg_type_shift;
|
unsigned int msg_type_shift;
|
||||||
unsigned int msg_ctl_width;
|
unsigned int msg_ctl_width;
|
||||||
@@ -51,27 +159,35 @@ struct bcm63xx_spi {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs,
|
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,
|
static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs,
|
||||||
unsigned int offset)
|
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,
|
static inline void bcm_spi_writeb(struct bcm63xx_spi *bs,
|
||||||
u8 value, unsigned int offset)
|
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,
|
static inline void bcm_spi_writew(struct bcm63xx_spi *bs,
|
||||||
u16 value, unsigned int offset)
|
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] = {
|
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);
|
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
|
||||||
u16 msg_ctl;
|
u16 msg_ctl;
|
||||||
u16 cmd;
|
u16 cmd;
|
||||||
u8 rx_tail;
|
|
||||||
unsigned int i, timeout = 0, prepend_len = 0, len = 0;
|
unsigned int i, timeout = 0, prepend_len = 0, len = 0;
|
||||||
struct spi_transfer *t = first;
|
struct spi_transfer *t = first;
|
||||||
bool do_rx = false;
|
bool do_rx = false;
|
||||||
@@ -314,18 +429,71 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
|
|||||||
return IRQ_HANDLED;
|
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)
|
static int bcm63xx_spi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *r;
|
struct resource *r;
|
||||||
|
const unsigned long *bcm63xx_spireg;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct bcm63xx_spi_pdata *pdata = dev_get_platdata(&pdev->dev);
|
|
||||||
int irq;
|
int irq;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct bcm63xx_spi *bs;
|
struct bcm63xx_spi *bs;
|
||||||
int ret;
|
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);
|
irq = platform_get_irq(pdev, 0);
|
||||||
if (irq < 0) {
|
if (irq < 0) {
|
||||||
dev_err(dev, "no irq\n");
|
dev_err(dev, "no irq\n");
|
||||||
@@ -359,7 +527,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
bs->irq = irq;
|
bs->irq = irq;
|
||||||
bs->clk = clk;
|
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,
|
ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0,
|
||||||
pdev->name, master);
|
pdev->name, master);
|
||||||
@@ -368,26 +537,16 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
master->bus_num = pdata->bus_num;
|
master->bus_num = BCM63XX_SPI_BUS_NUM;
|
||||||
master->num_chipselect = pdata->num_chipselect;
|
master->num_chipselect = BCM63XX_SPI_MAX_CS;
|
||||||
master->transfer_one_message = bcm63xx_spi_transfer_one;
|
master->transfer_one_message = bcm63xx_spi_transfer_one;
|
||||||
master->mode_bits = MODEBITS;
|
master->mode_bits = MODEBITS;
|
||||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
master->auto_runtime_pm = true;
|
master->auto_runtime_pm = true;
|
||||||
bs->msg_type_shift = pdata->msg_type_shift;
|
bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
|
||||||
bs->msg_ctl_width = pdata->msg_ctl_width;
|
bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
|
||||||
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
|
bs->tx_io = (u8 *)(bs->regs + bs->reg_offsets[SPI_MSG_DATA]);
|
||||||
bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
|
bs->rx_io = (const u8 *)(bs->regs + bs->reg_offsets[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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize hardware */
|
/* Initialize hardware */
|
||||||
ret = clk_prepare_enable(bs->clk);
|
ret = clk_prepare_enable(bs->clk);
|
||||||
@@ -467,6 +626,7 @@ static struct platform_driver bcm63xx_spi_driver = {
|
|||||||
.name = "bcm63xx-spi",
|
.name = "bcm63xx-spi",
|
||||||
.pm = &bcm63xx_spi_pm_ops,
|
.pm = &bcm63xx_spi_pm_ops,
|
||||||
},
|
},
|
||||||
|
.id_table = bcm63xx_spi_dev_match,
|
||||||
.probe = bcm63xx_spi_probe,
|
.probe = bcm63xx_spi_probe,
|
||||||
.remove = bcm63xx_spi_remove,
|
.remove = bcm63xx_spi_remove,
|
||||||
};
|
};
|
||||||
|
@@ -352,10 +352,7 @@ bfin_sport_spi_pump_transfers(unsigned long data)
|
|||||||
transfer = drv_data->cur_transfer;
|
transfer = drv_data->cur_transfer;
|
||||||
chip = drv_data->cur_chip;
|
chip = drv_data->cur_chip;
|
||||||
|
|
||||||
if (transfer->speed_hz)
|
transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz);
|
||||||
transfer_speed = bfin_sport_hz_to_spi_baud(transfer->speed_hz);
|
|
||||||
else
|
|
||||||
transfer_speed = chip->baud;
|
|
||||||
bfin_write(&drv_data->regs->tclkdiv, transfer_speed);
|
bfin_write(&drv_data->regs->tclkdiv, transfer_speed);
|
||||||
SSYNC();
|
SSYNC();
|
||||||
|
|
||||||
|
@@ -661,11 +661,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
|
|||||||
message->state = RUNNING_STATE;
|
message->state = RUNNING_STATE;
|
||||||
dma_config = 0;
|
dma_config = 0;
|
||||||
|
|
||||||
/* Speed setup (surely valid because already checked) */
|
bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz));
|
||||||
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->stat, BIT_STAT_CLR);
|
bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
|
||||||
bfin_spi_cs_active(drv_data, chip);
|
bfin_spi_cs_active(drv_data, chip);
|
||||||
|
@@ -24,6 +24,8 @@
|
|||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/spi_bitbang.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_cs *cs = spi->controller_state;
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
bitbang = spi_master_get_devdata(spi->master);
|
bitbang = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
@@ -210,12 +211,12 @@ int spi_bitbang_setup(struct spi_device *spi)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* deselect chip (low or high) */
|
/* deselect chip (low or high) */
|
||||||
spin_lock_irqsave(&bitbang->lock, flags);
|
mutex_lock(&bitbang->lock);
|
||||||
if (!bitbang->busy) {
|
if (!bitbang->busy) {
|
||||||
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
|
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
|
||||||
ndelay(cs->nsecs);
|
ndelay(cs->nsecs);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
mutex_unlock(&bitbang->lock);
|
||||||
|
|
||||||
return 0;
|
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)
|
static int spi_bitbang_prepare_hardware(struct spi_master *spi)
|
||||||
{
|
{
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
bitbang = spi_master_get_devdata(spi);
|
bitbang = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
spin_lock_irqsave(&bitbang->lock, flags);
|
mutex_lock(&bitbang->lock);
|
||||||
bitbang->busy = 1;
|
bitbang->busy = 1;
|
||||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
mutex_unlock(&bitbang->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spi_bitbang_transfer_one(struct spi_master *master,
|
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;
|
struct spi_bitbang *bitbang = spi_master_get_devdata(master);
|
||||||
unsigned nsecs;
|
int status = 0;
|
||||||
struct spi_transfer *t = NULL;
|
|
||||||
unsigned cs_change;
|
|
||||||
int status;
|
|
||||||
int do_setup = -1;
|
|
||||||
struct spi_device *spi = m->spi;
|
|
||||||
|
|
||||||
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
|
if (transfer->len)
|
||||||
* word-at-a-time bitbang code, and presumably chipselect()
|
status = bitbang->txrx_bufs(spi, transfer);
|
||||||
* should enforce these requirements too?
|
|
||||||
*/
|
|
||||||
nsecs = 100;
|
|
||||||
|
|
||||||
cs_change = 1;
|
if (status == transfer->len)
|
||||||
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;
|
|
||||||
}
|
|
||||||
status = 0;
|
status = 0;
|
||||||
|
else if (status >= 0)
|
||||||
|
status = -EREMOTEIO;
|
||||||
|
|
||||||
/* protocol tweaks before next transfer */
|
out:
|
||||||
if (t->delay_usecs)
|
spi_finalize_current_transfer(master);
|
||||||
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);
|
|
||||||
|
|
||||||
return status;
|
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)
|
static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
|
||||||
{
|
{
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
bitbang = spi_master_get_devdata(spi);
|
bitbang = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
spin_lock_irqsave(&bitbang->lock, flags);
|
mutex_lock(&bitbang->lock);
|
||||||
bitbang->busy = 0;
|
bitbang->busy = 0;
|
||||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
mutex_unlock(&bitbang->lock);
|
||||||
|
|
||||||
return 0;
|
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)
|
if (!master || !bitbang->chipselect)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
spin_lock_init(&bitbang->lock);
|
mutex_init(&bitbang->lock);
|
||||||
|
|
||||||
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;
|
||||||
@@ -437,7 +370,8 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
|
|||||||
|
|
||||||
master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
|
master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
|
||||||
master->unprepare_transfer_hardware = spi_bitbang_unprepare_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) {
|
if (!bitbang->txrx_bufs) {
|
||||||
bitbang->use_dma = 0;
|
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)
|
if (in_8(&hw->regs->cdm) != cdm)
|
||||||
out_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) {
|
if (!hw->bitbang.busy) {
|
||||||
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
|
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
|
||||||
/* Need to ndelay here? */
|
/* Need to ndelay here? */
|
||||||
}
|
}
|
||||||
spin_unlock(&hw->bitbang.lock);
|
mutex_unlock(&hw->bitbang.lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -198,12 +198,12 @@ static int s3c24xx_spi_setup(struct spi_device *spi)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
spin_lock(&hw->bitbang.lock);
|
mutex_lock(&hw->bitbang.lock);
|
||||||
if (!hw->bitbang.busy) {
|
if (!hw->bitbang.busy) {
|
||||||
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
|
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
|
||||||
/* need to ndelay for 0.5 clocktick ? */
|
/* need to ndelay for 0.5 clocktick ? */
|
||||||
}
|
}
|
||||||
spin_unlock(&hw->bitbang.lock);
|
mutex_unlock(&hw->bitbang.lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
struct spi_bitbang {
|
struct spi_bitbang {
|
||||||
spinlock_t lock;
|
struct mutex lock;
|
||||||
u8 busy;
|
u8 busy;
|
||||||
u8 use_dma;
|
u8 use_dma;
|
||||||
u8 flags; /* extra spi->mode support */
|
u8 flags; /* extra spi->mode support */
|
||||||
|
Reference in New Issue
Block a user