xref: /linux/drivers/video/backlight/otm3225a.c (revision fa84cf094ef9667e2b91c104b0a788fd1896f482)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Driver for ORISE Technology OTM3225A SOC for TFT LCD
3  * Copyright (C) 2017, EETS GmbH, Felix Brack <fb@ltec.ch>
4  *
5  * This driver implements a lcd device for the ORISE OTM3225A display
6  * controller. The control interface to the display is SPI and the display's
7  * memory is updated over the 16-bit RGB interface.
8  * The main source of information for writing this driver was provided by the
9  * OTM3225A datasheet from ORISE Technology. Some information arise from the
10  * ILI9328 datasheet from ILITEK as well as from the datasheets and sample code
11  * provided by Crystalfontz America Inc. who sells the CFAF240320A-032T, a 3.2"
12  * TFT LC display using the OTM3225A controller.
13  */
14 
15 #include <linux/delay.h>
16 #include <linux/device.h>
17 #include <linux/kernel.h>
18 #include <linux/lcd.h>
19 #include <linux/module.h>
20 #include <linux/spi/spi.h>
21 
22 #define OTM3225A_INDEX_REG	0x70
23 #define OTM3225A_DATA_REG	0x72
24 
25 /* instruction register list */
26 #define DRIVER_OUTPUT_CTRL_1	0x01
27 #define DRIVER_WAVEFORM_CTRL	0x02
28 #define ENTRY_MODE		0x03
29 #define SCALING_CTRL		0x04
30 #define DISPLAY_CTRL_1		0x07
31 #define DISPLAY_CTRL_2		0x08
32 #define DISPLAY_CTRL_3		0x09
33 #define FRAME_CYCLE_CTRL	0x0A
34 #define EXT_DISP_IFACE_CTRL_1	0x0C
35 #define FRAME_MAKER_POS		0x0D
36 #define EXT_DISP_IFACE_CTRL_2	0x0F
37 #define POWER_CTRL_1		0x10
38 #define POWER_CTRL_2		0x11
39 #define POWER_CTRL_3		0x12
40 #define POWER_CTRL_4		0x13
41 #define GRAM_ADDR_HORIZ_SET	0x20
42 #define GRAM_ADDR_VERT_SET	0x21
43 #define GRAM_READ_WRITE		0x22
44 #define POWER_CTRL_7		0x29
45 #define FRAME_RATE_CTRL		0x2B
46 #define GAMMA_CTRL_1		0x30
47 #define GAMMA_CTRL_2		0x31
48 #define GAMMA_CTRL_3		0x32
49 #define GAMMA_CTRL_4		0x35
50 #define GAMMA_CTRL_5		0x36
51 #define GAMMA_CTRL_6		0x37
52 #define GAMMA_CTRL_7		0x38
53 #define GAMMA_CTRL_8		0x39
54 #define GAMMA_CTRL_9		0x3C
55 #define GAMMA_CTRL_10		0x3D
56 #define WINDOW_HORIZ_RAM_START	0x50
57 #define WINDOW_HORIZ_RAM_END	0x51
58 #define WINDOW_VERT_RAM_START	0x52
59 #define WINDOW_VERT_RAM_END	0x53
60 #define DRIVER_OUTPUT_CTRL_2	0x60
61 #define BASE_IMG_DISPLAY_CTRL	0x61
62 #define VERT_SCROLL_CTRL	0x6A
63 #define PD1_DISPLAY_POS		0x80
64 #define PD1_RAM_START		0x81
65 #define PD1_RAM_END		0x82
66 #define PD2_DISPLAY_POS		0x83
67 #define PD2_RAM_START		0x84
68 #define PD2_RAM_END		0x85
69 #define PANEL_IFACE_CTRL_1	0x90
70 #define PANEL_IFACE_CTRL_2	0x92
71 #define PANEL_IFACE_CTRL_4	0x95
72 #define PANEL_IFACE_CTRL_5	0x97
73 
74 struct otm3225a_data {
75 	struct spi_device *spi;
76 	struct lcd_device *ld;
77 	int power;
78 };
79 
80 struct otm3225a_spi_instruction {
81 	unsigned char reg;	/* register to write */
82 	unsigned short value;	/* data to write to 'reg' */
83 	unsigned short delay;	/* delay in ms after write */
84 };
85 
86 static struct otm3225a_spi_instruction display_init[] = {
87 	{ DRIVER_OUTPUT_CTRL_1,		0x0000, 0 },
88 	{ DRIVER_WAVEFORM_CTRL,		0x0700, 0 },
89 	{ ENTRY_MODE,			0x50A0, 0 },
90 	{ SCALING_CTRL,			0x0000, 0 },
91 	{ DISPLAY_CTRL_2,		0x0606, 0 },
92 	{ DISPLAY_CTRL_3,		0x0000, 0 },
93 	{ FRAME_CYCLE_CTRL,		0x0000, 0 },
94 	{ EXT_DISP_IFACE_CTRL_1,	0x0000, 0 },
95 	{ FRAME_MAKER_POS,		0x0000, 0 },
96 	{ EXT_DISP_IFACE_CTRL_2,	0x0002, 0 },
97 	{ POWER_CTRL_2,			0x0007, 0 },
98 	{ POWER_CTRL_3,			0x0000, 0 },
99 	{ POWER_CTRL_4,			0x0000, 200 },
100 	{ DISPLAY_CTRL_1,		0x0101, 0 },
101 	{ POWER_CTRL_1,			0x12B0, 0 },
102 	{ POWER_CTRL_2,			0x0007, 0 },
103 	{ POWER_CTRL_3,			0x01BB, 50 },
104 	{ POWER_CTRL_4,			0x0013, 0 },
105 	{ POWER_CTRL_7,			0x0010, 50 },
106 	{ GAMMA_CTRL_1,			0x000A, 0 },
107 	{ GAMMA_CTRL_2,			0x1326, 0 },
108 	{ GAMMA_CTRL_3,			0x0A29, 0 },
109 	{ GAMMA_CTRL_4,			0x0A0A, 0 },
110 	{ GAMMA_CTRL_5,			0x1E03, 0 },
111 	{ GAMMA_CTRL_6,			0x031E, 0 },
112 	{ GAMMA_CTRL_7,			0x0706, 0 },
113 	{ GAMMA_CTRL_8,			0x0303, 0 },
114 	{ GAMMA_CTRL_9,			0x010E, 0 },
115 	{ GAMMA_CTRL_10,		0x040E, 0 },
116 	{ WINDOW_HORIZ_RAM_START,	0x0000, 0 },
117 	{ WINDOW_HORIZ_RAM_END,		0x00EF, 0 },
118 	{ WINDOW_VERT_RAM_START,	0x0000, 0 },
119 	{ WINDOW_VERT_RAM_END,		0x013F, 0 },
120 	{ DRIVER_OUTPUT_CTRL_2,		0x2700, 0 },
121 	{ BASE_IMG_DISPLAY_CTRL,	0x0001, 0 },
122 	{ VERT_SCROLL_CTRL,		0x0000, 0 },
123 	{ PD1_DISPLAY_POS,		0x0000, 0 },
124 	{ PD1_RAM_START,		0x0000, 0 },
125 	{ PD1_RAM_END,			0x0000, 0 },
126 	{ PD2_DISPLAY_POS,		0x0000, 0 },
127 	{ PD2_RAM_START,		0x0000, 0 },
128 	{ PD2_RAM_END,			0x0000, 0 },
129 	{ PANEL_IFACE_CTRL_1,		0x0010, 0 },
130 	{ PANEL_IFACE_CTRL_2,		0x0000, 0 },
131 	{ PANEL_IFACE_CTRL_4,		0x0210, 0 },
132 	{ PANEL_IFACE_CTRL_5,		0x0000, 0 },
133 	{ DISPLAY_CTRL_1,		0x0133, 0 },
134 };
135 
136 static struct otm3225a_spi_instruction display_enable_rgb_interface[] = {
137 	{ ENTRY_MODE,			0x1080, 0 },
138 	{ GRAM_ADDR_HORIZ_SET,		0x0000, 0 },
139 	{ GRAM_ADDR_VERT_SET,		0x0000, 0 },
140 	{ EXT_DISP_IFACE_CTRL_1,	0x0111, 500 },
141 };
142 
143 static struct otm3225a_spi_instruction display_off[] = {
144 	{ DISPLAY_CTRL_1,	0x0131, 100 },
145 	{ DISPLAY_CTRL_1,	0x0130, 100 },
146 	{ DISPLAY_CTRL_1,	0x0100, 0 },
147 	{ POWER_CTRL_1,		0x0280, 0 },
148 	{ POWER_CTRL_3,		0x018B, 0 },
149 };
150 
151 static struct otm3225a_spi_instruction display_on[] = {
152 	{ POWER_CTRL_1,		0x1280, 0 },
153 	{ DISPLAY_CTRL_1,	0x0101, 100 },
154 	{ DISPLAY_CTRL_1,	0x0121, 0 },
155 	{ DISPLAY_CTRL_1,	0x0123, 100 },
156 	{ DISPLAY_CTRL_1,	0x0133, 10 },
157 };
158 
159 static void otm3225a_write(struct spi_device *spi,
160 			   struct otm3225a_spi_instruction *instruction,
161 			   unsigned int count)
162 {
163 	unsigned char buf[3];
164 
165 	while (count--) {
166 		/* address register using index register */
167 		buf[0] = OTM3225A_INDEX_REG;
168 		buf[1] = 0x00;
169 		buf[2] = instruction->reg;
170 		spi_write(spi, buf, 3);
171 
172 		/* write data to addressed register */
173 		buf[0] = OTM3225A_DATA_REG;
174 		buf[1] = (instruction->value >> 8) & 0xff;
175 		buf[2] = instruction->value & 0xff;
176 		spi_write(spi, buf, 3);
177 
178 		/* execute delay if any */
179 		if (instruction->delay)
180 			msleep(instruction->delay);
181 		instruction++;
182 	}
183 }
184 
185 static int otm3225a_set_power(struct lcd_device *ld, int power)
186 {
187 	struct otm3225a_data *dd = lcd_get_data(ld);
188 
189 	if (power == dd->power)
190 		return 0;
191 
192 	if (power > FB_BLANK_UNBLANK)
193 		otm3225a_write(dd->spi, display_off, ARRAY_SIZE(display_off));
194 	else
195 		otm3225a_write(dd->spi, display_on, ARRAY_SIZE(display_on));
196 	dd->power = power;
197 
198 	return 0;
199 }
200 
201 static int otm3225a_get_power(struct lcd_device *ld)
202 {
203 	struct otm3225a_data *dd = lcd_get_data(ld);
204 
205 	return dd->power;
206 }
207 
208 static struct lcd_ops otm3225a_ops = {
209 	.set_power = otm3225a_set_power,
210 	.get_power = otm3225a_get_power,
211 };
212 
213 static int otm3225a_probe(struct spi_device *spi)
214 {
215 	struct otm3225a_data *dd;
216 	struct lcd_device *ld;
217 	struct device *dev = &spi->dev;
218 
219 	dd = devm_kzalloc(dev, sizeof(struct otm3225a_data), GFP_KERNEL);
220 	if (dd == NULL)
221 		return -ENOMEM;
222 
223 	ld = devm_lcd_device_register(dev, dev_name(dev), dev, dd,
224 				      &otm3225a_ops);
225 	if (IS_ERR(ld))
226 		return PTR_ERR(ld);
227 
228 	dd->spi = spi;
229 	dd->ld = ld;
230 	dev_set_drvdata(dev, dd);
231 
232 	dev_info(dev, "Initializing and switching to RGB interface");
233 	otm3225a_write(spi, display_init, ARRAY_SIZE(display_init));
234 	otm3225a_write(spi, display_enable_rgb_interface,
235 		       ARRAY_SIZE(display_enable_rgb_interface));
236 	return 0;
237 }
238 
239 static struct spi_driver otm3225a_driver = {
240 	.driver = {
241 		.name = "otm3225a",
242 		.owner = THIS_MODULE,
243 	},
244 	.probe = otm3225a_probe,
245 };
246 
247 module_spi_driver(otm3225a_driver);
248 
249 MODULE_AUTHOR("Felix Brack <fb@ltec.ch>");
250 MODULE_DESCRIPTION("OTM3225A TFT LCD driver");
251 MODULE_VERSION("1.0.0");
252 MODULE_LICENSE("GPL v2");
253