blob: 2e1b72ad54aa95e408136002442ac3584052df1a [file] [log] [blame]
Thomas Petazzoni7a39e962014-12-31 10:11:24 +01001/*
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
41static 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
87static 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
114static 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]
143static int set_gamma(struct fbtft_par *par, unsigned long *curves)
144{
145 unsigned long mask[] = {
Geert Uytterhoeven153fe942015-03-20 16:21:58 +0100146 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 };
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100150 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
181static 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};
197FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display);
198
199MODULE_ALIAS("spi:" DRVNAME);
200MODULE_ALIAS("platform:" DRVNAME);
201MODULE_ALIAS("spi:s6d1121");
202MODULE_ALIAS("platform:s6d1121");
203
204MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller");
205MODULE_AUTHOR("Roman Rolinsky");
206MODULE_LICENSE("GPL");