1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * FBTFT driver for the RA8875 LCD Controller
4 * Copyright by Pf@nne & NOTRO
5 */
6
7#include <linux/module.h>
8#include <linux/kernel.h>
9#include <linux/init.h>
10#include <linux/delay.h>
11
12#include <linux/gpio/consumer.h>
13#include "fbtft.h"
14
15#define DRVNAME "fb_ra8875"
16
17static int write_spi(struct fbtft_par *par, void *buf, size_t len)
18{
19	struct spi_transfer t = {
20		.tx_buf = buf,
21		.len = len,
22		.speed_hz = 1000000,
23	};
24	struct spi_message m;
25
26	fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
27			  "%s(len=%zu): ", __func__, len);
28
29	if (!par->spi) {
30		dev_err(par->info->device,
31			"%s: par->spi is unexpectedly NULL\n", __func__);
32		return -1;
33	}
34
35	spi_message_init(&m);
36	spi_message_add_tail(&t, &m);
37	return spi_sync(par->spi, &m);
38}
39
40static int init_display(struct fbtft_par *par)
41{
42	gpiod_set_value(par->gpio.dc, 1);
43
44	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
45		      "%s()\n", __func__);
46	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
47		      "display size %dx%d\n",
48		par->info->var.xres,
49		par->info->var.yres);
50
51	par->fbtftops.reset(par);
52
53	if ((par->info->var.xres == 320) && (par->info->var.yres == 240)) {
54		/* PLL clock frequency */
55		write_reg(par, 0x88, 0x0A);
56		write_reg(par, 0x89, 0x02);
57		mdelay(10);
58		/* color deep / MCU Interface */
59		write_reg(par, 0x10, 0x0C);
60		/* pixel clock period  */
61		write_reg(par, 0x04, 0x03);
62		mdelay(1);
63		/* horizontal settings */
64		write_reg(par, 0x14, 0x27);
65		write_reg(par, 0x15, 0x00);
66		write_reg(par, 0x16, 0x05);
67		write_reg(par, 0x17, 0x04);
68		write_reg(par, 0x18, 0x03);
69		/* vertical settings */
70		write_reg(par, 0x19, 0xEF);
71		write_reg(par, 0x1A, 0x00);
72		write_reg(par, 0x1B, 0x05);
73		write_reg(par, 0x1C, 0x00);
74		write_reg(par, 0x1D, 0x0E);
75		write_reg(par, 0x1E, 0x00);
76		write_reg(par, 0x1F, 0x02);
77	} else if ((par->info->var.xres == 480) &&
78		   (par->info->var.yres == 272)) {
79		/* PLL clock frequency  */
80		write_reg(par, 0x88, 0x0A);
81		write_reg(par, 0x89, 0x02);
82		mdelay(10);
83		/* color deep / MCU Interface */
84		write_reg(par, 0x10, 0x0C);
85		/* pixel clock period  */
86		write_reg(par, 0x04, 0x82);
87		mdelay(1);
88		/* horizontal settings */
89		write_reg(par, 0x14, 0x3B);
90		write_reg(par, 0x15, 0x00);
91		write_reg(par, 0x16, 0x01);
92		write_reg(par, 0x17, 0x00);
93		write_reg(par, 0x18, 0x05);
94		/* vertical settings */
95		write_reg(par, 0x19, 0x0F);
96		write_reg(par, 0x1A, 0x01);
97		write_reg(par, 0x1B, 0x02);
98		write_reg(par, 0x1C, 0x00);
99		write_reg(par, 0x1D, 0x07);
100		write_reg(par, 0x1E, 0x00);
101		write_reg(par, 0x1F, 0x09);
102	} else if ((par->info->var.xres == 640) &&
103		   (par->info->var.yres == 480)) {
104		/* PLL clock frequency */
105		write_reg(par, 0x88, 0x0B);
106		write_reg(par, 0x89, 0x02);
107		mdelay(10);
108		/* color deep / MCU Interface */
109		write_reg(par, 0x10, 0x0C);
110		/* pixel clock period */
111		write_reg(par, 0x04, 0x01);
112		mdelay(1);
113		/* horizontal settings */
114		write_reg(par, 0x14, 0x4F);
115		write_reg(par, 0x15, 0x05);
116		write_reg(par, 0x16, 0x0F);
117		write_reg(par, 0x17, 0x01);
118		write_reg(par, 0x18, 0x00);
119		/* vertical settings */
120		write_reg(par, 0x19, 0xDF);
121		write_reg(par, 0x1A, 0x01);
122		write_reg(par, 0x1B, 0x0A);
123		write_reg(par, 0x1C, 0x00);
124		write_reg(par, 0x1D, 0x0E);
125		write_reg(par, 0x1E, 0x00);
126		write_reg(par, 0x1F, 0x01);
127	} else if ((par->info->var.xres == 800) &&
128		   (par->info->var.yres == 480)) {
129		/* PLL clock frequency */
130		write_reg(par, 0x88, 0x0B);
131		write_reg(par, 0x89, 0x02);
132		mdelay(10);
133		/* color deep / MCU Interface */
134		write_reg(par, 0x10, 0x0C);
135		/* pixel clock period */
136		write_reg(par, 0x04, 0x81);
137		mdelay(1);
138		/* horizontal settings */
139		write_reg(par, 0x14, 0x63);
140		write_reg(par, 0x15, 0x03);
141		write_reg(par, 0x16, 0x03);
142		write_reg(par, 0x17, 0x02);
143		write_reg(par, 0x18, 0x00);
144		/* vertical settings */
145		write_reg(par, 0x19, 0xDF);
146		write_reg(par, 0x1A, 0x01);
147		write_reg(par, 0x1B, 0x14);
148		write_reg(par, 0x1C, 0x00);
149		write_reg(par, 0x1D, 0x06);
150		write_reg(par, 0x1E, 0x00);
151		write_reg(par, 0x1F, 0x01);
152	} else {
153		dev_err(par->info->device, "display size is not supported!!");
154		return -1;
155	}
156
157	/* PWM clock */
158	write_reg(par, 0x8a, 0x81);
159	write_reg(par, 0x8b, 0xFF);
160	mdelay(10);
161
162	/* Display ON */
163	write_reg(par, 0x01, 0x80);
164	mdelay(10);
165
166	return 0;
167}
168
169static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
170{
171	/* Set_Active_Window */
172	write_reg(par, 0x30, xs & 0x00FF);
173	write_reg(par, 0x31, (xs & 0xFF00) >> 8);
174	write_reg(par, 0x32, ys & 0x00FF);
175	write_reg(par, 0x33, (ys & 0xFF00) >> 8);
176	write_reg(par, 0x34, (xs + xe) & 0x00FF);
177	write_reg(par, 0x35, ((xs + xe) & 0xFF00) >> 8);
178	write_reg(par, 0x36, (ys + ye) & 0x00FF);
179	write_reg(par, 0x37, ((ys + ye) & 0xFF00) >> 8);
180
181	/* Set_Memory_Write_Cursor */
182	write_reg(par, 0x46,  xs & 0xff);
183	write_reg(par, 0x47, (xs >> 8) & 0x03);
184	write_reg(par, 0x48,  ys & 0xff);
185	write_reg(par, 0x49, (ys >> 8) & 0x01);
186
187	write_reg(par, 0x02);
188}
189
190static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
191{
192	va_list args;
193	int i, ret;
194	u8 *buf = par->buf;
195
196	/* slow down spi-speed for writing registers */
197	par->fbtftops.write = write_spi;
198
199	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
200		va_start(args, len);
201		for (i = 0; i < len; i++)
202			buf[i] = (u8)va_arg(args, unsigned int);
203		va_end(args);
204		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device,
205				  u8, buf, len, "%s: ", __func__);
206	}
207
208	va_start(args, len);
209	*buf++ = 0x80;
210	*buf = (u8)va_arg(args, unsigned int);
211	ret = par->fbtftops.write(par, par->buf, 2);
212	if (ret < 0) {
213		va_end(args);
214		dev_err(par->info->device, "write() failed and returned %dn",
215			ret);
216		return;
217	}
218	len--;
219
220	udelay(100);
221
222	if (len) {
223		buf = (u8 *)par->buf;
224		*buf++ = 0x00;
225		i = len;
226		while (i--)
227			*buf++ = (u8)va_arg(args, unsigned int);
228
229		ret = par->fbtftops.write(par, par->buf, len + 1);
230		if (ret < 0) {
231			va_end(args);
232			dev_err(par->info->device,
233				"write() failed and returned %dn", ret);
234			return;
235		}
236	}
237	va_end(args);
238
239	/* restore user spi-speed */
240	par->fbtftops.write = fbtft_write_spi;
241	udelay(100);
242}
243
244static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
245{
246	u16 *vmem16;
247	__be16 *txbuf16;
248	size_t remain;
249	size_t to_copy;
250	size_t tx_array_size;
251	int i;
252	int ret = 0;
253	size_t startbyte_size = 0;
254
255	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
256		      __func__, offset, len);
257
258	remain = len / 2;
259	vmem16 = (u16 *)(par->info->screen_buffer + offset);
260	tx_array_size = par->txbuf.len / 2;
261	txbuf16 = par->txbuf.buf + 1;
262	tx_array_size -= 2;
263	*(u8 *)(par->txbuf.buf) = 0x00;
264	startbyte_size = 1;
265
266	while (remain) {
267		to_copy = min(tx_array_size, remain);
268		dev_dbg(par->info->device, "    to_copy=%zu, remain=%zu\n",
269			to_copy, remain - to_copy);
270
271		for (i = 0; i < to_copy; i++)
272			txbuf16[i] = cpu_to_be16(vmem16[i]);
273
274		vmem16 = vmem16 + to_copy;
275		ret = par->fbtftops.write(par, par->txbuf.buf,
276			startbyte_size + to_copy * 2);
277		if (ret < 0)
278			return ret;
279		remain -= to_copy;
280	}
281
282	return ret;
283}
284
285static struct fbtft_display display = {
286	.regwidth = 8,
287	.fbtftops = {
288		.init_display = init_display,
289		.set_addr_win = set_addr_win,
290		.write_register = write_reg8_bus8,
291		.write_vmem = write_vmem16_bus8,
292		.write = write_spi,
293	},
294};
295
296FBTFT_REGISTER_DRIVER(DRVNAME, "raio,ra8875", &display);
297
298MODULE_ALIAS("spi:" DRVNAME);
299MODULE_ALIAS("platform:" DRVNAME);
300MODULE_ALIAS("spi:ra8875");
301MODULE_ALIAS("platform:ra8875");
302
303MODULE_DESCRIPTION("FB driver for the RA8875 LCD Controller");
304MODULE_AUTHOR("Pf@nne");
305MODULE_LICENSE("GPL");
306