]>
Commit | Line | Data |
---|---|---|
5741ecd6 TP |
1 | /* |
2 | * FB driver for the UC1701 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) 2014 Juergen Holzmann | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | */ | |
23 | ||
24 | #include <linux/module.h> | |
25 | #include <linux/kernel.h> | |
26 | #include <linux/init.h> | |
27 | #include <linux/gpio.h> | |
28 | #include <linux/spi/spi.h> | |
29 | #include <linux/delay.h> | |
30 | ||
31 | #include "fbtft.h" | |
32 | ||
33 | #define DRVNAME "fb_uc1701" | |
34 | #define WIDTH 102 | |
35 | #define HEIGHT 64 | |
36 | #define PAGES (HEIGHT/8) | |
37 | ||
38 | /* 1: Display on/off */ | |
39 | #define LCD_DISPLAY_ENABLE 0xAE | |
40 | /* 2: display start line set */ | |
41 | #define LCD_START_LINE 0x40 | |
42 | /* 3: Page address set (lower 4 bits select one of the pages) */ | |
43 | #define LCD_PAGE_ADDRESS 0xB0 | |
44 | /* 4: column address */ | |
45 | #define LCD_COL_ADDRESS 0x10 | |
46 | /* 8: select orientation */ | |
47 | #define LCD_BOTTOMVIEW 0xA0 | |
48 | /* 9: inverted display */ | |
49 | #define LCD_DISPLAY_INVERT 0xA6 | |
50 | /* 10: show memory content or switch all pixels on */ | |
51 | #define LCD_ALL_PIXEL 0xA4 | |
52 | /* 11: lcd bias set */ | |
53 | #define LCD_BIAS 0xA2 | |
54 | /* 14: Reset Controller */ | |
55 | #define LCD_RESET_CMD 0xE2 | |
56 | /* 15: output mode select (turns display upside-down) */ | |
57 | #define LCD_SCAN_DIR 0xC0 | |
58 | /* 16: power control set */ | |
59 | #define LCD_POWER_CONTROL 0x28 | |
60 | /* 17: voltage regulator resistor ratio set */ | |
61 | #define LCD_VOLTAGE 0x20 | |
62 | /* 18: Volume mode set */ | |
63 | #define LCD_VOLUME_MODE 0x81 | |
64 | /* 22: NOP command */ | |
65 | #define LCD_NO_OP 0xE3 | |
66 | /* 25: advanced program control */ | |
67 | #define LCD_ADV_PROG_CTRL 0xFA | |
68 | /* 25: advanced program control2 */ | |
69 | #define LCD_ADV_PROG_CTRL2 0x10 | |
70 | #define LCD_TEMPCOMP_HIGH 0x80 | |
71 | /* column offset for normal orientation */ | |
72 | #define SHIFT_ADDR_NORMAL 0 | |
73 | /* column offset for bottom view orientation */ | |
74 | #define SHIFT_ADDR_TOPVIEW 30 | |
75 | ||
76 | ||
77 | static int init_display(struct fbtft_par *par) | |
78 | { | |
79 | fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); | |
80 | ||
81 | par->fbtftops.reset(par); | |
82 | ||
83 | /* softreset of LCD */ | |
84 | write_reg(par, LCD_RESET_CMD); | |
85 | mdelay(10); | |
86 | ||
87 | /* set startpoint */ | |
88 | /* LCD_START_LINE | (pos & 0x3F) */ | |
89 | write_reg(par, LCD_START_LINE); | |
90 | ||
91 | /* select orientation BOTTOMVIEW */ | |
92 | write_reg(par, LCD_BOTTOMVIEW | 1); | |
93 | /* output mode select (turns display upside-down) */ | |
94 | write_reg(par, LCD_SCAN_DIR | 0x00); | |
95 | ||
96 | /* Normal Pixel mode */ | |
97 | write_reg(par, LCD_ALL_PIXEL | 0); | |
98 | ||
99 | /* positive display */ | |
100 | write_reg(par, LCD_DISPLAY_INVERT | 0); | |
101 | ||
102 | /* bias 1/9 */ | |
103 | write_reg(par, LCD_BIAS | 0); | |
104 | ||
105 | /* power control mode: all features on */ | |
106 | /* LCD_POWER_CONTROL | (val&0x07) */ | |
107 | write_reg(par, LCD_POWER_CONTROL | 0x07); | |
108 | ||
109 | /* set voltage regulator R/R */ | |
110 | /* LCD_VOLTAGE | (val&0x07) */ | |
111 | write_reg(par, LCD_VOLTAGE | 0x07); | |
112 | ||
113 | /* volume mode set */ | |
114 | /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ | |
115 | write_reg(par, LCD_VOLUME_MODE); | |
116 | /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ | |
117 | write_reg(par, 0x09); | |
118 | /* ???? */ | |
119 | /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */ | |
120 | write_reg(par, LCD_NO_OP); | |
121 | ||
122 | /* advanced program control */ | |
123 | write_reg(par, LCD_ADV_PROG_CTRL); | |
124 | write_reg(par, LCD_ADV_PROG_CTRL2|LCD_TEMPCOMP_HIGH); | |
125 | ||
126 | /* enable display */ | |
127 | write_reg(par, LCD_DISPLAY_ENABLE | 1); | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) | |
133 | { | |
134 | fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); | |
135 | ||
136 | /* goto address */ | |
137 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), | |
138 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), | |
139 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ | |
140 | write_reg(par, LCD_PAGE_ADDRESS); | |
141 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), | |
142 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), | |
143 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ | |
144 | write_reg(par, 0x00); | |
145 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), | |
146 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), | |
147 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ | |
148 | write_reg(par, LCD_COL_ADDRESS); | |
149 | } | |
150 | ||
151 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) | |
152 | { | |
153 | u16 *vmem16 = (u16 *)par->info->screen_base; | |
154 | u8 *buf = par->txbuf.buf; | |
155 | int x, y, i; | |
156 | int ret = 0; | |
157 | ||
158 | fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); | |
159 | ||
160 | for (y = 0; y < PAGES; y++) { | |
161 | buf = par->txbuf.buf; | |
162 | for (x = 0; x < WIDTH; x++) { | |
163 | *buf = 0x00; | |
164 | for (i = 0; i < 8; i++) | |
165 | *buf |= (vmem16[((y*8*WIDTH)+(i*WIDTH))+x] ? 1 : 0) << i; | |
166 | buf++; | |
167 | } | |
168 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), | |
169 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), | |
170 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ | |
171 | write_reg(par, LCD_PAGE_ADDRESS|(u8)y); | |
172 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), | |
173 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), | |
174 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ | |
175 | write_reg(par, 0x00); | |
176 | /* LCD_PAGE_ADDRESS | ((page) & 0x1F), | |
177 | (((col)+SHIFT_ADDR_NORMAL) & 0x0F), | |
178 | LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */ | |
179 | write_reg(par, LCD_COL_ADDRESS); | |
180 | gpio_set_value(par->gpio.dc, 1); | |
181 | ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); | |
182 | gpio_set_value(par->gpio.dc, 0); | |
183 | } | |
184 | ||
185 | if (ret < 0) | |
aed1c72e HM |
186 | dev_err(par->info->device, "write failed and returned: %d\n", |
187 | ret); | |
5741ecd6 TP |
188 | |
189 | return ret; | |
190 | } | |
191 | ||
192 | ||
193 | static struct fbtft_display display = { | |
194 | .regwidth = 8, | |
195 | .width = WIDTH, | |
196 | .height = HEIGHT, | |
197 | .fbtftops = { | |
198 | .init_display = init_display, | |
199 | .set_addr_win = set_addr_win, | |
200 | .write_vmem = write_vmem, | |
201 | }, | |
202 | .backlight = 1, | |
203 | }; | |
204 | FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display); | |
205 | ||
206 | MODULE_ALIAS("spi:" DRVNAME); | |
207 | MODULE_ALIAS("spi:uc1701"); | |
208 | ||
209 | MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller"); | |
210 | MODULE_AUTHOR("Juergen Holzmann"); | |
211 | MODULE_LICENSE("GPL"); |