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. | |
5741ecd6 TP |
18 | */ |
19 | ||
20 | #include <linux/module.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/init.h> | |
23 | #include <linux/gpio.h> | |
24 | #include <linux/spi/spi.h> | |
25 | #include <linux/delay.h> | |
26 | ||
27 | #include "fbtft.h" | |
28 | ||
29 | #define DRVNAME "fb_uc1701" | |
30 | #define WIDTH 102 | |
31 | #define HEIGHT 64 | |
94c0a544 | 32 | #define PAGES (HEIGHT / 8) |
5741ecd6 TP |
33 | |
34 | /* 1: Display on/off */ | |
35 | #define LCD_DISPLAY_ENABLE 0xAE | |
36 | /* 2: display start line set */ | |
37 | #define LCD_START_LINE 0x40 | |
38 | /* 3: Page address set (lower 4 bits select one of the pages) */ | |
39 | #define LCD_PAGE_ADDRESS 0xB0 | |
40 | /* 4: column address */ | |
41 | #define LCD_COL_ADDRESS 0x10 | |
42 | /* 8: select orientation */ | |
43 | #define LCD_BOTTOMVIEW 0xA0 | |
44 | /* 9: inverted display */ | |
45 | #define LCD_DISPLAY_INVERT 0xA6 | |
46 | /* 10: show memory content or switch all pixels on */ | |
47 | #define LCD_ALL_PIXEL 0xA4 | |
48 | /* 11: lcd bias set */ | |
49 | #define LCD_BIAS 0xA2 | |
50 | /* 14: Reset Controller */ | |
51 | #define LCD_RESET_CMD 0xE2 | |
52 | /* 15: output mode select (turns display upside-down) */ | |
53 | #define LCD_SCAN_DIR 0xC0 | |
54 | /* 16: power control set */ | |
55 | #define LCD_POWER_CONTROL 0x28 | |
56 | /* 17: voltage regulator resistor ratio set */ | |
57 | #define LCD_VOLTAGE 0x20 | |
58 | /* 18: Volume mode set */ | |
59 | #define LCD_VOLUME_MODE 0x81 | |
60 | /* 22: NOP command */ | |
61 | #define LCD_NO_OP 0xE3 | |
62 | /* 25: advanced program control */ | |
63 | #define LCD_ADV_PROG_CTRL 0xFA | |
64 | /* 25: advanced program control2 */ | |
65 | #define LCD_ADV_PROG_CTRL2 0x10 | |
66 | #define LCD_TEMPCOMP_HIGH 0x80 | |
67 | /* column offset for normal orientation */ | |
68 | #define SHIFT_ADDR_NORMAL 0 | |
69 | /* column offset for bottom view orientation */ | |
70 | #define SHIFT_ADDR_TOPVIEW 30 | |
71 | ||
5741ecd6 TP |
72 | static int init_display(struct fbtft_par *par) |
73 | { | |
5741ecd6 TP |
74 | par->fbtftops.reset(par); |
75 | ||
76 | /* softreset of LCD */ | |
77 | write_reg(par, LCD_RESET_CMD); | |
78 | mdelay(10); | |
79 | ||
80 | /* set startpoint */ | |
5741ecd6 TP |
81 | write_reg(par, LCD_START_LINE); |
82 | ||
83 | /* select orientation BOTTOMVIEW */ | |
84 | write_reg(par, LCD_BOTTOMVIEW | 1); | |
fd59f106 | 85 | |
5741ecd6 TP |
86 | /* output mode select (turns display upside-down) */ |
87 | write_reg(par, LCD_SCAN_DIR | 0x00); | |
88 | ||
89 | /* Normal Pixel mode */ | |
90 | write_reg(par, LCD_ALL_PIXEL | 0); | |
91 | ||
92 | /* positive display */ | |
93 | write_reg(par, LCD_DISPLAY_INVERT | 0); | |
94 | ||
95 | /* bias 1/9 */ | |
96 | write_reg(par, LCD_BIAS | 0); | |
97 | ||
98 | /* power control mode: all features on */ | |
5741ecd6 TP |
99 | write_reg(par, LCD_POWER_CONTROL | 0x07); |
100 | ||
101 | /* set voltage regulator R/R */ | |
5741ecd6 TP |
102 | write_reg(par, LCD_VOLTAGE | 0x07); |
103 | ||
104 | /* volume mode set */ | |
5741ecd6 | 105 | write_reg(par, LCD_VOLUME_MODE); |
5741ecd6 | 106 | write_reg(par, 0x09); |
5741ecd6 TP |
107 | write_reg(par, LCD_NO_OP); |
108 | ||
109 | /* advanced program control */ | |
110 | write_reg(par, LCD_ADV_PROG_CTRL); | |
94c0a544 | 111 | write_reg(par, LCD_ADV_PROG_CTRL2 | LCD_TEMPCOMP_HIGH); |
5741ecd6 TP |
112 | |
113 | /* enable display */ | |
114 | write_reg(par, LCD_DISPLAY_ENABLE | 1); | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
119 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) | |
120 | { | |
5741ecd6 | 121 | /* goto address */ |
5741ecd6 | 122 | write_reg(par, LCD_PAGE_ADDRESS); |
5741ecd6 | 123 | write_reg(par, 0x00); |
5741ecd6 TP |
124 | write_reg(par, LCD_COL_ADDRESS); |
125 | } | |
126 | ||
127 | static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) | |
128 | { | |
4b6dc179 | 129 | u16 *vmem16 = (u16 *)par->info->screen_buffer; |
5741ecd6 TP |
130 | u8 *buf = par->txbuf.buf; |
131 | int x, y, i; | |
132 | int ret = 0; | |
133 | ||
5741ecd6 TP |
134 | for (y = 0; y < PAGES; y++) { |
135 | buf = par->txbuf.buf; | |
136 | for (x = 0; x < WIDTH; x++) { | |
137 | *buf = 0x00; | |
138 | for (i = 0; i < 8; i++) | |
94c0a544 AB |
139 | *buf |= (vmem16[((y * 8 * WIDTH) + |
140 | (i * WIDTH)) + x] ? | |
141 | 1 : 0) << i; | |
5741ecd6 TP |
142 | buf++; |
143 | } | |
fd59f106 | 144 | |
94c0a544 | 145 | write_reg(par, LCD_PAGE_ADDRESS | (u8)y); |
5741ecd6 | 146 | write_reg(par, 0x00); |
5741ecd6 TP |
147 | write_reg(par, LCD_COL_ADDRESS); |
148 | gpio_set_value(par->gpio.dc, 1); | |
149 | ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH); | |
150 | gpio_set_value(par->gpio.dc, 0); | |
151 | } | |
152 | ||
153 | if (ret < 0) | |
aed1c72e HM |
154 | dev_err(par->info->device, "write failed and returned: %d\n", |
155 | ret); | |
5741ecd6 TP |
156 | |
157 | return ret; | |
158 | } | |
159 | ||
5741ecd6 TP |
160 | static struct fbtft_display display = { |
161 | .regwidth = 8, | |
162 | .width = WIDTH, | |
163 | .height = HEIGHT, | |
164 | .fbtftops = { | |
165 | .init_display = init_display, | |
166 | .set_addr_win = set_addr_win, | |
167 | .write_vmem = write_vmem, | |
168 | }, | |
169 | .backlight = 1, | |
170 | }; | |
1014c2ce | 171 | |
5741ecd6 TP |
172 | FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display); |
173 | ||
174 | MODULE_ALIAS("spi:" DRVNAME); | |
175 | MODULE_ALIAS("spi:uc1701"); | |
176 | ||
177 | MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller"); | |
178 | MODULE_AUTHOR("Juergen Holzmann"); | |
179 | MODULE_LICENSE("GPL"); |