1 /*
2  * FB driver for the S6D1121 LCD Controller
3  *
4  * Copyright (C) 2013 Roman Rolinsky
5  *
6  * Based on fb_ili9325.c by Noralf Tronnes
7  * Based on ili9325.c by Jeroen Domburg
8  * Init code from UTFT library by Henning Karlsen
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  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24 
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/init.h>
28 #include <linux/gpio.h>
29 #include <linux/delay.h>
30 
31 #include "fbtft.h"
32 
33 #define DRVNAME		"fb_s6d1121"
34 #define WIDTH		240
35 #define HEIGHT		320
36 #define BPP		16
37 #define FPS		20
38 #define DEFAULT_GAMMA	"26 09 24 2C 1F 23 24 25 22 26 25 23 0D 00\n" \
39 			"1C 1A 13 1D 0B 11 12 10 13 15 36 19 00 0D"
40 
41 static int init_display(struct fbtft_par *par)
42 {
43 	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
44 
45 	par->fbtftops.reset(par);
46 
47 	if (par->gpio.cs != -1)
48 		gpio_set_value(par->gpio.cs, 0);  /* Activate chip */
49 
50 	/* Initialization sequence from Lib_UTFT */
51 
52 	write_reg(par, 0x0011, 0x2004);
53 	write_reg(par, 0x0013, 0xCC00);
54 	write_reg(par, 0x0015, 0x2600);
55 	write_reg(par, 0x0014, 0x252A);
56 	write_reg(par, 0x0012, 0x0033);
57 	write_reg(par, 0x0013, 0xCC04);
58 	write_reg(par, 0x0013, 0xCC06);
59 	write_reg(par, 0x0013, 0xCC4F);
60 	write_reg(par, 0x0013, 0x674F);
61 	write_reg(par, 0x0011, 0x2003);
62 	write_reg(par, 0x0016, 0x0007);
63 	write_reg(par, 0x0002, 0x0013);
64 	write_reg(par, 0x0003, 0x0003);
65 	write_reg(par, 0x0001, 0x0127);
66 	write_reg(par, 0x0008, 0x0303);
67 	write_reg(par, 0x000A, 0x000B);
68 	write_reg(par, 0x000B, 0x0003);
69 	write_reg(par, 0x000C, 0x0000);
70 	write_reg(par, 0x0041, 0x0000);
71 	write_reg(par, 0x0050, 0x0000);
72 	write_reg(par, 0x0060, 0x0005);
73 	write_reg(par, 0x0070, 0x000B);
74 	write_reg(par, 0x0071, 0x0000);
75 	write_reg(par, 0x0078, 0x0000);
76 	write_reg(par, 0x007A, 0x0000);
77 	write_reg(par, 0x0079, 0x0007);
78 	write_reg(par, 0x0007, 0x0051);
79 	write_reg(par, 0x0007, 0x0053);
80 	write_reg(par, 0x0079, 0x0000);
81 
82 	write_reg(par, 0x0022); /* Write Data to GRAM */
83 
84 	return 0;
85 }
86 
87 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
88 {
89 	fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
90 		"%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
91 	switch (par->info->var.rotate) {
92 	/* R20h = Horizontal GRAM Start Address */
93 	/* R21h = Vertical GRAM Start Address */
94 	case 0:
95 		write_reg(par, 0x0020, xs);
96 		write_reg(par, 0x0021, ys);
97 		break;
98 	case 180:
99 		write_reg(par, 0x0020, WIDTH - 1 - xs);
100 		write_reg(par, 0x0021, HEIGHT - 1 - ys);
101 		break;
102 	case 270:
103 		write_reg(par, 0x0020, WIDTH - 1 - ys);
104 		write_reg(par, 0x0021, xs);
105 		break;
106 	case 90:
107 		write_reg(par, 0x0020, ys);
108 		write_reg(par, 0x0021, HEIGHT - 1 - xs);
109 		break;
110 	}
111 	write_reg(par, 0x0022); /* Write Data to GRAM */
112 }
113 
114 static int set_var(struct fbtft_par *par)
115 {
116 	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
117 
118 	switch (par->info->var.rotate) {
119 	/* AM: GRAM update direction */
120 	case 0:
121 		write_reg(par, 0x03, 0x0003 | (par->bgr << 12));
122 		break;
123 	case 180:
124 		write_reg(par, 0x03, 0x0000 | (par->bgr << 12));
125 		break;
126 	case 270:
127 		write_reg(par, 0x03, 0x000A | (par->bgr << 12));
128 		break;
129 	case 90:
130 		write_reg(par, 0x03, 0x0009 | (par->bgr << 12));
131 		break;
132 	}
133 
134 	return 0;
135 }
136 
137 /*
138   Gamma string format:
139     PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 PKP6 PKP7 PKP8 PKP9 PKP10 PKP11 VRP0 VRP1
140     PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1
141 */
142 #define CURVE(num, idx)  curves[num*par->gamma.num_values + idx]
143 static int set_gamma(struct fbtft_par *par, unsigned long *curves)
144 {
145 	unsigned long mask[] = {
146 		0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
147 		0x3f, 0x3f, 0x1f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
148 		0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f,
149 	};
150 	int i, j;
151 
152 	fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
153 
154 	/* apply mask */
155 	for (i = 0; i < 2; i++)
156 		for (j = 0; j < 14; j++)
157 			CURVE(i, j) &= mask[i*par->gamma.num_values + j];
158 
159 	write_reg(par, 0x0030, CURVE(0, 1) << 8 | CURVE(0, 0));
160 	write_reg(par, 0x0031, CURVE(0, 3) << 8 | CURVE(0, 2));
161 	write_reg(par, 0x0032, CURVE(0, 5) << 8 | CURVE(0, 3));
162 	write_reg(par, 0x0033, CURVE(0, 7) << 8 | CURVE(0, 6));
163 	write_reg(par, 0x0034, CURVE(0, 9) << 8 | CURVE(0, 8));
164 	write_reg(par, 0x0035, CURVE(0, 11) << 8 | CURVE(0, 10));
165 
166 	write_reg(par, 0x0036, CURVE(1, 1) << 8 | CURVE(1, 0));
167 	write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2));
168 	write_reg(par, 0x0038, CURVE(1, 5) << 8 | CURVE(1, 4));
169 	write_reg(par, 0x0039, CURVE(1, 7) << 8 | CURVE(1, 6));
170 	write_reg(par, 0x003A, CURVE(1, 9) << 8 | CURVE(1, 8));
171 	write_reg(par, 0x003B, CURVE(1, 11) << 8 | CURVE(1, 10));
172 
173 	write_reg(par, 0x003C, CURVE(0, 13) << 8 | CURVE(0, 12));
174 	write_reg(par, 0x003D, CURVE(1, 13) << 8 | CURVE(1, 12));
175 
176 	return 0;
177 }
178 #undef CURVE
179 
180 
181 static struct fbtft_display display = {
182 	.regwidth = 16,
183 	.width = WIDTH,
184 	.height = HEIGHT,
185 	.bpp = BPP,
186 	.fps = FPS,
187 	.gamma_num = 2,
188 	.gamma_len = 14,
189 	.gamma = DEFAULT_GAMMA,
190 	.fbtftops = {
191 		.init_display = init_display,
192 		.set_addr_win = set_addr_win,
193 		.set_var = set_var,
194 		.set_gamma = set_gamma,
195 	},
196 };
197 FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display);
198 
199 MODULE_ALIAS("spi:" DRVNAME);
200 MODULE_ALIAS("platform:" DRVNAME);
201 MODULE_ALIAS("spi:s6d1121");
202 MODULE_ALIAS("platform:s6d1121");
203 
204 MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller");
205 MODULE_AUTHOR("Roman Rolinsky");
206 MODULE_LICENSE("GPL");
207