|
@@ -18,6 +18,7 @@
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/errno.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
+#include <linux/regmap.h>
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/io.h>
|
|
@@ -108,11 +109,11 @@ struct fsl_dspi {
|
|
|
struct spi_bitbang bitbang;
|
|
|
struct platform_device *pdev;
|
|
|
|
|
|
- void __iomem *base;
|
|
|
+ struct regmap *regmap;
|
|
|
int irq;
|
|
|
- struct clk *clk;
|
|
|
+ struct clk *clk;
|
|
|
|
|
|
- struct spi_transfer *cur_transfer;
|
|
|
+ struct spi_transfer *cur_transfer;
|
|
|
struct chip_data *cur_chip;
|
|
|
size_t len;
|
|
|
void *tx;
|
|
@@ -123,24 +124,17 @@ struct fsl_dspi {
|
|
|
u8 cs;
|
|
|
u16 void_write_data;
|
|
|
|
|
|
- wait_queue_head_t waitq;
|
|
|
- u32 waitflags;
|
|
|
+ wait_queue_head_t waitq;
|
|
|
+ u32 waitflags;
|
|
|
};
|
|
|
|
|
|
static inline int is_double_byte_mode(struct fsl_dspi *dspi)
|
|
|
{
|
|
|
- return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
|
|
|
- == SPI_FRAME_BITS(8)) ? 0 : 1;
|
|
|
-}
|
|
|
+ unsigned int val;
|
|
|
|
|
|
-static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
|
|
|
-{
|
|
|
- u32 temp;
|
|
|
+ regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
|
|
|
|
|
|
- temp = readl(dspi->base + SPI_CTAR(dspi->cs));
|
|
|
- temp &= ~SPI_FRAME_BITS_MASK;
|
|
|
- temp |= SPI_FRAME_BITS(bits);
|
|
|
- writel(temp, dspi->base + SPI_CTAR(dspi->cs));
|
|
|
+ return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
|
|
|
}
|
|
|
|
|
|
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
|
|
@@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
|
|
|
*/
|
|
|
if (tx_word && (dspi->len == 1)) {
|
|
|
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
|
|
|
- set_bit_mode(dspi, 8);
|
|
|
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
|
|
|
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
|
|
|
tx_word = 0;
|
|
|
}
|
|
|
|
|
@@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
|
|
|
dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
|
|
|
}
|
|
|
|
|
|
- writel(dspi_pushr, dspi->base + SPI_PUSHR);
|
|
|
+ regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
|
|
|
+
|
|
|
tx_count++;
|
|
|
}
|
|
|
|
|
@@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
|
|
|
while ((dspi->rx < dspi->rx_end)
|
|
|
&& (rx_count < DSPI_FIFO_SIZE)) {
|
|
|
if (rx_word) {
|
|
|
+ unsigned int val;
|
|
|
+
|
|
|
if ((dspi->rx_end - dspi->rx) == 1)
|
|
|
break;
|
|
|
|
|
|
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
|
|
|
+ regmap_read(dspi->regmap, SPI_POPR, &val);
|
|
|
+ d = SPI_POPR_RXDATA(val);
|
|
|
|
|
|
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
|
|
|
*(u16 *)dspi->rx = d;
|
|
|
dspi->rx += 2;
|
|
|
|
|
|
} else {
|
|
|
- d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
|
|
|
+ unsigned int val;
|
|
|
+
|
|
|
+ regmap_read(dspi->regmap, SPI_POPR, &val);
|
|
|
+ d = SPI_POPR_RXDATA(val);
|
|
|
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
|
|
|
*(u8 *)dspi->rx = d;
|
|
|
dspi->rx++;
|
|
@@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|
|
if (!dspi->tx)
|
|
|
dspi->dataflags |= TRAN_STATE_TX_VOID;
|
|
|
|
|
|
- writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
|
|
|
- writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
|
|
|
- writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
|
|
|
+ regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
|
|
|
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
|
|
|
+ regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
|
|
|
|
|
|
if (t->speed_hz)
|
|
|
- writel(dspi->cur_chip->ctar_val,
|
|
|
- dspi->base + SPI_CTAR(dspi->cs));
|
|
|
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
|
|
|
+ dspi->cur_chip->ctar_val);
|
|
|
|
|
|
dspi_transfer_write(dspi);
|
|
|
|
|
@@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|
|
static void dspi_chipselect(struct spi_device *spi, int value)
|
|
|
{
|
|
|
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
|
|
|
- u32 pushr = readl(dspi->base + SPI_PUSHR);
|
|
|
+ unsigned int pushr;
|
|
|
+
|
|
|
+ regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
|
|
|
|
|
|
switch (value) {
|
|
|
case BITBANG_CS_ACTIVE:
|
|
@@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- writel(pushr, dspi->base + SPI_PUSHR);
|
|
|
+ regmap_write(dspi->regmap, SPI_PUSHR, pushr);
|
|
|
}
|
|
|
|
|
|
static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|
@@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|
|
/* Only alloc on first setup */
|
|
|
chip = spi_get_ctldata(spi);
|
|
|
if (chip == NULL) {
|
|
|
- chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
|
|
|
+ chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
|
|
|
+ GFP_KERNEL);
|
|
|
if (!chip)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
@@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
|
|
fmsz = spi->bits_per_word - 1;
|
|
|
} else {
|
|
|
pr_err("Invalid wordsize\n");
|
|
|
- kfree(chip);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
@@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
|
|
|
{
|
|
|
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
|
|
|
|
|
|
- writel(SPI_SR_EOQF, dspi->base + SPI_SR);
|
|
|
+ regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
|
|
|
|
|
|
dspi_transfer_read(dspi);
|
|
|
|
|
|
if (!dspi->len) {
|
|
|
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
|
|
|
- set_bit_mode(dspi, 16);
|
|
|
+ regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
|
|
|
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
|
|
|
+
|
|
|
dspi->waitflags = 1;
|
|
|
wake_up_interruptible(&dspi->waitq);
|
|
|
} else {
|
|
@@ -430,8 +436,13 @@ static int dspi_resume(struct device *dev)
|
|
|
}
|
|
|
#endif /* CONFIG_PM_SLEEP */
|
|
|
|
|
|
-static const struct dev_pm_ops dspi_pm = {
|
|
|
- SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
|
|
|
+static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
|
|
|
+
|
|
|
+static struct regmap_config dspi_regmap_config = {
|
|
|
+ .reg_bits = 32,
|
|
|
+ .val_bits = 32,
|
|
|
+ .reg_stride = 4,
|
|
|
+ .max_register = 0x88,
|
|
|
};
|
|
|
|
|
|
static int dspi_probe(struct platform_device *pdev)
|
|
@@ -440,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev)
|
|
|
struct spi_master *master;
|
|
|
struct fsl_dspi *dspi;
|
|
|
struct resource *res;
|
|
|
+ void __iomem *base;
|
|
|
int ret = 0, cs_num, bus_num;
|
|
|
|
|
|
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
|
|
@@ -474,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev)
|
|
|
master->bus_num = bus_num;
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
- dspi->base = devm_ioremap_resource(&pdev->dev, res);
|
|
|
- if (IS_ERR(dspi->base)) {
|
|
|
- ret = PTR_ERR(dspi->base);
|
|
|
+ base = devm_ioremap_resource(&pdev->dev, res);
|
|
|
+ if (IS_ERR(base)) {
|
|
|
+ ret = PTR_ERR(base);
|
|
|
goto out_master_put;
|
|
|
}
|
|
|
|
|
|
+ dspi_regmap_config.lock_arg = dspi;
|
|
|
+ dspi_regmap_config.val_format_endian =
|
|
|
+ of_property_read_bool(np, "big-endian")
|
|
|
+ ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
|
|
|
+ dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
|
|
|
+ &dspi_regmap_config);
|
|
|
+ if (IS_ERR(dspi->regmap)) {
|
|
|
+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
|
|
|
+ PTR_ERR(dspi->regmap));
|
|
|
+ return PTR_ERR(dspi->regmap);
|
|
|
+ }
|
|
|
+
|
|
|
dspi->irq = platform_get_irq(pdev, 0);
|
|
|
if (dspi->irq < 0) {
|
|
|
dev_err(&pdev->dev, "can't get platform irq\n");
|