xref: /linux/drivers/video/fbdev/mmp/hw/mmp_spi.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
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