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 fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 112 113 par->fbtftops.reset(par); 114 115 if (par->gpio.cs != -1) 116 gpio_set_value(par->gpio.cs, 0); /* Activate chip */ 117 118 write_reg(par, CMD_SWRESET); /* software reset */ 119 mdelay(500); 120 write_reg(par, CMD_SLPOUT); /* exit sleep */ 121 mdelay(5); 122 write_reg(par, CMD_PIXFMT, 0x05); /* Set Color Format 16bit */ 123 write_reg(par, CMD_GAMMASET, 0x02); /* default gamma curve 3 */ 124#ifdef GAMMA_ADJ 125 write_reg(par, CMD_GAMRSEL, 0x01); /* Enable Gamma adj */ 126#endif 127 write_reg(par, CMD_NORML); 128 write_reg(par, CMD_DFUNCTR, 0xff, 0x06); 129 /* Frame Rate Control (In normal mode/Full colors) */ 130 write_reg(par, CMD_FRMCTR1, 0x08, 0x02); 131 write_reg(par, CMD_DINVCTR, 0x07); /* display inversion */ 132 /* Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD */ 133 write_reg(par, CMD_PWCTR1, 0x0A, 0x02); 134 /* Set BT[2:0] for AVDD & VCL & VGH & VGL */ 135 write_reg(par, CMD_PWCTR2, 0x02); 136 /* Set VMH[6:0] & VML[6:0] for VOMH & VCOML */ 137 write_reg(par, CMD_VCOMCTR1, 0x50, 0x63); 138 write_reg(par, CMD_VCOMOFFS, 0); 139 140 write_reg(par, CMD_CLMADRS, 0, 0, 0, WIDTH); /* Set Column Address */ 141 write_reg(par, CMD_PGEADRS, 0, 0, 0, HEIGHT); /* Set Page Address */ 142 143 write_reg(par, CMD_DISPON); /* display ON */ 144 write_reg(par, CMD_RAMWR); /* Memory Write */ 145 146 return 0; 147} 148 149static void set_addr_win(struct fbtft_par *par, int xs, int ys, 150 int xe, int ye) 151{ 152 fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, 153 "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye); 154 155 switch (par->info->var.rotate) { 156 case 0: 157 write_reg(par, CMD_CLMADRS, xs >> 8, xs & 0xff, xe >> 8, 158 xe & 0xff); 159 write_reg(par, CMD_PGEADRS, 160 (ys + __OFFSET) >> 8, (ys + __OFFSET) & 0xff, 161 (ye + __OFFSET) >> 8, (ye + __OFFSET) & 0xff); 162 break; 163 case 90: 164 write_reg(par, CMD_CLMADRS, 165 (xs + __OFFSET) >> 8, (xs + __OFFSET) & 0xff, 166 (xe + __OFFSET) >> 8, (xe + __OFFSET) & 0xff); 167 write_reg(par, CMD_PGEADRS, ys >> 8, ys & 0xff, ye >> 8, 168 ye & 0xff); 169 break; 170 case 180: 171 case 270: 172 write_reg(par, CMD_CLMADRS, xs >> 8, xs & 0xff, xe >> 8, 173 xe & 0xff); 174 write_reg(par, CMD_PGEADRS, ys >> 8, ys & 0xff, ye >> 8, 175 ye & 0xff); 176 break; 177 default: 178 par->info->var.rotate = 0; /* Fix incorrect setting */ 179 } 180 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */ 181} 182 183/* 1847) MY: 1(bottom to top), 0(top to bottom) Row Address Order 1856) MX: 1(R to L), 0(L to R) Column Address Order 1865) MV: 1(Exchanged), 0(normal) Row/Column exchange 1874) ML: 1(bottom to top), 0(top to bottom) Vertical Refresh Order 1883) RGB: 1(BGR), 0(RGB) Color Space 1892) MH: 1(R to L), 0(L to R) Horizontal Refresh Order 1901) 1910) 192 193 MY, MX, MV, ML,RGB, MH, D1, D0 194 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //normal 195 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 //Y-Mirror 196 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Mirror 197 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 //X-Y-Mirror 198 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange 199 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 //X-Y Exchange, Y-Mirror 200 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 //XY exchange 201 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 202*/ 203static int set_var(struct fbtft_par *par) 204{ 205 u8 mactrl_data = 0; /* Avoid compiler warning */ 206 207 fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 208 209 switch (par->info->var.rotate) { 210 case 0: 211 mactrl_data = 0x08; 212 break; 213 case 180: 214 mactrl_data = 0xC8; 215 break; 216 case 270: 217 mactrl_data = 0xA8; 218 break; 219 case 90: 220 mactrl_data = 0x68; 221 break; 222 } 223 224 /* Colorspcae */ 225 if (par->bgr) 226 mactrl_data |= (1 << 2); 227 write_reg(par, CMD_MADCTL, mactrl_data); 228 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */ 229 return 0; 230} 231 232#ifdef GAMMA_ADJ 233#define CURVE(num, idx) curves[num*par->gamma.num_values + idx] 234static int gamma_adj(struct fbtft_par *par, unsigned long *curves) 235{ 236 unsigned long mask[] = { 237 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 238 0x1f, 0x3f, 0x0f, 0x0f, 0x7f, 0x1f, 239 0x3F, 0x3F, 0x3F, 0x3F, 0x3F}; 240 int i, j; 241 242 fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); 243 244 for (i = 0; i < GAMMA_NUM; i++) 245 for (j = 0; j < GAMMA_LEN; j++) 246 CURVE(i, j) &= mask[i*par->gamma.num_values + j]; 247 248 write_reg(par, CMD_PGAMMAC, 249 CURVE(0, 0), 250 CURVE(0, 1), 251 CURVE(0, 2), 252 CURVE(0, 3), 253 CURVE(0, 4), 254 CURVE(0, 5), 255 CURVE(0, 6), 256 (CURVE(0, 7) << 4) | CURVE(0, 8), 257 CURVE(0, 9), 258 CURVE(0, 10), 259 CURVE(0, 11), 260 CURVE(0, 12), 261 CURVE(0, 13), 262 CURVE(0, 14), 263 CURVE(0, 15) 264 ); 265 266 write_reg(par, CMD_RAMWR); /* Write Data to GRAM mode */ 267 268 return 0; 269} 270#undef CURVE 271#endif 272 273static struct fbtft_display display = { 274 .regwidth = 8, 275 .width = WIDTH, 276 .height = HEIGHT, 277 .bpp = BPP, 278 .fps = FPS, 279#ifdef GAMMA_ADJ 280 .gamma_num = GAMMA_NUM, 281 .gamma_len = GAMMA_LEN, 282 .gamma = DEFAULT_GAMMA, 283#endif 284 .fbtftops = { 285 .init_display = init_display, 286 .set_addr_win = set_addr_win, 287 .set_var = set_var, 288#ifdef GAMMA_ADJ 289 .set_gamma = gamma_adj, 290#endif 291 }, 292}; 293 294FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9163", &display); 295 296MODULE_ALIAS("spi:" DRVNAME); 297MODULE_ALIAS("platform:" DRVNAME); 298MODULE_ALIAS("spi:ili9163"); 299MODULE_ALIAS("platform:ili9163"); 300 301MODULE_DESCRIPTION("FB driver for the ILI9163 LCD Controller"); 302MODULE_AUTHOR("Kozhevnikov Anatoly"); 303MODULE_LICENSE("GPL"); 304