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: &m);
36 spi_message_add_tail(t: &t, m: &m);
37 return spi_sync(spi: par->spi, message: &m);
38}
39
40static int init_display(struct fbtft_par *par)
41{
42 gpiod_set_value(desc: par->gpio.dc, value: 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

source code of linux/drivers/staging/fbtft/fb_ra8875.c