// SPDX-License-Identifier: GPL-2.0-or-later /* * linux/drivers/video/mmp/hw/mmp_spi.c * using the spi in LCD controler for commands send * * Copyright (C) 2012 Marvell Technology Group Ltd. * Authors: Guoqing Li <ligq@marvell.com> * Lisa Du <cldu@marvell.com> * Zhou Zhu <zzhu3@marvell.com> */ #include <linux/errno.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include <linux/spi/spi.h> #include "mmp_ctrl.h" /** * spi_write - write command to the SPI port * @spi: the SPI device. * @data: can be 8/16/32-bit, MSB justified data to write. * * Wait bus transfer complete IRQ. * The caller is expected to perform the necessary locking. * * Returns: * %-ETIMEDOUT timeout occurred * 0 success */ static inline int lcd_spi_write(struct spi_device *spi, u32 data) { int timeout = 100000, isr, ret = 0; u32 tmp; void __iomem *reg_base = (void __iomem *) *(void **)spi_master_get_devdata(spi->master); /* clear ISR */ writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR); switch (spi->bits_per_word) { case 8: writel_relaxed((u8)data, reg_base + LCD_SPU_SPI_TXDATA); break; case 16: writel_relaxed((u16)data, reg_base + LCD_SPU_SPI_TXDATA); break; case 32: writel_relaxed((u32)data, reg_base + LCD_SPU_SPI_TXDATA); break; default: dev_err(&spi->dev, "Wrong spi bit length\n"); } /* SPI start to send command */ tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL); tmp &= ~CFG_SPI_START_MASK; tmp |= CFG_SPI_START(1); writel(tmp, reg_base + LCD_SPU_SPI_CTRL); isr = readl_relaxed(reg_base + SPU_IRQ_ISR); while (!(isr & SPI_IRQ_ENA_MASK)) { udelay(100); isr = readl_relaxed(reg_base + SPU_IRQ_ISR); if (!--timeout) { ret = -ETIMEDOUT; dev_err(&spi->dev, "spi cmd send time out\n"); break; } } tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL); tmp &= ~CFG_SPI_START_MASK; tmp |= CFG_SPI_START(0); writel_relaxed(tmp, reg_base + LCD_SPU_SPI_CTRL); writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR); return ret; } static int lcd_spi_setup(struct spi_device *spi) { void __iomem *reg_base = (void __iomem *) *(void **)spi_master_get_devdata(spi->master); u32 tmp; tmp = CFG_SCLKCNT(16) | CFG_TXBITS(spi->bits_per_word) | CFG_SPI_SEL(1) | CFG_SPI_ENA(1) | CFG_SPI_3W4WB(1); writel(tmp, reg_base + LCD_SPU_SPI_CTRL); /* * After set mode it need a time to pull up the spi singals, * or it would cause the wrong waveform when send spi command, * especially on pxa910h */ tmp = readl_relaxed(reg_base + SPU_IOPAD_CONTROL); if ((tmp & CFG_IOPADMODE_MASK) != IOPAD_DUMB18SPI) writel_relaxed(IOPAD_DUMB18SPI | (tmp & ~CFG_IOPADMODE_MASK), reg_base + SPU_IOPAD_CONTROL); udelay(20); return 0; } static int lcd_spi_one_transfer(struct spi_device *spi, struct spi_message *m) { struct spi_transfer *t; int i; list_for_each_entry(t, &m->transfers, transfer_list) { switch (spi->bits_per_word) { case 8: for (i = 0; i < t->len; i++) lcd_spi_write(spi, ((u8 *)t->tx_buf)[i]); break; case 16: for (i = 0; i < t->len/2; i++) lcd_spi_write(spi, ((u16 *)t->tx_buf)[i]); break; case 32: for (i = 0; i < t->len/4; i++) lcd_spi_write(spi, ((u32 *)t->tx_buf)[i]); break; default: dev_err(&spi->dev, "Wrong spi bit length\n"); } } m->status = 0; if (m->complete) m->complete(m->context); return 0; } int lcd_spi_register(struct mmphw_ctrl *ctrl) { struct spi_master *master; void **p_regbase; int err; master = spi_alloc_master(ctrl->dev, sizeof(void *)); if (!master) { dev_err(ctrl->dev, "unable to allocate SPI master\n"); return -ENOMEM; } p_regbase = spi_master_get_devdata(master); *p_regbase = (void __force *)ctrl->reg_base; /* set bus num to 5 to avoid conflict with other spi hosts */ master->bus_num = 5; master->num_chipselect = 1; master->setup = lcd_spi_setup; master->transfer = lcd_spi_one_transfer; err = spi_register_master(master); if (err < 0) { dev_err(ctrl->dev, "unable to register SPI master\n"); spi_master_put(master); return err; } dev_info(&master->dev, "registered\n"); return 0; }