1 /*
2 * FB driver for the HX8357D LCD Controller
3 * Copyright (C) 2015 Adafruit Industries
4 *
5 * Based on the HX8347D FB driver
6 * Copyright (C) 2013 Christian Vogelgsang
7 *
8 * Based on driver code found here: https://github.com/watterott/r61505u-Adapter
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.
19 */
20
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/delay.h>
25
26 #include "fbtft.h"
27 #include "fb_hx8357d.h"
28
29 #define DRVNAME "fb_hx8357d"
30 #define WIDTH 320
31 #define HEIGHT 480
32
init_display(struct fbtft_par * par)33 static int init_display(struct fbtft_par *par)
34 {
35 par->fbtftops.reset(par);
36
37 /* Reset things like Gamma */
38 write_reg(par, HX8357B_SWRESET);
39 usleep_range(5000, 7000);
40
41 /* setextc */
42 write_reg(par, HX8357D_SETC, 0xFF, 0x83, 0x57);
43 msleep(150);
44
45 /* setRGB which also enables SDO */
46 write_reg(par, HX8357_SETRGB, 0x00, 0x00, 0x06, 0x06);
47
48 /* -1.52V */
49 write_reg(par, HX8357D_SETCOM, 0x25);
50
51 /* Normal mode 70Hz, Idle mode 55 Hz */
52 write_reg(par, HX8357_SETOSC, 0x68);
53
54 /* Set Panel - BGR, Gate direction swapped */
55 write_reg(par, HX8357_SETPANEL, 0x05);
56
57 write_reg(par, HX8357_SETPWR1,
58 0x00, /* Not deep standby */
59 0x15, /* BT */
60 0x1C, /* VSPR */
61 0x1C, /* VSNR */
62 0x83, /* AP */
63 0xAA); /* FS */
64
65 write_reg(par, HX8357D_SETSTBA,
66 0x50, /* OPON normal */
67 0x50, /* OPON idle */
68 0x01, /* STBA */
69 0x3C, /* STBA */
70 0x1E, /* STBA */
71 0x08); /* GEN */
72
73 write_reg(par, HX8357D_SETCYC,
74 0x02, /* NW 0x02 */
75 0x40, /* RTN */
76 0x00, /* DIV */
77 0x2A, /* DUM */
78 0x2A, /* DUM */
79 0x0D, /* GDON */
80 0x78); /* GDOFF */
81
82 write_reg(par, HX8357D_SETGAMMA,
83 0x02,
84 0x0A,
85 0x11,
86 0x1d,
87 0x23,
88 0x35,
89 0x41,
90 0x4b,
91 0x4b,
92 0x42,
93 0x3A,
94 0x27,
95 0x1B,
96 0x08,
97 0x09,
98 0x03,
99 0x02,
100 0x0A,
101 0x11,
102 0x1d,
103 0x23,
104 0x35,
105 0x41,
106 0x4b,
107 0x4b,
108 0x42,
109 0x3A,
110 0x27,
111 0x1B,
112 0x08,
113 0x09,
114 0x03,
115 0x00,
116 0x01);
117
118 /* 16 bit */
119 write_reg(par, HX8357_COLMOD, 0x55);
120
121 write_reg(par, HX8357_MADCTL, 0xC0);
122
123 /* TE off */
124 write_reg(par, HX8357_TEON, 0x00);
125
126 /* tear line */
127 write_reg(par, HX8357_TEARLINE, 0x00, 0x02);
128
129 /* Exit Sleep */
130 write_reg(par, HX8357_SLPOUT);
131 msleep(150);
132
133 /* display on */
134 write_reg(par, HX8357_DISPON);
135 usleep_range(5000, 7000);
136
137 return 0;
138 }
139
set_addr_win(struct fbtft_par * par,int xs,int ys,int xe,int ye)140 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
141 {
142 /* Column addr set */
143 write_reg(par, HX8357_CASET,
144 xs >> 8, xs & 0xff, /* XSTART */
145 xe >> 8, xe & 0xff); /* XEND */
146
147 /* Row addr set */
148 write_reg(par, HX8357_PASET,
149 ys >> 8, ys & 0xff, /* YSTART */
150 ye >> 8, ye & 0xff); /* YEND */
151
152 /* write to RAM */
153 write_reg(par, HX8357_RAMWR);
154 }
155
156 #define HX8357D_MADCTL_MY 0x80
157 #define HX8357D_MADCTL_MX 0x40
158 #define HX8357D_MADCTL_MV 0x20
159 #define HX8357D_MADCTL_ML 0x10
160 #define HX8357D_MADCTL_RGB 0x00
161 #define HX8357D_MADCTL_BGR 0x08
162 #define HX8357D_MADCTL_MH 0x04
set_var(struct fbtft_par * par)163 static int set_var(struct fbtft_par *par)
164 {
165 u8 val;
166
167 switch (par->info->var.rotate) {
168 case 270:
169 val = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
170 break;
171 case 180:
172 val = 0;
173 break;
174 case 90:
175 val = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
176 break;
177 default:
178 val = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
179 break;
180 }
181
182 val |= (par->bgr ? HX8357D_MADCTL_RGB : HX8357D_MADCTL_BGR);
183
184 /* Memory Access Control */
185 write_reg(par, HX8357_MADCTL, val);
186
187 return 0;
188 }
189
190 static struct fbtft_display display = {
191 .regwidth = 8,
192 .width = WIDTH,
193 .height = HEIGHT,
194 .gamma_num = 2,
195 .gamma_len = 14,
196 .fbtftops = {
197 .init_display = init_display,
198 .set_addr_win = set_addr_win,
199 .set_var = set_var,
200 },
201 };
202
203 FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8357d", &display);
204
205 MODULE_ALIAS("spi:" DRVNAME);
206 MODULE_ALIAS("platform:" DRVNAME);
207 MODULE_ALIAS("spi:hx8357d");
208 MODULE_ALIAS("platform:hx8357d");
209
210 MODULE_DESCRIPTION("FB driver for the HX8357D LCD Controller");
211 MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
212 MODULE_LICENSE("GPL");
213