1783de57cSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2735d98cdSThomas Petazzoni /*
3735d98cdSThomas Petazzoni  * FB driver for the ST7735R LCD Controller
4735d98cdSThomas Petazzoni  *
5735d98cdSThomas Petazzoni  * Copyright (C) 2013 Noralf Tronnes
6735d98cdSThomas Petazzoni  */
7735d98cdSThomas Petazzoni 
8735d98cdSThomas Petazzoni #include <linux/module.h>
9735d98cdSThomas Petazzoni #include <linux/kernel.h>
10735d98cdSThomas Petazzoni #include <linux/init.h>
1179f5da7dSPriit Laes #include <video/mipi_display.h>
12735d98cdSThomas Petazzoni 
13735d98cdSThomas Petazzoni #include "fbtft.h"
14735d98cdSThomas Petazzoni 
15735d98cdSThomas Petazzoni #define DRVNAME "fb_st7735r"
16735d98cdSThomas Petazzoni #define DEFAULT_GAMMA   "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \
17735d98cdSThomas Petazzoni 			"0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10"
18735d98cdSThomas Petazzoni 
19999c8c28SJoe Perches static const s16 default_init_sequence[] = {
2079f5da7dSPriit Laes 	-1, MIPI_DCS_SOFT_RESET,
21735d98cdSThomas Petazzoni 	-2, 150,                               /* delay */
22735d98cdSThomas Petazzoni 
2379f5da7dSPriit Laes 	-1, MIPI_DCS_EXIT_SLEEP_MODE,
24735d98cdSThomas Petazzoni 	-2, 500,                               /* delay */
25735d98cdSThomas Petazzoni 
26735d98cdSThomas Petazzoni 	/* FRMCTR1 - frame rate control: normal mode
27a4f368dcSAnson Jacob 	 * frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D)
28a4f368dcSAnson Jacob 	 */
29735d98cdSThomas Petazzoni 	-1, 0xB1, 0x01, 0x2C, 0x2D,
30735d98cdSThomas Petazzoni 
31735d98cdSThomas Petazzoni 	/* FRMCTR2 - frame rate control: idle mode
32a4f368dcSAnson Jacob 	 * frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D)
33a4f368dcSAnson Jacob 	 */
34735d98cdSThomas Petazzoni 	-1, 0xB2, 0x01, 0x2C, 0x2D,
35735d98cdSThomas Petazzoni 
36735d98cdSThomas Petazzoni 	/* FRMCTR3 - frame rate control - partial mode
37a4f368dcSAnson Jacob 	 * dot inversion mode, line inversion mode
38a4f368dcSAnson Jacob 	 */
39735d98cdSThomas Petazzoni 	-1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D,
40735d98cdSThomas Petazzoni 
41735d98cdSThomas Petazzoni 	/* INVCTR - display inversion control
42a4f368dcSAnson Jacob 	 * no inversion
43a4f368dcSAnson Jacob 	 */
44735d98cdSThomas Petazzoni 	-1, 0xB4, 0x07,
45735d98cdSThomas Petazzoni 
46735d98cdSThomas Petazzoni 	/* PWCTR1 - Power Control
47a4f368dcSAnson Jacob 	 * -4.6V, AUTO mode
48a4f368dcSAnson Jacob 	 */
49735d98cdSThomas Petazzoni 	-1, 0xC0, 0xA2, 0x02, 0x84,
50735d98cdSThomas Petazzoni 
51735d98cdSThomas Petazzoni 	/* PWCTR2 - Power Control
52a4f368dcSAnson Jacob 	 * VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
53a4f368dcSAnson Jacob 	 */
54735d98cdSThomas Petazzoni 	-1, 0xC1, 0xC5,
55735d98cdSThomas Petazzoni 
56735d98cdSThomas Petazzoni 	/* PWCTR3 - Power Control
57a4f368dcSAnson Jacob 	 * Opamp current small, Boost frequency
58a4f368dcSAnson Jacob 	 */
59735d98cdSThomas Petazzoni 	-1, 0xC2, 0x0A, 0x00,
60735d98cdSThomas Petazzoni 
61735d98cdSThomas Petazzoni 	/* PWCTR4 - Power Control
62a4f368dcSAnson Jacob 	 * BCLK/2, Opamp current small & Medium low
63a4f368dcSAnson Jacob 	 */
64735d98cdSThomas Petazzoni 	-1, 0xC3, 0x8A, 0x2A,
65735d98cdSThomas Petazzoni 
66735d98cdSThomas Petazzoni 	/* PWCTR5 - Power Control */
67735d98cdSThomas Petazzoni 	-1, 0xC4, 0x8A, 0xEE,
68735d98cdSThomas Petazzoni 
69735d98cdSThomas Petazzoni 	/* VMCTR1 - Power Control */
70735d98cdSThomas Petazzoni 	-1, 0xC5, 0x0E,
71735d98cdSThomas Petazzoni 
7279f5da7dSPriit Laes 	-1, MIPI_DCS_EXIT_INVERT_MODE,
73735d98cdSThomas Petazzoni 
7479f5da7dSPriit Laes 	-1, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT,
75735d98cdSThomas Petazzoni 
7679f5da7dSPriit Laes 	-1, MIPI_DCS_SET_DISPLAY_ON,
77735d98cdSThomas Petazzoni 	-2, 100,                               /* delay */
78735d98cdSThomas Petazzoni 
7979f5da7dSPriit Laes 	-1, MIPI_DCS_ENTER_NORMAL_MODE,
80735d98cdSThomas Petazzoni 	-2, 10,                               /* delay */
81735d98cdSThomas Petazzoni 
82735d98cdSThomas Petazzoni 	/* end marker */
83735d98cdSThomas Petazzoni 	-3
84735d98cdSThomas Petazzoni };
85735d98cdSThomas Petazzoni 
set_addr_win(struct fbtft_par * par,int xs,int ys,int xe,int ye)86735d98cdSThomas Petazzoni static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
87735d98cdSThomas Petazzoni {
8879f5da7dSPriit Laes 	write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
8979f5da7dSPriit Laes 		  xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
90735d98cdSThomas Petazzoni 
9179f5da7dSPriit Laes 	write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
9279f5da7dSPriit Laes 		  ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
93735d98cdSThomas Petazzoni 
9479f5da7dSPriit Laes 	write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
95735d98cdSThomas Petazzoni }
96735d98cdSThomas Petazzoni 
97e6ea2028SAnish Bhatt #define MY BIT(7)
98e6ea2028SAnish Bhatt #define MX BIT(6)
99e6ea2028SAnish Bhatt #define MV BIT(5)
set_var(struct fbtft_par * par)100735d98cdSThomas Petazzoni static int set_var(struct fbtft_par *par)
101735d98cdSThomas Petazzoni {
102735d98cdSThomas Petazzoni 	/* MADCTL - Memory data access control
103a4f368dcSAnson Jacob 	 * RGB/BGR:
104a4f368dcSAnson Jacob 	 * 1. Mode selection pin SRGB
105a4f368dcSAnson Jacob 	 *    RGB H/W pin for color filter setting: 0=RGB, 1=BGR
106a4f368dcSAnson Jacob 	 * 2. MADCTL RGB bit
107a4f368dcSAnson Jacob 	 *    RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR
108a4f368dcSAnson Jacob 	 */
109735d98cdSThomas Petazzoni 	switch (par->info->var.rotate) {
110735d98cdSThomas Petazzoni 	case 0:
11179f5da7dSPriit Laes 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
11279f5da7dSPriit Laes 			  MX | MY | (par->bgr << 3));
113735d98cdSThomas Petazzoni 		break;
114735d98cdSThomas Petazzoni 	case 270:
11579f5da7dSPriit Laes 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
11679f5da7dSPriit Laes 			  MY | MV | (par->bgr << 3));
117735d98cdSThomas Petazzoni 		break;
118735d98cdSThomas Petazzoni 	case 180:
11979f5da7dSPriit Laes 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
12079f5da7dSPriit Laes 			  par->bgr << 3);
121735d98cdSThomas Petazzoni 		break;
122735d98cdSThomas Petazzoni 	case 90:
12379f5da7dSPriit Laes 		write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
12479f5da7dSPriit Laes 			  MX | MV | (par->bgr << 3));
125735d98cdSThomas Petazzoni 		break;
126735d98cdSThomas Petazzoni 	}
127735d98cdSThomas Petazzoni 
128735d98cdSThomas Petazzoni 	return 0;
129735d98cdSThomas Petazzoni }
130735d98cdSThomas Petazzoni 
131735d98cdSThomas Petazzoni /*
132a4f368dcSAnson Jacob  * Gamma string format:
133a4f368dcSAnson Jacob  * VRF0P VOS0P PK0P PK1P PK2P PK3P PK4P PK5P PK6P PK7P PK8P PK9P SELV0P SELV1P SELV62P SELV63P
134a4f368dcSAnson Jacob  * VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N
135735d98cdSThomas Petazzoni  */
1360b1533c6SLeonardo Brás #define CURVE(num, idx)  curves[(num) * par->gamma.num_values + (idx)]
set_gamma(struct fbtft_par * par,u32 * curves)13722eb36b8SArnd Bergmann static int set_gamma(struct fbtft_par *par, u32 *curves)
138735d98cdSThomas Petazzoni {
139735d98cdSThomas Petazzoni 	int i, j;
140735d98cdSThomas Petazzoni 
141735d98cdSThomas Petazzoni 	/* apply mask */
142735d98cdSThomas Petazzoni 	for (i = 0; i < par->gamma.num_curves; i++)
143735d98cdSThomas Petazzoni 		for (j = 0; j < par->gamma.num_values; j++)
144153fe946SGeert Uytterhoeven 			CURVE(i, j) &= 0x3f;
145735d98cdSThomas Petazzoni 
146735d98cdSThomas Petazzoni 	for (i = 0; i < par->gamma.num_curves; i++)
147735d98cdSThomas Petazzoni 		write_reg(par, 0xE0 + i,
148333c7b94SLeonardo Brás 			  CURVE(i, 0),  CURVE(i, 1),
149333c7b94SLeonardo Brás 			  CURVE(i, 2),  CURVE(i, 3),
150333c7b94SLeonardo Brás 			  CURVE(i, 4),  CURVE(i, 5),
151333c7b94SLeonardo Brás 			  CURVE(i, 6),  CURVE(i, 7),
152333c7b94SLeonardo Brás 			  CURVE(i, 8),  CURVE(i, 9),
153333c7b94SLeonardo Brás 			  CURVE(i, 10), CURVE(i, 11),
154333c7b94SLeonardo Brás 			  CURVE(i, 12), CURVE(i, 13),
155333c7b94SLeonardo Brás 			  CURVE(i, 14), CURVE(i, 15));
156735d98cdSThomas Petazzoni 
157735d98cdSThomas Petazzoni 	return 0;
158735d98cdSThomas Petazzoni }
159333c7b94SLeonardo Brás 
160735d98cdSThomas Petazzoni #undef CURVE
161735d98cdSThomas Petazzoni 
162735d98cdSThomas Petazzoni static struct fbtft_display display = {
163735d98cdSThomas Petazzoni 	.regwidth = 8,
164735d98cdSThomas Petazzoni 	.width = 128,
165735d98cdSThomas Petazzoni 	.height = 160,
166735d98cdSThomas Petazzoni 	.init_sequence = default_init_sequence,
167735d98cdSThomas Petazzoni 	.gamma_num = 2,
168735d98cdSThomas Petazzoni 	.gamma_len = 16,
169735d98cdSThomas Petazzoni 	.gamma = DEFAULT_GAMMA,
170735d98cdSThomas Petazzoni 	.fbtftops = {
171735d98cdSThomas Petazzoni 		.set_addr_win = set_addr_win,
172735d98cdSThomas Petazzoni 		.set_var = set_var,
173735d98cdSThomas Petazzoni 		.set_gamma = set_gamma,
174735d98cdSThomas Petazzoni 	},
175735d98cdSThomas Petazzoni };
1761014c2ceSAnish Bhatt 
177735d98cdSThomas Petazzoni FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display);
178735d98cdSThomas Petazzoni 
179735d98cdSThomas Petazzoni MODULE_ALIAS("spi:" DRVNAME);
180735d98cdSThomas Petazzoni MODULE_ALIAS("platform:" DRVNAME);
181735d98cdSThomas Petazzoni MODULE_ALIAS("spi:st7735r");
182735d98cdSThomas Petazzoni MODULE_ALIAS("platform:st7735r");
183735d98cdSThomas Petazzoni 
184735d98cdSThomas Petazzoni MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller");
185735d98cdSThomas Petazzoni MODULE_AUTHOR("Noralf Tronnes");
186735d98cdSThomas Petazzoni MODULE_LICENSE("GPL");
187