• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * FB driver for the HX8340BN LCD Controller
3  *
4  * This display uses 9-bit SPI: Data/Command bit + 8 data bits
5  * For platforms that doesn't support 9-bit, the driver is capable
6  * of emulating this using 8-bit transfer.
7  * This is done by transferring eight 9-bit words in 9 bytes.
8  *
9  * Copyright (C) 2013 Noralf Tronnes
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  */
21 
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/init.h>
25 #include <linux/vmalloc.h>
26 #include <linux/spi/spi.h>
27 #include <linux/delay.h>
28 #include <video/mipi_display.h>
29 
30 #include "fbtft.h"
31 
32 #define DRVNAME		"fb_hx8340bn"
33 #define WIDTH		176
34 #define HEIGHT		220
35 #define TXBUFLEN	(4 * PAGE_SIZE)
36 #define DEFAULT_GAMMA	"1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \
37 			"3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 "
38 
39 static bool emulate;
40 module_param(emulate, bool, 0000);
41 MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode");
42 
init_display(struct fbtft_par * par)43 static int init_display(struct fbtft_par *par)
44 {
45 	par->fbtftops.reset(par);
46 
47 	/* BTL221722-276L startup sequence, from datasheet */
48 
49 	/*
50 	 * SETEXTCOM: Set extended command set (C1h)
51 	 * This command is used to set extended command set access enable.
52 	 * Enable: After command (C1h), must write: ffh,83h,40h
53 	 */
54 	write_reg(par, 0xC1, 0xFF, 0x83, 0x40);
55 
56 	/*
57 	 * Sleep out
58 	 * This command turns off sleep mode.
59 	 * In this mode the DC/DC converter is enabled, Internal oscillator
60 	 * is started, and panel scanning is started.
61 	 */
62 	write_reg(par, 0x11);
63 	mdelay(150);
64 
65 	/* Undoc'd register? */
66 	write_reg(par, 0xCA, 0x70, 0x00, 0xD9);
67 
68 	/*
69 	 * SETOSC: Set Internal Oscillator (B0h)
70 	 * This command is used to set internal oscillator related settings
71 	 *	OSC_EN: Enable internal oscillator
72 	 *	Internal oscillator frequency: 125% x 2.52MHz
73 	 */
74 	write_reg(par, 0xB0, 0x01, 0x11);
75 
76 	/* Drive ability setting */
77 	write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06);
78 	mdelay(20);
79 
80 	/*
81 	 * SETPWCTR5: Set Power Control 5(B5h)
82 	 * This command is used to set VCOM Low and VCOM High Voltage
83 	 * VCOMH 0110101 :  3.925
84 	 * VCOML 0100000 : -1.700
85 	 * 45h=69  VCOMH: "VMH" + 5d   VCOML: "VMH" + 5d
86 	 */
87 	write_reg(par, 0xB5, 0x35, 0x20, 0x45);
88 
89 	/*
90 	 * SETPWCTR4: Set Power Control 4(B4h)
91 	 *	VRH[4:0]:	Specify the VREG1 voltage adjusting.
92 	 *			VREG1 voltage is for gamma voltage setting.
93 	 *	BT[2:0]:	Switch the output factor of step-up circuit 2
94 	 *			for VGH and VGL voltage generation.
95 	 */
96 	write_reg(par, 0xB4, 0x33, 0x25, 0x4C);
97 	mdelay(10);
98 
99 	/*
100 	 * Interface Pixel Format (3Ah)
101 	 * This command is used to define the format of RGB picture data,
102 	 * which is to be transfer via the system and RGB interface.
103 	 * RGB interface: 16 Bit/Pixel
104 	 */
105 	write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
106 
107 	/*
108 	 * Display on (29h)
109 	 * This command is used to recover from DISPLAY OFF mode.
110 	 * Output from the Frame Memory is enabled.
111 	 */
112 	write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
113 	mdelay(10);
114 
115 	return 0;
116 }
117 
set_addr_win(struct fbtft_par * par,int xs,int ys,int xe,int ye)118 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
119 {
120 	write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, 0x00, xs, 0x00, xe);
121 	write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, 0x00, ys, 0x00, ye);
122 	write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
123 }
124 
set_var(struct fbtft_par * par)125 static int set_var(struct fbtft_par *par)
126 {
127 	/* MADCTL - Memory data access control */
128 	/* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */
129 #define MY BIT(7)
130 #define MX BIT(6)
131 #define MV BIT(5)
132 	switch (par->info->var.rotate) {
133 	case 0:
134 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, par->bgr << 3);
135 		break;
136 	case 270:
137 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
138 			  MX | MV | (par->bgr << 3));
139 		break;
140 	case 180:
141 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
142 			  MX | MY | (par->bgr << 3));
143 		break;
144 	case 90:
145 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
146 			  MY | MV | (par->bgr << 3));
147 		break;
148 	}
149 
150 	return 0;
151 }
152 
153 /*
154  * Gamma Curve selection, GC (only GC0 can be customized):
155  *   0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0
156  * Gamma string format:
157  *   OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1
158  *   ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX  GC
159  */
160 #define CURVE(num, idx)  curves[(num) * par->gamma.num_values + (idx)]
set_gamma(struct fbtft_par * par,u32 * curves)161 static int set_gamma(struct fbtft_par *par, u32 *curves)
162 {
163 	unsigned long mask[] = {
164 		0x0f, 0x0f, 0x1f, 0x0f, 0x0f, 0x0f, 0x1f, 0x07, 0x07, 0x07,
165 		0x07, 0x07, 0x07, 0x03, 0x03, 0x0f, 0x0f, 0x1f, 0x0f, 0x0f,
166 		0x0f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00,
167 	};
168 	int i, j;
169 
170 	/* apply mask */
171 	for (i = 0; i < par->gamma.num_curves; i++)
172 		for (j = 0; j < par->gamma.num_values; j++)
173 			CURVE(i, j) &= mask[i * par->gamma.num_values + j];
174 
175 	/* Gamma Set (26h) */
176 	write_reg(par, MIPI_DCS_SET_GAMMA_CURVE, 1 << CURVE(1, 14));
177 
178 	if (CURVE(1, 14))
179 		return 0; /* only GC0 can be customized */
180 
181 	write_reg(par, 0xC2,
182 		  (CURVE(0, 8) << 4) | CURVE(0, 7),
183 		  (CURVE(0, 10) << 4) | CURVE(0, 9),
184 		  (CURVE(0, 12) << 4) | CURVE(0, 11),
185 		  CURVE(0, 2),
186 		  (CURVE(0, 4) << 4) | CURVE(0, 3),
187 		  CURVE(0, 5),
188 		  CURVE(0, 6),
189 		  (CURVE(0, 1) << 4) | CURVE(0, 0),
190 		  (CURVE(0, 14) << 2) | CURVE(0, 13));
191 
192 	write_reg(par, 0xC3,
193 		  (CURVE(1, 8) << 4) | CURVE(1, 7),
194 		  (CURVE(1, 10) << 4) | CURVE(1, 9),
195 		  (CURVE(1, 12) << 4) | CURVE(1, 11),
196 		  CURVE(1, 2),
197 		  (CURVE(1, 4) << 4) | CURVE(1, 3),
198 		  CURVE(1, 5),
199 		  CURVE(1, 6),
200 		  (CURVE(1, 1) << 4) | CURVE(1, 0));
201 
202 	mdelay(10);
203 
204 	return 0;
205 }
206 
207 #undef CURVE
208 
209 static struct fbtft_display display = {
210 	.regwidth = 8,
211 	.width = WIDTH,
212 	.height = HEIGHT,
213 	.txbuflen = TXBUFLEN,
214 	.gamma_num = 2,
215 	.gamma_len = 15,
216 	.gamma = DEFAULT_GAMMA,
217 	.fbtftops = {
218 		.init_display = init_display,
219 		.set_addr_win = set_addr_win,
220 		.set_var = set_var,
221 		.set_gamma = set_gamma,
222 	},
223 };
224 
225 FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display);
226 
227 MODULE_ALIAS("spi:" DRVNAME);
228 MODULE_ALIAS("platform:" DRVNAME);
229 MODULE_ALIAS("spi:hx8340bn");
230 MODULE_ALIAS("platform:hx8340bn");
231 
232 MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller");
233 MODULE_AUTHOR("Noralf Tronnes");
234 MODULE_LICENSE("GPL");
235