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 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 */ 25 26#include <linux/module.h> 27#include <linux/kernel.h> 28#include <linux/init.h> 29#include <linux/vmalloc.h> 30#include <linux/spi/spi.h> 31#include <linux/delay.h> 32 33#include "fbtft.h" 34 35#define DRVNAME "fb_hx8340bn" 36#define WIDTH 176 37#define HEIGHT 220 38#define TXBUFLEN (4 * PAGE_SIZE) 39#define DEFAULT_GAMMA "1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \ 40 "3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 " 41 42 43static bool emulate; 44module_param(emulate, bool, 0); 45MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode"); 46 47 48static int init_display(struct fbtft_par *par) 49{ 50 par->fbtftops.reset(par); 51 52 /* BTL221722-276L startup sequence, from datasheet */ 53 54 /* SETEXTCOM: Set extended command set (C1h) 55 This command is used to set extended command set access enable. 56 Enable: After command (C1h), must write: ffh,83h,40h */ 57 write_reg(par, 0xC1, 0xFF, 0x83, 0x40); 58 59 /* Sleep out 60 This command turns off sleep mode. 61 In this mode the DC/DC converter is enabled, Internal oscillator 62 is started, and panel scanning is started. */ 63 write_reg(par, 0x11); 64 mdelay(150); 65 66 /* Undoc'd register? */ 67 write_reg(par, 0xCA, 0x70, 0x00, 0xD9); 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 write_reg(par, 0xB0, 0x01, 0x11); 74 75 /* Drive ability setting */ 76 write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06); 77 mdelay(20); 78 79 /* SETPWCTR5: Set Power Control 5(B5h) 80 This command is used to set VCOM Low and VCOM High Voltage */ 81 /* VCOMH 0110101 : 3.925 */ 82 /* VCOML 0100000 : -1.700 */ 83 /* 45h=69 VCOMH: "VMH" + 5d VCOML: "VMH" + 5d */ 84 write_reg(par, 0xB5, 0x35, 0x20, 0x45); 85 86 /* SETPWCTR4: Set Power Control 4(B4h) 87 VRH[4:0]: Specify the VREG1 voltage adjusting. 88 VREG1 voltage is for gamma voltage setting. 89 BT[2:0]: Switch the output factor of step-up circuit 2 90 for VGH and VGL voltage generation. */ 91 write_reg(par, 0xB4, 0x33, 0x25, 0x4C); 92 mdelay(10); 93 94 /* Interface Pixel Format (3Ah) 95 This command is used to define the format of RGB picture data, 96 which is to be transfer via the system and RGB interface. */ 97 /* RGB interface: 16 Bit/Pixel */ 98 write_reg(par, 0x3A, 0x05); 99 100 /* Display on (29h) 101 This command is used to recover from DISPLAY OFF mode. 102 Output from the Frame Memory is enabled. */ 103 write_reg(par, 0x29); 104 mdelay(10); 105 106 return 0; 107} 108 109static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 110{ 111 write_reg(par, FBTFT_CASET, 0x00, xs, 0x00, xe); 112 write_reg(par, FBTFT_RASET, 0x00, ys, 0x00, ye); 113 write_reg(par, FBTFT_RAMWR); 114} 115 116static int set_var(struct fbtft_par *par) 117{ 118 /* MADCTL - Memory data access control */ 119 /* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */ 120#define MY (1 << 7) 121#define MX (1 << 6) 122#define MV (1 << 5) 123 switch (par->info->var.rotate) { 124 case 0: 125 write_reg(par, 0x36, par->bgr << 3); 126 break; 127 case 270: 128 write_reg(par, 0x36, MX | MV | (par->bgr << 3)); 129 break; 130 case 180: 131 write_reg(par, 0x36, MX | MY | (par->bgr << 3)); 132 break; 133 case 90: 134 write_reg(par, 0x36, MY | MV | (par->bgr << 3)); 135 break; 136 } 137 138 return 0; 139} 140 141/* 142 Gamma Curve selection, GC (only GC0 can be customized): 143 0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0 144 Gamma string format: 145 OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1 146 ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX GC 147*/ 148#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 149static int set_gamma(struct fbtft_par *par, unsigned long *curves) 150{ 151 unsigned long mask[] = { 152 0x0f, 0x0f, 0x1f, 0x0f, 0x0f, 0x0f, 0x1f, 0x07, 0x07, 0x07, 153 0x07, 0x07, 0x07, 0x03, 0x03, 0x0f, 0x0f, 0x1f, 0x0f, 0x0f, 154 0x0f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x00, 0x00, 155 }; 156 int i, j; 157 158 /* apply mask */ 159 for (i = 0; i < par->gamma.num_curves; i++) 160 for (j = 0; j < par->gamma.num_values; j++) 161 CURVE(i, j) &= mask[i * par->gamma.num_values + j]; 162 163 write_reg(par, 0x26, 1 << CURVE(1, 14)); /* Gamma Set (26h) */ 164 165 if (CURVE(1, 14)) 166 return 0; /* only GC0 can be customized */ 167 168 write_reg(par, 0xC2, 169 (CURVE(0, 8) << 4) | CURVE(0, 7), 170 (CURVE(0, 10) << 4) | CURVE(0, 9), 171 (CURVE(0, 12) << 4) | CURVE(0, 11), 172 CURVE(0, 2), 173 (CURVE(0, 4) << 4) | CURVE(0, 3), 174 CURVE(0, 5), 175 CURVE(0, 6), 176 (CURVE(0, 1) << 4) | CURVE(0, 0), 177 (CURVE(0, 14) << 2) | CURVE(0, 13)); 178 179 write_reg(par, 0xC3, 180 (CURVE(1, 8) << 4) | CURVE(1, 7), 181 (CURVE(1, 10) << 4) | CURVE(1, 9), 182 (CURVE(1, 12) << 4) | CURVE(1, 11), 183 CURVE(1, 2), 184 (CURVE(1, 4) << 4) | CURVE(1, 3), 185 CURVE(1, 5), 186 CURVE(1, 6), 187 (CURVE(1, 1) << 4) | CURVE(1, 0)); 188 189 mdelay(10); 190 191 return 0; 192} 193#undef CURVE 194 195 196static struct fbtft_display display = { 197 .regwidth = 8, 198 .width = WIDTH, 199 .height = HEIGHT, 200 .txbuflen = TXBUFLEN, 201 .gamma_num = 2, 202 .gamma_len = 15, 203 .gamma = DEFAULT_GAMMA, 204 .fbtftops = { 205 .init_display = init_display, 206 .set_addr_win = set_addr_win, 207 .set_var = set_var, 208 .set_gamma = set_gamma, 209 }, 210}; 211FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display); 212 213MODULE_ALIAS("spi:" DRVNAME); 214MODULE_ALIAS("platform:" DRVNAME); 215MODULE_ALIAS("spi:hx8340bn"); 216MODULE_ALIAS("platform:hx8340bn"); 217 218MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller"); 219MODULE_AUTHOR("Noralf Tronnes"); 220MODULE_LICENSE("GPL"); 221