1 // SPDX-License-Identifier: GPL-2.0+
3 * FB driver for the TLS8204 LCD Controller
5 * The display is monochrome and the video memory is RGB565.
6 * Any pixel value except 0 turns the pixel on.
8 * Copyright (C) 2013 Noralf Tronnes
9 * Copyright (C) 2014 Michael Hope (adapted for the TLS8204)
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/gpio/consumer.h>
16 #include <linux/spi/spi.h>
17 #include <linux/delay.h>
21 #define DRVNAME "fb_tls8204"
24 #define TXBUFLEN WIDTH
26 /* gamma is used to control contrast in this driver */
27 #define DEFAULT_GAMMA "40"
29 static unsigned int bs = 4;
30 module_param(bs, uint, 0000);
31 MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
33 static int init_display(struct fbtft_par *par)
35 par->fbtftops.reset(par);
37 /* Enter extended command mode */
38 write_reg(par, 0x21); /* 5:1 1
39 * 2:0 PD - Powerdown control: chip is active
40 * 1:0 V - Entry mode: horizontal addressing
41 * 0:1 H - Extended instruction set control:
46 write_reg(par, 0x10 | (bs & 0x7));
49 * 2:x BS2 - Bias System
54 /* Set the address of the first display line. */
55 write_reg(par, 0x04 | (64 >> 6));
56 write_reg(par, 0x40 | (64 & 0x3F));
58 /* Enter H=0 standard command mode */
61 /* H=0 Display control */
62 write_reg(par, 0x08 | 4);
64 * 2:1 D - DE: 10=normal mode
72 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
74 /* H=0 Set X address of RAM */
75 write_reg(par, 0x80); /* 7:1 1
79 /* H=0 Set Y address of RAM */
80 write_reg(par, 0x40); /* 7:0 0
86 static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
88 u16 *vmem16 = (u16 *)par->info->screen_buffer;
92 for (y = 0; y < HEIGHT / 8; y++) {
93 u8 *buf = par->txbuf.buf;
94 /* The display is 102x68 but the LCD is 84x48.
95 * Set the write pointer at the start of each row.
97 gpiod_set_value(par->gpio.dc, 0);
98 write_reg(par, 0x80 | 0);
99 write_reg(par, 0x40 | y);
101 for (x = 0; x < WIDTH; x++) {
104 for (i = 0; i < 8 * WIDTH; i += WIDTH) {
106 if (vmem16[(y * 8 * WIDTH) + i + x])
112 gpiod_set_value(par->gpio.dc, 1);
113 ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
115 dev_err(par->info->device,
116 "write failed and returned: %d\n", ret);
124 static int set_gamma(struct fbtft_par *par, u32 *curves)
129 write_reg(par, 0x21); /* turn on extended instruction set */
130 write_reg(par, 0x80 | curves[0]);
131 write_reg(par, 0x20); /* turn off extended instruction set */
136 static struct fbtft_display display = {
140 .txbuflen = TXBUFLEN,
143 .gamma = DEFAULT_GAMMA,
145 .init_display = init_display,
146 .set_addr_win = set_addr_win,
147 .write_vmem = write_vmem,
148 .set_gamma = set_gamma,
153 FBTFT_REGISTER_DRIVER(DRVNAME, "teralane,tls8204", &display);
155 MODULE_ALIAS("spi:" DRVNAME);
156 MODULE_ALIAS("spi:tls8204");
158 MODULE_DESCRIPTION("FB driver for the TLS8204 LCD Controller");
159 MODULE_AUTHOR("Michael Hope");
160 MODULE_LICENSE("GPL");