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