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