1/* 2 * FB driver for the ILI9163 LCD Controller 3 * 4 * Copyright (C) 2015 Kozhevnikov Anatoly 5 * 6 * Based on ili9325.c by Noralf Tronnes and 7 * .S.U.M.O.T.O.Y. by Max MC Costa (https://github.com/sumotoy/TFT_ILI9163C). 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20#include <linux/module.h> 21#include <linux/kernel.h> 22#include <linux/init.h> 23#include <linux/gpio.h> 24#include <linux/delay.h> 25 26#include "fbtft.h" 27 28#define DRVNAME "fb_ili9163" 29#define WIDTH 128 30#define HEIGHT 128 31#define BPP 16 32#define FPS 30 33 34#ifdef GAMMA_ADJ 35#define GAMMA_LEN 15 36#define GAMMA_NUM 1 37#define DEFAULT_GAMMA "36 29 12 22 1C 15 42 B7 2F 13 12 0A 11 0B 06\n" 38#endif 39 40/* ILI9163C commands */ 41#define CMD_NOP 0x00 /* Non operation*/ 42#define CMD_SWRESET 0x01 /* Soft Reset */ 43#define CMD_SLPIN 0x10 /* Sleep ON */ 44#define CMD_SLPOUT 0x11 /* Sleep OFF */ 45#define CMD_PTLON 0x12 /* Partial Mode ON */ 46#define CMD_NORML 0x13 /* Normal Display ON */ 47#define CMD_DINVOF 0x20 /* Display Inversion OFF */ 48#define CMD_DINVON 0x21 /* Display Inversion ON */ 49#define CMD_GAMMASET 0x26 /* Gamma Set (0x01[1],0x02[2],0x04[3],0x08[4]) */ 50#define CMD_DISPOFF 0x28 /* Display OFF */ 51#define CMD_DISPON 0x29 /* Display ON */ 52#define CMD_IDLEON 0x39 /* Idle Mode ON */ 53#define CMD_IDLEOF 0x38 /* Idle Mode OFF */ 54#define CMD_CLMADRS 0x2A /* Column Address Set */ 55#define CMD_PGEADRS 0x2B /* Page Address Set */ 56 57#define CMD_RAMWR 0x2C /* Memory Write */ 58#define CMD_RAMRD 0x2E /* Memory Read */ 59#define CMD_CLRSPACE 0x2D /* Color Space : 4K/65K/262K */ 60#define CMD_PARTAREA 0x30 /* Partial Area */ 61#define CMD_VSCLLDEF 0x33 /* Vertical Scroll Definition */ 62#define CMD_TEFXLON 0x34 /* Tearing Effect Line ON */ 63#define CMD_TEFXLOF 0x35 /* Tearing Effect Line OFF */ 64#define CMD_MADCTL 0x36 /* Memory Access Control */ 65 66#define CMD_PIXFMT 0x3A /* Interface Pixel Format */ 67#define CMD_FRMCTR1 0xB1 /* Frame Rate Control 68 (In normal mode/Full colors) */ 69#define CMD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle mode/8-colors) */ 70#define CMD_FRMCTR3 0xB3 /* Frame Rate Control 71 (In Partial mode/full colors) */ 72#define CMD_DINVCTR 0xB4 /* Display Inversion Control */ 73#define CMD_RGBBLK 0xB5 /* RGB Interface Blanking Porch setting */ 74#define CMD_DFUNCTR 0xB6 /* Display Function set 5 */ 75#define CMD_SDRVDIR 0xB7 /* Source Driver Direction Control */ 76#define CMD_GDRVDIR 0xB8 /* Gate Driver Direction Control */ 77 78#define CMD_PWCTR1 0xC0 /* Power_Control1 */ 79#define CMD_PWCTR2 0xC1 /* Power_Control2 */ 80#define CMD_PWCTR3 0xC2 /* Power_Control3 */ 81#define CMD_PWCTR4 0xC3 /* Power_Control4 */ 82#define CMD_PWCTR5 0xC4 /* Power_Control5 */ 83#define CMD_VCOMCTR1 0xC5 /* VCOM_Control 1 */ 84#define CMD_VCOMCTR2 0xC6 /* VCOM_Control 2 */ 85#define CMD_VCOMOFFS 0xC7 /* VCOM Offset Control */ 86#define CMD_PGAMMAC 0xE0 /* Positive Gamma Correction Setting */ 87#define CMD_NGAMMAC 0xE1 /* Negative Gamma Correction Setting */ 88#define CMD_GAMRSEL 0xF2 /* GAM_R_SEL */ 89 90/* 91This display: 92http://www.ebay.com/itm/Replace-Nokia-5110-LCD-1-44-Red-Serial-128X128-SPI-Color-TFT-LCD-Display-Module-/271422122271 93This particular display has a design error! The controller has 3 pins to 94configure to constrain the memory and resolution to a fixed dimension (in 95that case 128x128) but they leaved those pins configured for 128x160 so 96there was several pixel memory addressing problems. 97I solved by setup several parameters that dinamically fix the resolution as 98needit so below the parameters for this display. If you have a strain or a 99correct display (can happen with chinese) you can copy those parameters and 100create setup for different displays. 101*/ 102 103#ifdef RED 104#define __OFFSET 32 /*see note 2 - this is the red version */ 105#else 106#define __OFFSET 0 /*see note 2 - this is the black version */ 107#endif 108 109static int init_display(struct fbtft_par *par) 110{ 111 par->fbtftops.reset(par); 112 113 if (par->gpio.cs != -1) 114 gpio_set_value(par->gpio.cs, 0); /* Activate chip */ 115 116 write_reg(par, CMD_SWRESET); /* software reset */ 117 mdelay(500); 118 write_reg(par, CMD_SLPOUT); /* exit sleep */ 119 mdelay(5); 120 write_reg(par, CMD_PIXFMT, 0x05); /* Set Color Format 16bit */ 121 write_reg(par, CMD_GAMMASET, 0x02); /* default gamma curve 3 */ 122#ifdef GAMMA_ADJ 123 write_reg(par, CMD_GAMRSEL, 0x01); /* Enable Gamma adj */ 124#endif 125 write_reg(par, CMD_NORML); 126 write_reg(par, CMD_DFUNCTR, 0xff, 0x06); 127 /* Frame Rate Control (In normal mode/Full colors) */ 128 write_reg(par, CMD_FRMCTR1, 0x08, 0x02); 129 write_reg(par, CMD_DINVCTR, 0x07); /* display inversion */ 130 /* Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD */ 131 write_reg(par, CMD_PWCTR1, 0x0A, 0x02); 132 /* Set BT[2:0] for AVDD & VCL & VGH & VGL */ 133 write_reg(par, CMD_PWCTR2, 0x02); 134 /* Set VMH[6:0] & VML[6:0] for VOMH & VCOML */ 135 write_reg(par, CMD_VCOMCTR1, 0x50, 0x63); 136 write_reg(par, CMD_VCOMOFFS, 0); 137 138 write_reg(par, CMD_CLMADRS, 0, 0, 0, WIDTH); /* Set Column Address */ 139 write_reg(par, CMD_PGEADRS, 0, 0, 0, HEIGHT); /* Set Page Address */ 140 141 write_reg(par, CMD_DISPON); /* display ON */ 142 write_reg(par, CMD_RAMWR); /* Memory Write */ 143 144 return 0; 145} 146 147static void set_addr_win(struct fbtft_par *par, int xs, int ys, 148 int xe, int ye) 149{ 150 switch (par->info->var.rotate) { 151 case 0: 152 write_reg(par, CMD_CLMADRS, xs >> 8, xs & 0xff, xe >> 8, 153 xe & 0xff); 154 write_reg(par, CMD_PGEADRS, 155 (ys + __OFFSET) >> 8, (ys + __OFFSET) & 0xff, 156 (ye + __OFFSET) >> 8, (ye + __OFFSET) & 0xff); 157 break; 158 case 90: 159 write_reg(par, CMD_CLMADRS, 160 (xs + __OFFSET) >> 8, (xs + __OFFSET) & 0xff, 161 (xe + __OFFSET) >> 8, (xe + __OFFSET) & 0xff); 162 write_reg(par, CMD_PGEADRS, ys >> 8, ys & 0xff, ye >> 8, 163 ye & 0xff); 164 break; 165 case 180: 166 case 270: 167 write_reg(par, CMD_CLMADRS, xs >> 8, xs & 0xff, xe >> 8, 168 xe & 0xff); 169 write_reg(par, CMD_PGEADRS, ys >> 8, ys & 0xff, ye >> 8, 170 ye & 0xff); 171 break; 172 default: 173 par->info->var.rotate = 0; /* Fix incorrect setting */ 174 } 175 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */ 176} 177 178/* 1797) MY: 1(bottom to top), 0(top to bottom) Row Address Order 1806) MX: 1(R to L), 0(L to R) Column Address Order 1815) MV: 1(Exchanged), 0(normal) Row/Column exchange 1824) ML: 1(bottom to top), 0(top to bottom) Vertical Refresh Order 1833) RGB: 1(BGR), 0(RGB) Color Space 1842) MH: 1(R to L), 0(L to R) Horizontal Refresh Order 1851) 1860) 187 188 MY, MX, MV, ML,RGB, MH, D1, D0 189 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //normal 190 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //Y-Mirror 191 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Mirror 192 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Y-Mirror 193 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange 194 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange, Y-Mirror 195 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 //XY exchange 196 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 197*/ 198static int set_var(struct fbtft_par *par) 199{ 200 u8 mactrl_data = 0; /* Avoid compiler warning */ 201 202 switch (par->info->var.rotate) { 203 case 0: 204 mactrl_data = 0x08; 205 break; 206 case 180: 207 mactrl_data = 0xC8; 208 break; 209 case 270: 210 mactrl_data = 0xA8; 211 break; 212 case 90: 213 mactrl_data = 0x68; 214 break; 215 } 216 217 /* Colorspcae */ 218 if (par->bgr) 219 mactrl_data |= (1 << 2); 220 write_reg(par, CMD_MADCTL, mactrl_data); 221 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */ 222 return 0; 223} 224 225#ifdef GAMMA_ADJ 226#define CURVE(num, idx) curves[num * par->gamma.num_values + idx] 227static int gamma_adj(struct fbtft_par *par, unsigned long *curves) 228{ 229 unsigned long mask[] = { 230 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 231 0x1f, 0x3f, 0x0f, 0x0f, 0x7f, 0x1f, 232 0x3F, 0x3F, 0x3F, 0x3F, 0x3F}; 233 int i, j; 234 235 for (i = 0; i < GAMMA_NUM; i++) 236 for (j = 0; j < GAMMA_LEN; j++) 237 CURVE(i, j) &= mask[i * par->gamma.num_values + j]; 238 239 write_reg(par, CMD_PGAMMAC, 240 CURVE(0, 0), 241 CURVE(0, 1), 242 CURVE(0, 2), 243 CURVE(0, 3), 244 CURVE(0, 4), 245 CURVE(0, 5), 246 CURVE(0, 6), 247 (CURVE(0, 7) << 4) | CURVE(0, 8), 248 CURVE(0, 9), 249 CURVE(0, 10), 250 CURVE(0, 11), 251 CURVE(0, 12), 252 CURVE(0, 13), 253 CURVE(0, 14), 254 CURVE(0, 15) 255 ); 256 257 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */ 258 259 return 0; 260} 261#undef CURVE 262#endif 263 264static struct fbtft_display display = { 265 .regwidth = 8, 266 .width = WIDTH, 267 .height = HEIGHT, 268 .bpp = BPP, 269 .fps = FPS, 270#ifdef GAMMA_ADJ 271 .gamma_num = GAMMA_NUM, 272 .gamma_len = GAMMA_LEN, 273 .gamma = DEFAULT_GAMMA, 274#endif 275 .fbtftops = { 276 .init_display = init_display, 277 .set_addr_win = set_addr_win, 278 .set_var = set_var, 279#ifdef GAMMA_ADJ 280 .set_gamma = gamma_adj, 281#endif 282 }, 283}; 284 285FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9163", &display); 286 287MODULE_ALIAS("spi:" DRVNAME); 288MODULE_ALIAS("platform:" DRVNAME); 289MODULE_ALIAS("spi:ili9163"); 290MODULE_ALIAS("platform:ili9163"); 291 292MODULE_DESCRIPTION("FB driver for the ILI9163 LCD Controller"); 293MODULE_AUTHOR("Kozhevnikov Anatoly"); 294MODULE_LICENSE("GPL"); 295