1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * FB driver for the S6D1121 LCD Controller 4 * 5 * Copyright (C) 2013 Roman Rolinsky 6 * 7 * Based on fb_ili9325.c by Noralf Tronnes 8 * Based on ili9325.c by Jeroen Domburg 9 * Init code from UTFT library by Henning Karlsen 10 */ 11 12 #include <linux/module.h> 13 #include <linux/kernel.h> 14 #include <linux/init.h> 15 #include <linux/gpio/consumer.h> 16 #include <linux/delay.h> 17 18 #include "fbtft.h" 19 20 #define DRVNAME "fb_s6d1121" 21 #define WIDTH 240 22 #define HEIGHT 320 23 #define BPP 16 24 #define FPS 20 25 #define DEFAULT_GAMMA "26 09 24 2C 1F 23 24 25 22 26 25 23 0D 00\n" \ 26 "1C 1A 13 1D 0B 11 12 10 13 15 36 19 00 0D" 27 28 static int init_display(struct fbtft_par *par) 29 { 30 par->fbtftops.reset(par); 31 32 if (!par->gpio.cs) 33 gpiod_set_value(par->gpio.cs, 0); /* Activate chip */ 34 35 /* Initialization sequence from Lib_UTFT */ 36 37 write_reg(par, 0x0011, 0x2004); 38 write_reg(par, 0x0013, 0xCC00); 39 write_reg(par, 0x0015, 0x2600); 40 write_reg(par, 0x0014, 0x252A); 41 write_reg(par, 0x0012, 0x0033); 42 write_reg(par, 0x0013, 0xCC04); 43 write_reg(par, 0x0013, 0xCC06); 44 write_reg(par, 0x0013, 0xCC4F); 45 write_reg(par, 0x0013, 0x674F); 46 write_reg(par, 0x0011, 0x2003); 47 write_reg(par, 0x0016, 0x0007); 48 write_reg(par, 0x0002, 0x0013); 49 write_reg(par, 0x0003, 0x0003); 50 write_reg(par, 0x0001, 0x0127); 51 write_reg(par, 0x0008, 0x0303); 52 write_reg(par, 0x000A, 0x000B); 53 write_reg(par, 0x000B, 0x0003); 54 write_reg(par, 0x000C, 0x0000); 55 write_reg(par, 0x0041, 0x0000); 56 write_reg(par, 0x0050, 0x0000); 57 write_reg(par, 0x0060, 0x0005); 58 write_reg(par, 0x0070, 0x000B); 59 write_reg(par, 0x0071, 0x0000); 60 write_reg(par, 0x0078, 0x0000); 61 write_reg(par, 0x007A, 0x0000); 62 write_reg(par, 0x0079, 0x0007); 63 write_reg(par, 0x0007, 0x0051); 64 write_reg(par, 0x0007, 0x0053); 65 write_reg(par, 0x0079, 0x0000); 66 67 write_reg(par, 0x0022); /* Write Data to GRAM */ 68 69 return 0; 70 } 71 72 static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) 73 { 74 switch (par->info->var.rotate) { 75 /* R20h = Horizontal GRAM Start Address */ 76 /* R21h = Vertical GRAM Start Address */ 77 case 0: 78 write_reg(par, 0x0020, xs); 79 write_reg(par, 0x0021, ys); 80 break; 81 case 180: 82 write_reg(par, 0x0020, WIDTH - 1 - xs); 83 write_reg(par, 0x0021, HEIGHT - 1 - ys); 84 break; 85 case 270: 86 write_reg(par, 0x0020, WIDTH - 1 - ys); 87 write_reg(par, 0x0021, xs); 88 break; 89 case 90: 90 write_reg(par, 0x0020, ys); 91 write_reg(par, 0x0021, HEIGHT - 1 - xs); 92 break; 93 } 94 write_reg(par, 0x0022); /* Write Data to GRAM */ 95 } 96 97 static int set_var(struct fbtft_par *par) 98 { 99 switch (par->info->var.rotate) { 100 /* AM: GRAM update direction */ 101 case 0: 102 write_reg(par, 0x03, 0x0003 | (par->bgr << 12)); 103 break; 104 case 180: 105 write_reg(par, 0x03, 0x0000 | (par->bgr << 12)); 106 break; 107 case 270: 108 write_reg(par, 0x03, 0x000A | (par->bgr << 12)); 109 break; 110 case 90: 111 write_reg(par, 0x03, 0x0009 | (par->bgr << 12)); 112 break; 113 } 114 115 return 0; 116 } 117 118 /* 119 * Gamma string format: 120 * PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 PKP6 PKP7 PKP8 PKP9 PKP10 PKP11 VRP0 VRP1 121 * PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1 122 */ 123 #define CURVE(num, idx) curves[(num) * par->gamma.num_values + (idx)] 124 static int set_gamma(struct fbtft_par *par, u32 *curves) 125 { 126 unsigned long mask[] = { 127 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 128 0x3f, 0x3f, 0x1f, 0x1f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 129 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x1f, 0x1f, 130 }; 131 int i, j; 132 133 /* apply mask */ 134 for (i = 0; i < 2; i++) 135 for (j = 0; j < 14; j++) 136 CURVE(i, j) &= mask[i * par->gamma.num_values + j]; 137 138 write_reg(par, 0x0030, CURVE(0, 1) << 8 | CURVE(0, 0)); 139 write_reg(par, 0x0031, CURVE(0, 3) << 8 | CURVE(0, 2)); 140 write_reg(par, 0x0032, CURVE(0, 5) << 8 | CURVE(0, 3)); 141 write_reg(par, 0x0033, CURVE(0, 7) << 8 | CURVE(0, 6)); 142 write_reg(par, 0x0034, CURVE(0, 9) << 8 | CURVE(0, 8)); 143 write_reg(par, 0x0035, CURVE(0, 11) << 8 | CURVE(0, 10)); 144 145 write_reg(par, 0x0036, CURVE(1, 1) << 8 | CURVE(1, 0)); 146 write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2)); 147 write_reg(par, 0x0038, CURVE(1, 5) << 8 | CURVE(1, 4)); 148 write_reg(par, 0x0039, CURVE(1, 7) << 8 | CURVE(1, 6)); 149 write_reg(par, 0x003A, CURVE(1, 9) << 8 | CURVE(1, 8)); 150 write_reg(par, 0x003B, CURVE(1, 11) << 8 | CURVE(1, 10)); 151 152 write_reg(par, 0x003C, CURVE(0, 13) << 8 | CURVE(0, 12)); 153 write_reg(par, 0x003D, CURVE(1, 13) << 8 | CURVE(1, 12)); 154 155 return 0; 156 } 157 158 #undef CURVE 159 160 static struct fbtft_display display = { 161 .regwidth = 16, 162 .width = WIDTH, 163 .height = HEIGHT, 164 .bpp = BPP, 165 .fps = FPS, 166 .gamma_num = 2, 167 .gamma_len = 14, 168 .gamma = DEFAULT_GAMMA, 169 .fbtftops = { 170 .init_display = init_display, 171 .set_addr_win = set_addr_win, 172 .set_var = set_var, 173 .set_gamma = set_gamma, 174 }, 175 }; 176 177 FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display); 178 179 MODULE_ALIAS("spi:" DRVNAME); 180 MODULE_ALIAS("platform:" DRVNAME); 181 MODULE_ALIAS("spi:s6d1121"); 182 MODULE_ALIAS("platform:s6d1121"); 183 184 MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller"); 185 MODULE_AUTHOR("Roman Rolinsky"); 186 MODULE_LICENSE("GPL"); 187