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