diff options
Diffstat (limited to 'drivers/spi/spi-bcm63xx.c')
-rw-r--r-- | drivers/spi/spi-bcm63xx.c | 214 |
1 files changed, 187 insertions, 27 deletions
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index e73e2b052..bf9a610e5 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -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); @@ -403,8 +562,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) goto out_clk_disable; } - dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n", - r->start, irq, bs->fifo_size); + dev_info(dev, "at %pr (irq %d, FIFOs size %d)\n", + r, irq, bs->fifo_size); return 0; @@ -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, }; |