blob: ed92a64306ff2dece1b74e38df087870a00a8bc9 [file] [log] [blame]
Kozhevnikov Anatoly3b143b52015-03-20 18:37:54 +03001/*
2 * FB driver for the ILI9163 LCD Controller
3 *
4 * Copyright (C) 2015 Kozhevnikov Anatoly
5 *
6 * Based on ili9325.c by Noralf Tronnes and
7 * .S.U.M.O.T.O.Y. by Max MC Costa (https://github.com/sumotoy/TFT_ILI9163C).
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
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/gpio.h>
24#include <linux/delay.h>
25
26#include "fbtft.h"
27
28#define DRVNAME "fb_ili9163"
29#define WIDTH 128
30#define HEIGHT 128
31#define BPP 16
32#define FPS 30
33
34#ifdef GAMMA_ADJ
35#define GAMMA_LEN 15
36#define GAMMA_NUM 1
37#define DEFAULT_GAMMA "36 29 12 22 1C 15 42 B7 2F 13 12 0A 11 0B 06\n"
38#endif
39
40/* ILI9163C commands */
41#define CMD_NOP 0x00 /* Non operation*/
42#define CMD_SWRESET 0x01 /* Soft Reset */
43#define CMD_SLPIN 0x10 /* Sleep ON */
44#define CMD_SLPOUT 0x11 /* Sleep OFF */
45#define CMD_PTLON 0x12 /* Partial Mode ON */
46#define CMD_NORML 0x13 /* Normal Display ON */
47#define CMD_DINVOF 0x20 /* Display Inversion OFF */
48#define CMD_DINVON 0x21 /* Display Inversion ON */
49#define CMD_GAMMASET 0x26 /* Gamma Set (0x01[1],0x02[2],0x04[3],0x08[4]) */
50#define CMD_DISPOFF 0x28 /* Display OFF */
51#define CMD_DISPON 0x29 /* Display ON */
52#define CMD_IDLEON 0x39 /* Idle Mode ON */
53#define CMD_IDLEOF 0x38 /* Idle Mode OFF */
54#define CMD_CLMADRS 0x2A /* Column Address Set */
55#define CMD_PGEADRS 0x2B /* Page Address Set */
56
57#define CMD_RAMWR 0x2C /* Memory Write */
58#define CMD_RAMRD 0x2E /* Memory Read */
59#define CMD_CLRSPACE 0x2D /* Color Space : 4K/65K/262K */
60#define CMD_PARTAREA 0x30 /* Partial Area */
61#define CMD_VSCLLDEF 0x33 /* Vertical Scroll Definition */
62#define CMD_TEFXLON 0x34 /* Tearing Effect Line ON */
63#define CMD_TEFXLOF 0x35 /* Tearing Effect Line OFF */
64#define CMD_MADCTL 0x36 /* Memory Access Control */
65
66#define CMD_PIXFMT 0x3A /* Interface Pixel Format */
67#define CMD_FRMCTR1 0xB1 /* Frame Rate Control
68 (In normal mode/Full colors) */
69#define CMD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle mode/8-colors) */
70#define CMD_FRMCTR3 0xB3 /* Frame Rate Control
71 (In Partial mode/full colors) */
72#define CMD_DINVCTR 0xB4 /* Display Inversion Control */
73#define CMD_RGBBLK 0xB5 /* RGB Interface Blanking Porch setting */
74#define CMD_DFUNCTR 0xB6 /* Display Function set 5 */
75#define CMD_SDRVDIR 0xB7 /* Source Driver Direction Control */
76#define CMD_GDRVDIR 0xB8 /* Gate Driver Direction Control */
77
78#define CMD_PWCTR1 0xC0 /* Power_Control1 */
79#define CMD_PWCTR2 0xC1 /* Power_Control2 */
80#define CMD_PWCTR3 0xC2 /* Power_Control3 */
81#define CMD_PWCTR4 0xC3 /* Power_Control4 */
82#define CMD_PWCTR5 0xC4 /* Power_Control5 */
83#define CMD_VCOMCTR1 0xC5 /* VCOM_Control 1 */
84#define CMD_VCOMCTR2 0xC6 /* VCOM_Control 2 */
85#define CMD_VCOMOFFS 0xC7 /* VCOM Offset Control */
86#define CMD_PGAMMAC 0xE0 /* Positive Gamma Correction Setting */
87#define CMD_NGAMMAC 0xE1 /* Negative Gamma Correction Setting */
88#define CMD_GAMRSEL 0xF2 /* GAM_R_SEL */
89
90/*
91This display:
92http://www.ebay.com/itm/Replace-Nokia-5110-LCD-1-44-Red-Serial-128X128-SPI-Color-TFT-LCD-Display-Module-/271422122271
93This particular display has a design error! The controller has 3 pins to
94configure to constrain the memory and resolution to a fixed dimension (in
95that case 128x128) but they leaved those pins configured for 128x160 so
96there was several pixel memory addressing problems.
97I solved by setup several parameters that dinamically fix the resolution as
98needit so below the parameters for this display. If you have a strain or a
99correct display (can happen with chinese) you can copy those parameters and
100create setup for different displays.
101*/
102
103#ifdef RED
104#define __OFFSET 32 /*see note 2 - this is the red version */
105#else
106#define __OFFSET 0 /*see note 2 - this is the black version */
107#endif
108
109static int init_display(struct fbtft_par *par)
110{
111 fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
112
113 par->fbtftops.reset(par);
114
115 if (par->gpio.cs != -1)
116 gpio_set_value(par->gpio.cs, 0); /* Activate chip */
117
118 write_reg(par, CMD_SWRESET); /* software reset */
119 mdelay(500);
120 write_reg(par, CMD_SLPOUT); /* exit sleep */
121 mdelay(5);
122 write_reg(par, CMD_PIXFMT, 0x05); /* Set Color Format 16bit */
123 write_reg(par, CMD_GAMMASET, 0x02); /* default gamma curve 3 */
124#ifdef GAMMA_ADJ
125 write_reg(par, CMD_GAMRSEL, 0x01); /* Enable Gamma adj */
126#endif
127 write_reg(par, CMD_NORML);
128 write_reg(par, CMD_DFUNCTR, 0xff, 0x06);
129 /* Frame Rate Control (In normal mode/Full colors) */
130 write_reg(par, CMD_FRMCTR1, 0x08, 0x02);
131 write_reg(par, CMD_DINVCTR, 0x07); /* display inversion */
132 /* Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD */
133 write_reg(par, CMD_PWCTR1, 0x0A, 0x02);
134 /* Set BT[2:0] for AVDD & VCL & VGH & VGL */
135 write_reg(par, CMD_PWCTR2, 0x02);
136 /* Set VMH[6:0] & VML[6:0] for VOMH & VCOML */
137 write_reg(par, CMD_VCOMCTR1, 0x50, 0x63);
138 write_reg(par, CMD_VCOMOFFS, 0);
139
140 write_reg(par, CMD_CLMADRS, 0, 0, 0, WIDTH); /* Set Column Address */
141 write_reg(par, CMD_PGEADRS, 0, 0, 0, HEIGHT); /* Set Page Address */
142
143 write_reg(par, CMD_DISPON); /* display ON */
144 write_reg(par, CMD_RAMWR); /* Memory Write */
145
146 return 0;
147}
148
149static void set_addr_win(struct fbtft_par *par, int xs, int ys,
150 int xe, int ye)
151{
152 fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
153 "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
154
155 switch (par->info->var.rotate) {
156 case 0:
157 write_reg(par, CMD_CLMADRS, xs >> 8, xs & 0xff, xe >> 8,
158 xe & 0xff);
159 write_reg(par, CMD_PGEADRS,
160 (ys + __OFFSET) >> 8, (ys + __OFFSET) & 0xff,
161 (ye + __OFFSET) >> 8, (ye + __OFFSET) & 0xff);
162 break;
163 case 90:
164 write_reg(par, CMD_CLMADRS,
165 (xs + __OFFSET) >> 8, (xs + __OFFSET) & 0xff,
166 (xe + __OFFSET) >> 8, (xe + __OFFSET) & 0xff);
167 write_reg(par, CMD_PGEADRS, ys >> 8, ys & 0xff, ye >> 8,
168 ye & 0xff);
169 break;
170 case 180:
171 case 270:
172 write_reg(par, CMD_CLMADRS, xs >> 8, xs & 0xff, xe >> 8,
173 xe & 0xff);
174 write_reg(par, CMD_PGEADRS, ys >> 8, ys & 0xff, ye >> 8,
175 ye & 0xff);
176 break;
177 default:
178 par->info->var.rotate = 0; /* Fix incorrect setting */
179 }
180 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */
181}
182
183/*
1847) MY: 1(bottom to top), 0(top to bottom) Row Address Order
1856) MX: 1(R to L), 0(L to R) Column Address Order
1865) MV: 1(Exchanged), 0(normal) Row/Column exchange
1874) ML: 1(bottom to top), 0(top to bottom) Vertical Refresh Order
1883) RGB: 1(BGR), 0(RGB) Color Space
1892) MH: 1(R to L), 0(L to R) Horizontal Refresh Order
1901)
1910)
192
193 MY, MX, MV, ML,RGB, MH, D1, D0
194 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //normal
195 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //Y-Mirror
196 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Mirror
197 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Y-Mirror
198 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange
199 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange, Y-Mirror
200 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 //XY exchange
201 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0
202*/
203static int set_var(struct fbtft_par *par)
204{
205 u8 mactrl_data = 0; /* Avoid compiler warning */
206
207 fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
208
209 switch (par->info->var.rotate) {
210 case 0:
211 mactrl_data = 0x08;
212 break;
213 case 180:
214 mactrl_data = 0xC8;
215 break;
216 case 270:
217 mactrl_data = 0xA8;
218 break;
219 case 90:
220 mactrl_data = 0x68;
221 break;
222 }
223
224 /* Colorspcae */
225 if (par->bgr)
226 mactrl_data |= (1 << 2);
227 write_reg(par, CMD_MADCTL, mactrl_data);
228 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */
229 return 0;
230}
231
232#ifdef GAMMA_ADJ
233#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
234static int gamma_adj(struct fbtft_par *par, unsigned long *curves)
235{
236 unsigned long mask[] = {
237 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
238 0x1f, 0x3f, 0x0f, 0x0f, 0x7f, 0x1f,
239 0x3F, 0x3F, 0x3F, 0x3F, 0x3F};
240 int i, j;
241
242 fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
243
244 for (i = 0; i < GAMMA_NUM; i++)
245 for (j = 0; j < GAMMA_LEN; j++)
246 CURVE(i, j) &= mask[i*par->gamma.num_values + j];
247
248 write_reg(par, CMD_PGAMMAC,
249 CURVE(0, 0),
250 CURVE(0, 1),
251 CURVE(0, 2),
252 CURVE(0, 3),
253 CURVE(0, 4),
254 CURVE(0, 5),
255 CURVE(0, 6),
256 (CURVE(0, 7) << 4) | CURVE(0, 8),
257 CURVE(0, 9),
258 CURVE(0, 10),
259 CURVE(0, 11),
260 CURVE(0, 12),
261 CURVE(0, 13),
262 CURVE(0, 14),
263 CURVE(0, 15)
264 );
265
266 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */
267
268 return 0;
269}
270#undef CURVE
271#endif
272
273static struct fbtft_display display = {
274 .regwidth = 8,
275 .width = WIDTH,
276 .height = HEIGHT,
277 .bpp = BPP,
278 .fps = FPS,
279#ifdef GAMMA_ADJ
280 .gamma_num = GAMMA_NUM,
281 .gamma_len = GAMMA_LEN,
282 .gamma = DEFAULT_GAMMA,
283#endif
284 .fbtftops = {
285 .init_display = init_display,
286 .set_addr_win = set_addr_win,
287 .set_var = set_var,
288#ifdef GAMMA_ADJ
289 .set_gamma = gamma_adj,
290#endif
291 },
292};
293
294FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9163", &display);
295
296MODULE_ALIAS("spi:" DRVNAME);
297MODULE_ALIAS("platform:" DRVNAME);
298MODULE_ALIAS("spi:ili9163");
299MODULE_ALIAS("platform:ili9163");
300
301MODULE_DESCRIPTION("FB driver for the ILI9163 LCD Controller");
302MODULE_AUTHOR("Kozhevnikov Anatoly");
303MODULE_LICENSE("GPL");