11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f7018c21STomi Valkeinen /*
3f7018c21STomi Valkeinen * linux/drivers/video/mmp/hw/mmp_spi.c
4f7018c21STomi Valkeinen * using the spi in LCD controler for commands send
5f7018c21STomi Valkeinen *
6f7018c21STomi Valkeinen * Copyright (C) 2012 Marvell Technology Group Ltd.
7f7018c21STomi Valkeinen * Authors: Guoqing Li <ligq@marvell.com>
8f7018c21STomi Valkeinen * Lisa Du <cldu@marvell.com>
9f7018c21STomi Valkeinen * Zhou Zhu <zzhu3@marvell.com>
10f7018c21STomi Valkeinen */
11f7018c21STomi Valkeinen #include <linux/errno.h>
12f7018c21STomi Valkeinen #include <linux/delay.h>
13f7018c21STomi Valkeinen #include <linux/err.h>
14f7018c21STomi Valkeinen #include <linux/io.h>
15f7018c21STomi Valkeinen #include <linux/spi/spi.h>
16f7018c21STomi Valkeinen #include "mmp_ctrl.h"
17f7018c21STomi Valkeinen
18f7018c21STomi Valkeinen /**
19f7018c21STomi Valkeinen * spi_write - write command to the SPI port
20031d039fSSam Ravnborg * @spi: the SPI device.
21f7018c21STomi Valkeinen * @data: can be 8/16/32-bit, MSB justified data to write.
22f7018c21STomi Valkeinen *
23f7018c21STomi Valkeinen * Wait bus transfer complete IRQ.
24f7018c21STomi Valkeinen * The caller is expected to perform the necessary locking.
25f7018c21STomi Valkeinen *
26f7018c21STomi Valkeinen * Returns:
27f7018c21STomi Valkeinen * %-ETIMEDOUT timeout occurred
28f7018c21STomi Valkeinen * 0 success
29f7018c21STomi Valkeinen */
lcd_spi_write(struct spi_device * spi,u32 data)30f7018c21STomi Valkeinen static inline int lcd_spi_write(struct spi_device *spi, u32 data)
31f7018c21STomi Valkeinen {
32f7018c21STomi Valkeinen int timeout = 100000, isr, ret = 0;
33f7018c21STomi Valkeinen u32 tmp;
34e41f6b17SBartlomiej Zolnierkiewicz void __iomem *reg_base = (void __iomem *)
35*b23031e7SUwe Kleine-König *(void **) spi_controller_get_devdata(spi->controller);
36f7018c21STomi Valkeinen
37f7018c21STomi Valkeinen /* clear ISR */
38f7018c21STomi Valkeinen writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
39f7018c21STomi Valkeinen
40f7018c21STomi Valkeinen switch (spi->bits_per_word) {
41f7018c21STomi Valkeinen case 8:
42f7018c21STomi Valkeinen writel_relaxed((u8)data, reg_base + LCD_SPU_SPI_TXDATA);
43f7018c21STomi Valkeinen break;
44f7018c21STomi Valkeinen case 16:
45f7018c21STomi Valkeinen writel_relaxed((u16)data, reg_base + LCD_SPU_SPI_TXDATA);
46f7018c21STomi Valkeinen break;
47f7018c21STomi Valkeinen case 32:
48f7018c21STomi Valkeinen writel_relaxed((u32)data, reg_base + LCD_SPU_SPI_TXDATA);
49f7018c21STomi Valkeinen break;
50f7018c21STomi Valkeinen default:
51f7018c21STomi Valkeinen dev_err(&spi->dev, "Wrong spi bit length\n");
52f7018c21STomi Valkeinen }
53f7018c21STomi Valkeinen
54f7018c21STomi Valkeinen /* SPI start to send command */
55f7018c21STomi Valkeinen tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
56f7018c21STomi Valkeinen tmp &= ~CFG_SPI_START_MASK;
57f7018c21STomi Valkeinen tmp |= CFG_SPI_START(1);
58f7018c21STomi Valkeinen writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
59f7018c21STomi Valkeinen
60f7018c21STomi Valkeinen isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
61f7018c21STomi Valkeinen while (!(isr & SPI_IRQ_ENA_MASK)) {
62f7018c21STomi Valkeinen udelay(100);
63f7018c21STomi Valkeinen isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
64f7018c21STomi Valkeinen if (!--timeout) {
65f7018c21STomi Valkeinen ret = -ETIMEDOUT;
66f7018c21STomi Valkeinen dev_err(&spi->dev, "spi cmd send time out\n");
67f7018c21STomi Valkeinen break;
68f7018c21STomi Valkeinen }
69f7018c21STomi Valkeinen }
70f7018c21STomi Valkeinen
71f7018c21STomi Valkeinen tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
72f7018c21STomi Valkeinen tmp &= ~CFG_SPI_START_MASK;
73f7018c21STomi Valkeinen tmp |= CFG_SPI_START(0);
74f7018c21STomi Valkeinen writel_relaxed(tmp, reg_base + LCD_SPU_SPI_CTRL);
75f7018c21STomi Valkeinen
76f7018c21STomi Valkeinen writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
77f7018c21STomi Valkeinen
78f7018c21STomi Valkeinen return ret;
79f7018c21STomi Valkeinen }
80f7018c21STomi Valkeinen
lcd_spi_setup(struct spi_device * spi)81f7018c21STomi Valkeinen static int lcd_spi_setup(struct spi_device *spi)
82f7018c21STomi Valkeinen {
83e41f6b17SBartlomiej Zolnierkiewicz void __iomem *reg_base = (void __iomem *)
84*b23031e7SUwe Kleine-König *(void **) spi_controller_get_devdata(spi->controller);
85f7018c21STomi Valkeinen u32 tmp;
86f7018c21STomi Valkeinen
87f7018c21STomi Valkeinen tmp = CFG_SCLKCNT(16) |
88f7018c21STomi Valkeinen CFG_TXBITS(spi->bits_per_word) |
89f7018c21STomi Valkeinen CFG_SPI_SEL(1) | CFG_SPI_ENA(1) |
90f7018c21STomi Valkeinen CFG_SPI_3W4WB(1);
91f7018c21STomi Valkeinen writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
92f7018c21STomi Valkeinen
93f7018c21STomi Valkeinen /*
94af1563f2SDario Binacchi * After set mode it needs some time to pull up the spi signals,
95f7018c21STomi Valkeinen * or it would cause the wrong waveform when send spi command,
96f7018c21STomi Valkeinen * especially on pxa910h
97f7018c21STomi Valkeinen */
98f7018c21STomi Valkeinen tmp = readl_relaxed(reg_base + SPU_IOPAD_CONTROL);
99f7018c21STomi Valkeinen if ((tmp & CFG_IOPADMODE_MASK) != IOPAD_DUMB18SPI)
100f7018c21STomi Valkeinen writel_relaxed(IOPAD_DUMB18SPI |
101f7018c21STomi Valkeinen (tmp & ~CFG_IOPADMODE_MASK),
102f7018c21STomi Valkeinen reg_base + SPU_IOPAD_CONTROL);
103f7018c21STomi Valkeinen udelay(20);
104f7018c21STomi Valkeinen return 0;
105f7018c21STomi Valkeinen }
106f7018c21STomi Valkeinen
lcd_spi_one_transfer(struct spi_device * spi,struct spi_message * m)107f7018c21STomi Valkeinen static int lcd_spi_one_transfer(struct spi_device *spi, struct spi_message *m)
108f7018c21STomi Valkeinen {
109f7018c21STomi Valkeinen struct spi_transfer *t;
110f7018c21STomi Valkeinen int i;
111f7018c21STomi Valkeinen
112f7018c21STomi Valkeinen list_for_each_entry(t, &m->transfers, transfer_list) {
113f7018c21STomi Valkeinen switch (spi->bits_per_word) {
114f7018c21STomi Valkeinen case 8:
115f7018c21STomi Valkeinen for (i = 0; i < t->len; i++)
116f7018c21STomi Valkeinen lcd_spi_write(spi, ((u8 *)t->tx_buf)[i]);
117f7018c21STomi Valkeinen break;
118f7018c21STomi Valkeinen case 16:
119f7018c21STomi Valkeinen for (i = 0; i < t->len/2; i++)
120f7018c21STomi Valkeinen lcd_spi_write(spi, ((u16 *)t->tx_buf)[i]);
121f7018c21STomi Valkeinen break;
122f7018c21STomi Valkeinen case 32:
123f7018c21STomi Valkeinen for (i = 0; i < t->len/4; i++)
124f7018c21STomi Valkeinen lcd_spi_write(spi, ((u32 *)t->tx_buf)[i]);
125f7018c21STomi Valkeinen break;
126f7018c21STomi Valkeinen default:
127f7018c21STomi Valkeinen dev_err(&spi->dev, "Wrong spi bit length\n");
128f7018c21STomi Valkeinen }
129f7018c21STomi Valkeinen }
130f7018c21STomi Valkeinen
131f7018c21STomi Valkeinen m->status = 0;
132f7018c21STomi Valkeinen if (m->complete)
133f7018c21STomi Valkeinen m->complete(m->context);
134f7018c21STomi Valkeinen return 0;
135f7018c21STomi Valkeinen }
136f7018c21STomi Valkeinen
lcd_spi_register(struct mmphw_ctrl * ctrl)137f7018c21STomi Valkeinen int lcd_spi_register(struct mmphw_ctrl *ctrl)
138f7018c21STomi Valkeinen {
139*b23031e7SUwe Kleine-König struct spi_controller *ctlr;
140f7018c21STomi Valkeinen void **p_regbase;
141f7018c21STomi Valkeinen int err;
142f7018c21STomi Valkeinen
143*b23031e7SUwe Kleine-König ctlr = spi_alloc_master(ctrl->dev, sizeof(void *));
144*b23031e7SUwe Kleine-König if (!ctlr) {
145f7018c21STomi Valkeinen dev_err(ctrl->dev, "unable to allocate SPI master\n");
146f7018c21STomi Valkeinen return -ENOMEM;
147f7018c21STomi Valkeinen }
148*b23031e7SUwe Kleine-König p_regbase = spi_controller_get_devdata(ctlr);
149e41f6b17SBartlomiej Zolnierkiewicz *p_regbase = (void __force *)ctrl->reg_base;
150f7018c21STomi Valkeinen
151f7018c21STomi Valkeinen /* set bus num to 5 to avoid conflict with other spi hosts */
152*b23031e7SUwe Kleine-König ctlr->bus_num = 5;
153*b23031e7SUwe Kleine-König ctlr->num_chipselect = 1;
154*b23031e7SUwe Kleine-König ctlr->setup = lcd_spi_setup;
155*b23031e7SUwe Kleine-König ctlr->transfer = lcd_spi_one_transfer;
156f7018c21STomi Valkeinen
157*b23031e7SUwe Kleine-König err = spi_register_controller(ctlr);
158f7018c21STomi Valkeinen if (err < 0) {
159f7018c21STomi Valkeinen dev_err(ctrl->dev, "unable to register SPI master\n");
160*b23031e7SUwe Kleine-König spi_controller_put(ctlr);
161f7018c21STomi Valkeinen return err;
162f7018c21STomi Valkeinen }
163f7018c21STomi Valkeinen
164*b23031e7SUwe Kleine-König dev_info(&ctlr->dev, "registered\n");
165f7018c21STomi Valkeinen
166f7018c21STomi Valkeinen return 0;
167f7018c21STomi Valkeinen }
168