blob: 9b1d70b218df14f177907010d12948bbc8471316 [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.
Thomas Petazzoni7a39e962014-12-31 10:11:24 +010019 */
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
37static int init_display(struct fbtft_par *par)
38{
Thomas Petazzoni7a39e962014-12-31 10:11:24 +010039 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
81static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
82{
Thomas Petazzoni7a39e962014-12-31 10:11:24 +010083 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
106static int set_var(struct fbtft_par *par)
107{
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100108 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/*
Anson Jacoba40fe152016-08-25 11:23:27 -0400128 * 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 */
Anish Bhatt94c0a542015-09-03 00:53:37 -0700132#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100133static int set_gamma(struct fbtft_par *par, unsigned long *curves)
134{
135 unsigned long mask[] = {
Geert Uytterhoeven153fe942015-03-20 16:21:58 +0100136 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 };
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100140 int i, j;
141
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100142 /* apply mask */
143 for (i = 0; i < 2; i++)
144 for (j = 0; j < 14; j++)
Anish Bhatt94c0a542015-09-03 00:53:37 -0700145 CURVE(i, j) &= mask[i * par->gamma.num_values + j];
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100146
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
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100168static 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};
Anish Bhatt1014c2c2015-09-03 00:53:36 -0700184
Thomas Petazzoni7a39e962014-12-31 10:11:24 +0100185FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display);
186
187MODULE_ALIAS("spi:" DRVNAME);
188MODULE_ALIAS("platform:" DRVNAME);
189MODULE_ALIAS("spi:s6d1121");
190MODULE_ALIAS("platform:s6d1121");
191
192MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller");
193MODULE_AUTHOR("Roman Rolinsky");
194MODULE_LICENSE("GPL");