]>
Commit | Line | Data |
---|---|---|
9518dbc0 TP |
1 | /* |
2 | * FB driver for the TLS8204 LCD Controller | |
3 | * | |
4 | * The display is monochrome and the video memory is RGB565. | |
5 | * Any pixel value except 0 turns the pixel on. | |
6 | * | |
7 | * Copyright (C) 2013 Noralf Tronnes | |
8 | * Copyright (C) 2014 Michael Hope (adapted for the TLS8204) | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
9518dbc0 TP |
19 | */ |
20 | ||
21 | #include <linux/module.h> | |
22 | #include <linux/kernel.h> | |
23 | #include <linux/init.h> | |
24 | #include <linux/gpio.h> | |
25 | #include <linux/spi/spi.h> | |
26 | #include <linux/delay.h> | |
27 | ||
28 | #include "fbtft.h" | |
29 | ||
30 | #define DRVNAME "fb_tls8204" | |
31 | #define WIDTH 84 | |
32 | #define HEIGHT 48 | |
33 | #define TXBUFLEN WIDTH | |
3c588452 AG |
34 | |
35 | /* gamma is used to control contrast in this driver */ | |
36 | #define DEFAULT_GAMMA "40" | |
9518dbc0 | 37 | |
1c41494a | 38 | static unsigned int bs = 4; |
9518dbc0 TP |
39 | module_param(bs, uint, 0); |
40 | MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)"); | |
41 | ||
42 | static int init_display(struct fbtft_par *par) | |
43 | { | |
9518dbc0 TP |
44 | par->fbtftops.reset(par); |
45 | ||
46 | /* Enter extended command mode */ | |
47 | write_reg(par, 0x21); /* 5:1 1 | |
48 | 2:0 PD - Powerdown control: chip is active | |
49 | 1:0 V - Entry mode: horizontal addressing | |
3c588452 AG |
50 | 0:1 H - Extended instruction set control: |
51 | extended | |
9518dbc0 TP |
52 | */ |
53 | ||
54 | /* H=1 Bias system */ | |
55 | write_reg(par, 0x10 | (bs & 0x7)); /* | |
56 | 4:1 1 | |
57 | 3:0 0 | |
58 | 2:x BS2 - Bias System | |
59 | 1:x BS1 | |
60 | 0:x BS0 | |
61 | */ | |
62 | ||
63 | /* Set the address of the first display line. */ | |
64 | write_reg(par, 0x04 | (64 >> 6)); | |
65 | write_reg(par, 0x40 | (64 & 0x3F)); | |
66 | ||
67 | /* Enter H=0 standard command mode */ | |
68 | write_reg(par, 0x20); | |
69 | ||
70 | /* H=0 Display control */ | |
71 | write_reg(par, 0x08 | 4); /* | |
72 | 3:1 1 | |
73 | 2:1 D - DE: 10=normal mode | |
74 | 1:0 0 | |
75 | 0:0 E | |
76 | */ | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
81 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) | |
82 | { | |
9518dbc0 TP |
83 | /* H=0 Set X address of RAM */ |
84 | write_reg(par, 0x80); /* 7:1 1 | |
85 | 6-0: X[6:0] - 0x00 | |
86 | */ | |
87 | ||
88 | /* H=0 Set Y address of RAM */ | |
89 | write_reg(par, 0x40); /* 7:0 0 | |
90 | 6:1 1 | |
91 | 2-0: Y[2:0] - 0x0 | |
92 | */ | |
93 | } | |
94 | ||
95 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) | |
96 | { | |
4b6dc179 | 97 | u16 *vmem16 = (u16 *)par->info->screen_buffer; |
9518dbc0 TP |
98 | int x, y, i; |
99 | int ret = 0; | |
100 | ||
94c0a544 | 101 | for (y = 0; y < HEIGHT / 8; y++) { |
9518dbc0 TP |
102 | u8 *buf = par->txbuf.buf; |
103 | /* The display is 102x68 but the LCD is 84x48. Set | |
104 | the write pointer at the start of each row. */ | |
105 | gpio_set_value(par->gpio.dc, 0); | |
106 | write_reg(par, 0x80 | 0); | |
107 | write_reg(par, 0x40 | y); | |
108 | ||
109 | for (x = 0; x < WIDTH; x++) { | |
110 | u8 ch = 0; | |
a94ac159 | 111 | |
94c0a544 | 112 | for (i = 0; i < 8 * WIDTH; i += WIDTH) { |
9518dbc0 | 113 | ch >>= 1; |
94c0a544 | 114 | if (vmem16[(y * 8 * WIDTH) + i + x]) |
9518dbc0 TP |
115 | ch |= 0x80; |
116 | } | |
117 | *buf++ = ch; | |
118 | } | |
119 | /* Write the row */ | |
120 | gpio_set_value(par->gpio.dc, 1); | |
121 | ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); | |
122 | if (ret < 0) { | |
123 | dev_err(par->info->device, | |
aed1c72e | 124 | "write failed and returned: %d\n", ret); |
9518dbc0 TP |
125 | break; |
126 | } | |
127 | } | |
128 | ||
129 | return ret; | |
130 | } | |
131 | ||
132 | static int set_gamma(struct fbtft_par *par, unsigned long *curves) | |
133 | { | |
9518dbc0 TP |
134 | /* apply mask */ |
135 | curves[0] &= 0x7F; | |
136 | ||
137 | write_reg(par, 0x21); /* turn on extended instruction set */ | |
138 | write_reg(par, 0x80 | curves[0]); | |
139 | write_reg(par, 0x20); /* turn off extended instruction set */ | |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
9518dbc0 TP |
144 | static struct fbtft_display display = { |
145 | .regwidth = 8, | |
146 | .width = WIDTH, | |
147 | .height = HEIGHT, | |
148 | .txbuflen = TXBUFLEN, | |
149 | .gamma_num = 1, | |
150 | .gamma_len = 1, | |
151 | .gamma = DEFAULT_GAMMA, | |
152 | .fbtftops = { | |
153 | .init_display = init_display, | |
154 | .set_addr_win = set_addr_win, | |
155 | .write_vmem = write_vmem, | |
156 | .set_gamma = set_gamma, | |
157 | }, | |
158 | .backlight = 1, | |
159 | }; | |
1014c2ce | 160 | |
9518dbc0 TP |
161 | FBTFT_REGISTER_DRIVER(DRVNAME, "teralane,tls8204", &display); |
162 | ||
163 | MODULE_ALIAS("spi:" DRVNAME); | |
164 | MODULE_ALIAS("spi:tls8204"); | |
165 | ||
166 | MODULE_DESCRIPTION("FB driver for the TLS8204 LCD Controller"); | |
167 | MODULE_AUTHOR("Michael Hope"); | |
168 | MODULE_LICENSE("GPL"); |