Merge tag 'samsung-defconfig-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / staging / fbtft / fb_ili9163.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * FB driver for the ILI9163 LCD Controller
4  *
5  * Copyright (C) 2015 Kozhevnikov Anatoly
6  *
7  * Based on ili9325.c by Noralf Tronnes and
8  * .S.U.M.O.T.O.Y. by Max MC Costa (https://github.com/sumotoy/TFT_ILI9163C).
9  */
10
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/delay.h>
16 #include <video/mipi_display.h>
17
18 #include "fbtft.h"
19
20 #define DRVNAME         "fb_ili9163"
21 #define WIDTH           128
22 #define HEIGHT          128
23 #define BPP             16
24 #define FPS             30
25
26 #ifdef GAMMA_ADJ
27 #define GAMMA_LEN       15
28 #define GAMMA_NUM       1
29 #define DEFAULT_GAMMA   "36 29 12 22 1C 15 42 B7 2F 13 12 0A 11 0B 06\n"
30 #endif
31
32 /* ILI9163C commands */
33 #define CMD_FRMCTR1     0xB1 /* Frame Rate Control */
34                              /* (In normal mode/Full colors) */
35 #define CMD_FRMCTR2     0xB2 /* Frame Rate Control (In Idle mode/8-colors) */
36 #define CMD_FRMCTR3     0xB3 /* Frame Rate Control */
37                              /* (In Partial mode/full colors) */
38 #define CMD_DINVCTR     0xB4 /* Display Inversion Control */
39 #define CMD_RGBBLK      0xB5 /* RGB Interface Blanking Porch setting */
40 #define CMD_DFUNCTR     0xB6 /* Display Function set 5 */
41 #define CMD_SDRVDIR     0xB7 /* Source Driver Direction Control */
42 #define CMD_GDRVDIR     0xB8 /* Gate Driver Direction Control  */
43
44 #define CMD_PWCTR1      0xC0 /* Power_Control1 */
45 #define CMD_PWCTR2      0xC1 /* Power_Control2 */
46 #define CMD_PWCTR3      0xC2 /* Power_Control3 */
47 #define CMD_PWCTR4      0xC3 /* Power_Control4 */
48 #define CMD_PWCTR5      0xC4 /* Power_Control5 */
49 #define CMD_VCOMCTR1    0xC5 /* VCOM_Control 1 */
50 #define CMD_VCOMCTR2    0xC6 /* VCOM_Control 2 */
51 #define CMD_VCOMOFFS    0xC7 /* VCOM Offset Control */
52 #define CMD_PGAMMAC     0xE0 /* Positive Gamma Correction Setting */
53 #define CMD_NGAMMAC     0xE1 /* Negative Gamma Correction Setting */
54 #define CMD_GAMRSEL     0xF2 /* GAM_R_SEL */
55
56 /*
57  * This display:
58  * http://www.ebay.com/itm/Replace-Nokia-5110-LCD-1-44-Red-Serial-128X128-SPI-
59  * Color-TFT-LCD-Display-Module-/271422122271
60  * This particular display has a design error! The controller has 3 pins to
61  * configure to constrain the memory and resolution to a fixed dimension (in
62  * that case 128x128) but they leaved those pins configured for 128x160 so
63  * there was several pixel memory addressing problems.
64  * I solved by setup several parameters that dinamically fix the resolution as
65  * needit so below the parameters for this display. If you have a strain or a
66  * correct display (can happen with chinese) you can copy those parameters and
67  * create setup for different displays.
68  */
69
70 #ifdef RED
71 #define __OFFSET                32 /*see note 2 - this is the red version */
72 #else
73 #define __OFFSET                0  /*see note 2 - this is the black version */
74 #endif
75
76 static int init_display(struct fbtft_par *par)
77 {
78         par->fbtftops.reset(par);
79
80         if (par->gpio.cs)
81                 gpiod_set_value(par->gpio.cs, 0);  /* Activate chip */
82
83         write_reg(par, MIPI_DCS_SOFT_RESET); /* software reset */
84         mdelay(500);
85         write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); /* exit sleep */
86         mdelay(5);
87         write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
88         /* default gamma curve 3 */
89         write_reg(par, MIPI_DCS_SET_GAMMA_CURVE, 0x02);
90 #ifdef GAMMA_ADJ
91         write_reg(par, CMD_GAMRSEL, 0x01); /* Enable Gamma adj */
92 #endif
93         write_reg(par, MIPI_DCS_ENTER_NORMAL_MODE);
94         write_reg(par, CMD_DFUNCTR, 0xff, 0x06);
95         /* Frame Rate Control (In normal mode/Full colors) */
96         write_reg(par, CMD_FRMCTR1, 0x08, 0x02);
97         write_reg(par, CMD_DINVCTR, 0x07); /* display inversion  */
98         /* Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD */
99         write_reg(par, CMD_PWCTR1, 0x0A, 0x02);
100         /* Set BT[2:0] for AVDD & VCL & VGH & VGL  */
101         write_reg(par, CMD_PWCTR2, 0x02);
102         /* Set VMH[6:0] & VML[6:0] for VOMH & VCOML */
103         write_reg(par, CMD_VCOMCTR1, 0x50, 0x63);
104         write_reg(par, CMD_VCOMOFFS, 0);
105
106         write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0, 0, WIDTH);
107         write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0, 0, HEIGHT);
108
109         write_reg(par, MIPI_DCS_SET_DISPLAY_ON); /* display ON */
110         write_reg(par, MIPI_DCS_WRITE_MEMORY_START); /* Memory Write */
111
112         return 0;
113 }
114
115 static void set_addr_win(struct fbtft_par *par, int xs, int ys,
116                          int xe, int ye)
117 {
118         switch (par->info->var.rotate) {
119         case 0:
120                 write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
121                           xs >> 8, xs & 0xff, xe >> 8, xe & 0xff);
122                 write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
123                           (ys + __OFFSET) >> 8, (ys + __OFFSET) & 0xff,
124                           (ye + __OFFSET) >> 8, (ye + __OFFSET) & 0xff);
125                 break;
126         case 90:
127                 write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
128                           (xs + __OFFSET) >> 8, (xs + __OFFSET) & 0xff,
129                           (xe + __OFFSET) >> 8, (xe + __OFFSET) & 0xff);
130                 write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
131                           ys >> 8, ys & 0xff, ye >> 8, ye & 0xff);
132                 break;
133         case 180:
134         case 270:
135                 write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
136                           xs >> 8, xs & 0xff, xe >> 8, xe & 0xff);
137                 write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
138                           ys >> 8, ys & 0xff, ye >> 8, ye & 0xff);
139                 break;
140         default:
141                 /* Fix incorrect setting */
142                 par->info->var.rotate = 0;
143         }
144         write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
145 }
146
147 /*
148  * 7) MY:  1(bottom to top),    0(top to bottom)    Row Address Order
149  * 6) MX:  1(R to L),           0(L to R)           Column Address Order
150  * 5) MV:  1(Exchanged),        0(normal)           Row/Column exchange
151  * 4) ML:  1(bottom to top),    0(top to bottom)    Vertical Refresh Order
152  * 3) RGB: 1(BGR),              0(RGB)              Color Space
153  * 2) MH:  1(R to L),           0(L to R)           Horizontal Refresh Order
154  * 1)
155  * 0)
156  *
157  *      MY, MX, MV, ML,RGB, MH, D1, D0
158  *      0 | 0 | 0 | 0 | 1 | 0 | 0 | 0   //normal
159  *      1 | 0 | 0 | 0 | 1 | 0 | 0 | 0   //Y-Mirror
160  *      0 | 1 | 0 | 0 | 1 | 0 | 0 | 0   //X-Mirror
161  *      1 | 1 | 0 | 0 | 1 | 0 | 0 | 0   //X-Y-Mirror
162  *      0 | 0 | 1 | 0 | 1 | 0 | 0 | 0   //X-Y Exchange
163  *      1 | 0 | 1 | 0 | 1 | 0 | 0 | 0   //X-Y Exchange, Y-Mirror
164  *      0 | 1 | 1 | 0 | 1 | 0 | 0 | 0   //XY exchange
165  *      1 | 1 | 1 | 0 | 1 | 0 | 0 | 0
166  */
167 static int set_var(struct fbtft_par *par)
168 {
169         u8 mactrl_data = 0; /* Avoid compiler warning */
170
171         switch (par->info->var.rotate) {
172         case 0:
173                 mactrl_data = 0x08;
174                 break;
175         case 180:
176                 mactrl_data = 0xC8;
177                 break;
178         case 270:
179                 mactrl_data = 0xA8;
180                 break;
181         case 90:
182                 mactrl_data = 0x68;
183                 break;
184         }
185
186         /* Colorspcae */
187         if (par->bgr)
188                 mactrl_data |= BIT(2);
189         write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, mactrl_data);
190         write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
191         return 0;
192 }
193
194 #ifdef GAMMA_ADJ
195 #define CURVE(num, idx)  curves[(num) * par->gamma.num_values + (idx)]
196 static int gamma_adj(struct fbtft_par *par, u32 *curves)
197 {
198         unsigned long mask[] = {
199                 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
200                 0x1f, 0x3f, 0x0f, 0x0f, 0x7f, 0x1f,
201                 0x3F, 0x3F, 0x3F, 0x3F, 0x3F};
202         int i, j;
203
204         for (i = 0; i < GAMMA_NUM; i++)
205                 for (j = 0; j < GAMMA_LEN; j++)
206                         CURVE(i, j) &= mask[i * par->gamma.num_values + j];
207
208         write_reg(par, CMD_PGAMMAC,
209                   CURVE(0, 0),
210                   CURVE(0, 1),
211                   CURVE(0, 2),
212                   CURVE(0, 3),
213                   CURVE(0, 4),
214                   CURVE(0, 5),
215                   CURVE(0, 6),
216                   (CURVE(0, 7) << 4) | CURVE(0, 8),
217                   CURVE(0, 9),
218                   CURVE(0, 10),
219                   CURVE(0, 11),
220                   CURVE(0, 12),
221                   CURVE(0, 13),
222                   CURVE(0, 14),
223                   CURVE(0, 15));
224
225         /* Write Data to GRAM mode */
226         write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
227
228         return 0;
229 }
230
231 #undef CURVE
232 #endif
233
234 static struct fbtft_display display = {
235         .regwidth = 8,
236         .width = WIDTH,
237         .height = HEIGHT,
238         .bpp = BPP,
239         .fps = FPS,
240 #ifdef GAMMA_ADJ
241         .gamma_num = GAMMA_NUM,
242         .gamma_len = GAMMA_LEN,
243         .gamma = DEFAULT_GAMMA,
244 #endif
245         .fbtftops = {
246                 .init_display = init_display,
247                 .set_addr_win = set_addr_win,
248                 .set_var = set_var,
249 #ifdef GAMMA_ADJ
250                 .set_gamma = gamma_adj,
251 #endif
252         },
253 };
254
255 FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9163", &display);
256
257 MODULE_ALIAS("spi:" DRVNAME);
258 MODULE_ALIAS("platform:" DRVNAME);
259 MODULE_ALIAS("spi:ili9163");
260 MODULE_ALIAS("platform:ili9163");
261
262 MODULE_DESCRIPTION("FB driver for the ILI9163 LCD Controller");
263 MODULE_AUTHOR("Kozhevnikov Anatoly");
264 MODULE_LICENSE("GPL");