1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * FB driver for the uPD161704 LCD Controller |
4 | * |
5 | * Copyright (C) 2014 Seong-Woo Kim |
6 | * |
7 | * Based on fb_ili9325.c by Noralf Tronnes |
8 | * Based on ili9325.c by Jeroen Domburg |
9 | * Init code from UTFT library by Henning Karlsen |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/init.h> |
15 | #include <linux/delay.h> |
16 | |
17 | #include "fbtft.h" |
18 | |
19 | #define DRVNAME "fb_bd663474" |
20 | #define WIDTH 240 |
21 | #define HEIGHT 320 |
22 | #define BPP 16 |
23 | |
24 | static int init_display(struct fbtft_par *par) |
25 | { |
26 | par->fbtftops.reset(par); |
27 | |
28 | /* Initialization sequence from Lib_UTFT */ |
29 | |
30 | /* oscillator start */ |
31 | write_reg(par, 0x000, 0x0001); /*oscillator 0: stop, 1: operation */ |
32 | mdelay(10); |
33 | |
34 | /* Power settings */ |
35 | write_reg(par, 0x100, 0x0000); /* power supply setup */ |
36 | write_reg(par, 0x101, 0x0000); |
37 | write_reg(par, 0x102, 0x3110); |
38 | write_reg(par, 0x103, 0xe200); |
39 | write_reg(par, 0x110, 0x009d); |
40 | write_reg(par, 0x111, 0x0022); |
41 | write_reg(par, 0x100, 0x0120); |
42 | mdelay(20); |
43 | |
44 | write_reg(par, 0x100, 0x3120); |
45 | mdelay(80); |
46 | /* Display control */ |
47 | write_reg(par, 0x001, 0x0100); |
48 | write_reg(par, 0x002, 0x0000); |
49 | write_reg(par, 0x003, 0x1230); |
50 | write_reg(par, 0x006, 0x0000); |
51 | write_reg(par, 0x007, 0x0101); |
52 | write_reg(par, 0x008, 0x0808); |
53 | write_reg(par, 0x009, 0x0000); |
54 | write_reg(par, 0x00b, 0x0000); |
55 | write_reg(par, 0x00c, 0x0000); |
56 | write_reg(par, 0x00d, 0x0018); |
57 | /* LTPS control settings */ |
58 | write_reg(par, 0x012, 0x0000); |
59 | write_reg(par, 0x013, 0x0000); |
60 | write_reg(par, 0x018, 0x0000); |
61 | write_reg(par, 0x019, 0x0000); |
62 | |
63 | write_reg(par, 0x203, 0x0000); |
64 | write_reg(par, 0x204, 0x0000); |
65 | |
66 | write_reg(par, 0x210, 0x0000); |
67 | write_reg(par, 0x211, 0x00ef); |
68 | write_reg(par, 0x212, 0x0000); |
69 | write_reg(par, 0x213, 0x013f); |
70 | write_reg(par, 0x214, 0x0000); |
71 | write_reg(par, 0x215, 0x0000); |
72 | write_reg(par, 0x216, 0x0000); |
73 | write_reg(par, 0x217, 0x0000); |
74 | |
75 | /* Gray scale settings */ |
76 | write_reg(par, 0x300, 0x5343); |
77 | write_reg(par, 0x301, 0x1021); |
78 | write_reg(par, 0x302, 0x0003); |
79 | write_reg(par, 0x303, 0x0011); |
80 | write_reg(par, 0x304, 0x050a); |
81 | write_reg(par, 0x305, 0x4342); |
82 | write_reg(par, 0x306, 0x1100); |
83 | write_reg(par, 0x307, 0x0003); |
84 | write_reg(par, 0x308, 0x1201); |
85 | write_reg(par, 0x309, 0x050a); |
86 | |
87 | /* RAM access settings */ |
88 | write_reg(par, 0x400, 0x4027); |
89 | write_reg(par, 0x401, 0x0000); |
90 | write_reg(par, 0x402, 0x0000); /* First screen drive position (1) */ |
91 | write_reg(par, 0x403, 0x013f); /* First screen drive position (2) */ |
92 | write_reg(par, 0x404, 0x0000); |
93 | |
94 | write_reg(par, 0x200, 0x0000); |
95 | write_reg(par, 0x201, 0x0000); |
96 | write_reg(par, 0x100, 0x7120); |
97 | write_reg(par, 0x007, 0x0103); |
98 | mdelay(10); |
99 | write_reg(par, 0x007, 0x0113); |
100 | |
101 | return 0; |
102 | } |
103 | |
104 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) |
105 | { |
106 | switch (par->info->var.rotate) { |
107 | /* R200h = Horizontal GRAM Start Address */ |
108 | /* R201h = Vertical GRAM Start Address */ |
109 | case 0: |
110 | write_reg(par, 0x0200, xs); |
111 | write_reg(par, 0x0201, ys); |
112 | break; |
113 | case 180: |
114 | write_reg(par, 0x0200, WIDTH - 1 - xs); |
115 | write_reg(par, 0x0201, HEIGHT - 1 - ys); |
116 | break; |
117 | case 270: |
118 | write_reg(par, 0x0200, WIDTH - 1 - ys); |
119 | write_reg(par, 0x0201, xs); |
120 | break; |
121 | case 90: |
122 | write_reg(par, 0x0200, ys); |
123 | write_reg(par, 0x0201, HEIGHT - 1 - xs); |
124 | break; |
125 | } |
126 | write_reg(par, 0x202); /* Write Data to GRAM */ |
127 | } |
128 | |
129 | static int set_var(struct fbtft_par *par) |
130 | { |
131 | switch (par->info->var.rotate) { |
132 | /* AM: GRAM update direction */ |
133 | case 0: |
134 | write_reg(par, 0x003, 0x1230); |
135 | break; |
136 | case 180: |
137 | write_reg(par, 0x003, 0x1200); |
138 | break; |
139 | case 270: |
140 | write_reg(par, 0x003, 0x1228); |
141 | break; |
142 | case 90: |
143 | write_reg(par, 0x003, 0x1218); |
144 | break; |
145 | } |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | static struct fbtft_display display = { |
151 | .regwidth = 16, |
152 | .width = WIDTH, |
153 | .height = HEIGHT, |
154 | .bpp = BPP, |
155 | .fbtftops = { |
156 | .init_display = init_display, |
157 | .set_addr_win = set_addr_win, |
158 | .set_var = set_var, |
159 | }, |
160 | }; |
161 | |
162 | FBTFT_REGISTER_DRIVER(DRVNAME, "hitachi,bd663474" , &display); |
163 | |
164 | MODULE_ALIAS("spi:" DRVNAME); |
165 | MODULE_ALIAS("platform:" DRVNAME); |
166 | MODULE_ALIAS("spi:bd663474" ); |
167 | MODULE_ALIAS("platform:bd663474" ); |
168 | |
169 | MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller" ); |
170 | MODULE_AUTHOR("Seong-Woo Kim" ); |
171 | MODULE_LICENSE("GPL" ); |
172 | |