11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2641b4b1bSZhou Zhu /* 3641b4b1bSZhou Zhu * linux/drivers/video/mmp/hw/mmp_spi.c 4641b4b1bSZhou Zhu * using the spi in LCD controler for commands send 5641b4b1bSZhou Zhu * 6641b4b1bSZhou Zhu * Copyright (C) 2012 Marvell Technology Group Ltd. 7641b4b1bSZhou Zhu * Authors: Guoqing Li <ligq@marvell.com> 8641b4b1bSZhou Zhu * Lisa Du <cldu@marvell.com> 9641b4b1bSZhou Zhu * Zhou Zhu <zzhu3@marvell.com> 10641b4b1bSZhou Zhu */ 11641b4b1bSZhou Zhu #include <linux/errno.h> 12641b4b1bSZhou Zhu #include <linux/delay.h> 13641b4b1bSZhou Zhu #include <linux/err.h> 14641b4b1bSZhou Zhu #include <linux/io.h> 15641b4b1bSZhou Zhu #include <linux/spi/spi.h> 16641b4b1bSZhou Zhu #include "mmp_ctrl.h" 17641b4b1bSZhou Zhu 18641b4b1bSZhou Zhu /** 19641b4b1bSZhou Zhu * spi_write - write command to the SPI port 20*031d039fSSam Ravnborg * @spi: the SPI device. 21641b4b1bSZhou Zhu * @data: can be 8/16/32-bit, MSB justified data to write. 22641b4b1bSZhou Zhu * 23641b4b1bSZhou Zhu * Wait bus transfer complete IRQ. 24641b4b1bSZhou Zhu * The caller is expected to perform the necessary locking. 25641b4b1bSZhou Zhu * 26641b4b1bSZhou Zhu * Returns: 27641b4b1bSZhou Zhu * %-ETIMEDOUT timeout occurred 28641b4b1bSZhou Zhu * 0 success 29641b4b1bSZhou Zhu */ 30641b4b1bSZhou Zhu static inline int lcd_spi_write(struct spi_device *spi, u32 data) 31641b4b1bSZhou Zhu { 32641b4b1bSZhou Zhu int timeout = 100000, isr, ret = 0; 33641b4b1bSZhou Zhu u32 tmp; 34e41f6b17SBartlomiej Zolnierkiewicz void __iomem *reg_base = (void __iomem *) 35641b4b1bSZhou Zhu *(void **)spi_master_get_devdata(spi->master); 36641b4b1bSZhou Zhu 37641b4b1bSZhou Zhu /* clear ISR */ 38641b4b1bSZhou Zhu writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR); 39641b4b1bSZhou Zhu 40641b4b1bSZhou Zhu switch (spi->bits_per_word) { 41641b4b1bSZhou Zhu case 8: 42641b4b1bSZhou Zhu writel_relaxed((u8)data, reg_base + LCD_SPU_SPI_TXDATA); 43641b4b1bSZhou Zhu break; 44641b4b1bSZhou Zhu case 16: 45641b4b1bSZhou Zhu writel_relaxed((u16)data, reg_base + LCD_SPU_SPI_TXDATA); 46641b4b1bSZhou Zhu break; 47641b4b1bSZhou Zhu case 32: 48641b4b1bSZhou Zhu writel_relaxed((u32)data, reg_base + LCD_SPU_SPI_TXDATA); 49641b4b1bSZhou Zhu break; 50641b4b1bSZhou Zhu default: 51641b4b1bSZhou Zhu dev_err(&spi->dev, "Wrong spi bit length\n"); 52641b4b1bSZhou Zhu } 53641b4b1bSZhou Zhu 54641b4b1bSZhou Zhu /* SPI start to send command */ 55641b4b1bSZhou Zhu tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL); 56641b4b1bSZhou Zhu tmp &= ~CFG_SPI_START_MASK; 57641b4b1bSZhou Zhu tmp |= CFG_SPI_START(1); 58641b4b1bSZhou Zhu writel(tmp, reg_base + LCD_SPU_SPI_CTRL); 59641b4b1bSZhou Zhu 60641b4b1bSZhou Zhu isr = readl_relaxed(reg_base + SPU_IRQ_ISR); 61641b4b1bSZhou Zhu while (!(isr & SPI_IRQ_ENA_MASK)) { 62641b4b1bSZhou Zhu udelay(100); 63641b4b1bSZhou Zhu isr = readl_relaxed(reg_base + SPU_IRQ_ISR); 64641b4b1bSZhou Zhu if (!--timeout) { 65641b4b1bSZhou Zhu ret = -ETIMEDOUT; 66641b4b1bSZhou Zhu dev_err(&spi->dev, "spi cmd send time out\n"); 67641b4b1bSZhou Zhu break; 68641b4b1bSZhou Zhu } 69641b4b1bSZhou Zhu } 70641b4b1bSZhou Zhu 71641b4b1bSZhou Zhu tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL); 72641b4b1bSZhou Zhu tmp &= ~CFG_SPI_START_MASK; 73641b4b1bSZhou Zhu tmp |= CFG_SPI_START(0); 74641b4b1bSZhou Zhu writel_relaxed(tmp, reg_base + LCD_SPU_SPI_CTRL); 75641b4b1bSZhou Zhu 76641b4b1bSZhou Zhu writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR); 77641b4b1bSZhou Zhu 78641b4b1bSZhou Zhu return ret; 79641b4b1bSZhou Zhu } 80641b4b1bSZhou Zhu 81641b4b1bSZhou Zhu static int lcd_spi_setup(struct spi_device *spi) 82641b4b1bSZhou Zhu { 83e41f6b17SBartlomiej Zolnierkiewicz void __iomem *reg_base = (void __iomem *) 84641b4b1bSZhou Zhu *(void **)spi_master_get_devdata(spi->master); 85641b4b1bSZhou Zhu u32 tmp; 86641b4b1bSZhou Zhu 87641b4b1bSZhou Zhu tmp = CFG_SCLKCNT(16) | 88641b4b1bSZhou Zhu CFG_TXBITS(spi->bits_per_word) | 89641b4b1bSZhou Zhu CFG_SPI_SEL(1) | CFG_SPI_ENA(1) | 90641b4b1bSZhou Zhu CFG_SPI_3W4WB(1); 91641b4b1bSZhou Zhu writel(tmp, reg_base + LCD_SPU_SPI_CTRL); 92641b4b1bSZhou Zhu 93641b4b1bSZhou Zhu /* 94641b4b1bSZhou Zhu * After set mode it need a time to pull up the spi singals, 95641b4b1bSZhou Zhu * or it would cause the wrong waveform when send spi command, 96641b4b1bSZhou Zhu * especially on pxa910h 97641b4b1bSZhou Zhu */ 98641b4b1bSZhou Zhu tmp = readl_relaxed(reg_base + SPU_IOPAD_CONTROL); 99641b4b1bSZhou Zhu if ((tmp & CFG_IOPADMODE_MASK) != IOPAD_DUMB18SPI) 100641b4b1bSZhou Zhu writel_relaxed(IOPAD_DUMB18SPI | 101641b4b1bSZhou Zhu (tmp & ~CFG_IOPADMODE_MASK), 102641b4b1bSZhou Zhu reg_base + SPU_IOPAD_CONTROL); 103641b4b1bSZhou Zhu udelay(20); 104641b4b1bSZhou Zhu return 0; 105641b4b1bSZhou Zhu } 106641b4b1bSZhou Zhu 107641b4b1bSZhou Zhu static int lcd_spi_one_transfer(struct spi_device *spi, struct spi_message *m) 108641b4b1bSZhou Zhu { 109641b4b1bSZhou Zhu struct spi_transfer *t; 110641b4b1bSZhou Zhu int i; 111641b4b1bSZhou Zhu 112641b4b1bSZhou Zhu list_for_each_entry(t, &m->transfers, transfer_list) { 113641b4b1bSZhou Zhu switch (spi->bits_per_word) { 114641b4b1bSZhou Zhu case 8: 115641b4b1bSZhou Zhu for (i = 0; i < t->len; i++) 116641b4b1bSZhou Zhu lcd_spi_write(spi, ((u8 *)t->tx_buf)[i]); 117641b4b1bSZhou Zhu break; 118641b4b1bSZhou Zhu case 16: 119641b4b1bSZhou Zhu for (i = 0; i < t->len/2; i++) 120641b4b1bSZhou Zhu lcd_spi_write(spi, ((u16 *)t->tx_buf)[i]); 121641b4b1bSZhou Zhu break; 122641b4b1bSZhou Zhu case 32: 123641b4b1bSZhou Zhu for (i = 0; i < t->len/4; i++) 124641b4b1bSZhou Zhu lcd_spi_write(spi, ((u32 *)t->tx_buf)[i]); 125641b4b1bSZhou Zhu break; 126641b4b1bSZhou Zhu default: 127641b4b1bSZhou Zhu dev_err(&spi->dev, "Wrong spi bit length\n"); 128641b4b1bSZhou Zhu } 129641b4b1bSZhou Zhu } 130641b4b1bSZhou Zhu 131641b4b1bSZhou Zhu m->status = 0; 132641b4b1bSZhou Zhu if (m->complete) 133641b4b1bSZhou Zhu m->complete(m->context); 134641b4b1bSZhou Zhu return 0; 135641b4b1bSZhou Zhu } 136641b4b1bSZhou Zhu 137641b4b1bSZhou Zhu int lcd_spi_register(struct mmphw_ctrl *ctrl) 138641b4b1bSZhou Zhu { 139641b4b1bSZhou Zhu struct spi_master *master; 140641b4b1bSZhou Zhu void **p_regbase; 141641b4b1bSZhou Zhu int err; 142641b4b1bSZhou Zhu 143641b4b1bSZhou Zhu master = spi_alloc_master(ctrl->dev, sizeof(void *)); 144641b4b1bSZhou Zhu if (!master) { 145641b4b1bSZhou Zhu dev_err(ctrl->dev, "unable to allocate SPI master\n"); 146641b4b1bSZhou Zhu return -ENOMEM; 147641b4b1bSZhou Zhu } 148641b4b1bSZhou Zhu p_regbase = spi_master_get_devdata(master); 149e41f6b17SBartlomiej Zolnierkiewicz *p_regbase = (void __force *)ctrl->reg_base; 150641b4b1bSZhou Zhu 151641b4b1bSZhou Zhu /* set bus num to 5 to avoid conflict with other spi hosts */ 152641b4b1bSZhou Zhu master->bus_num = 5; 153641b4b1bSZhou Zhu master->num_chipselect = 1; 154641b4b1bSZhou Zhu master->setup = lcd_spi_setup; 155641b4b1bSZhou Zhu master->transfer = lcd_spi_one_transfer; 156641b4b1bSZhou Zhu 157641b4b1bSZhou Zhu err = spi_register_master(master); 158641b4b1bSZhou Zhu if (err < 0) { 159641b4b1bSZhou Zhu dev_err(ctrl->dev, "unable to register SPI master\n"); 160641b4b1bSZhou Zhu spi_master_put(master); 161641b4b1bSZhou Zhu return err; 162641b4b1bSZhou Zhu } 163641b4b1bSZhou Zhu 164641b4b1bSZhou Zhu dev_info(&master->dev, "registered\n"); 165641b4b1bSZhou Zhu 166641b4b1bSZhou Zhu return 0; 167641b4b1bSZhou Zhu } 168