1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * lms501kf03 TFT LCD panel driver.
4 *
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
6 * Author: Jingoo Han <[email protected]>
7 */
8
9 #include <linux/delay.h>
10 #include <linux/lcd.h>
11 #include <linux/module.h>
12 #include <linux/spi/spi.h>
13 #include <linux/wait.h>
14
15 #define COMMAND_ONLY 0x00
16 #define DATA_ONLY 0x01
17
18 struct lms501kf03 {
19 struct device *dev;
20 struct spi_device *spi;
21 unsigned int power;
22 struct lcd_device *ld;
23 struct lcd_platform_data *lcd_pd;
24 };
25
26 static const unsigned char seq_password[] = {
27 0xb9, 0xff, 0x83, 0x69,
28 };
29
30 static const unsigned char seq_power[] = {
31 0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28,
32 0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
33 };
34
35 static const unsigned char seq_display[] = {
36 0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00,
37 0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
38 };
39
40 static const unsigned char seq_rgb_if[] = {
41 0xb3, 0x09,
42 };
43
44 static const unsigned char seq_display_inv[] = {
45 0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06,
46 };
47
48 static const unsigned char seq_vcom[] = {
49 0xb6, 0x4c, 0x2e,
50 };
51
52 static const unsigned char seq_gate[] = {
53 0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13,
54 0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75,
55 0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07,
56 };
57
58 static const unsigned char seq_panel[] = {
59 0xcc, 0x02,
60 };
61
62 static const unsigned char seq_col_mod[] = {
63 0x3a, 0x77,
64 };
65
66 static const unsigned char seq_w_gamma[] = {
67 0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a,
68 0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04,
69 0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16,
70 0x18, 0x16, 0x17, 0x0d, 0x15,
71 };
72
73 static const unsigned char seq_rgb_gamma[] = {
74 0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c,
75 0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92,
76 0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde,
77 0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb,
78 0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a,
79 0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b,
80 0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca,
81 0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe,
82 0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17,
83 0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63,
84 0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0,
85 0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00,
86 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 };
88
89 static const unsigned char seq_sleep_out[] = {
90 0x11,
91 };
92
93 static const unsigned char seq_display_on[] = {
94 0x29,
95 };
96
97 static const unsigned char seq_display_off[] = {
98 0x10,
99 };
100
lms501kf03_spi_write_byte(struct lms501kf03 * lcd,int addr,int data)101 static int lms501kf03_spi_write_byte(struct lms501kf03 *lcd, int addr, int data)
102 {
103 u16 buf[1];
104 struct spi_message msg;
105
106 struct spi_transfer xfer = {
107 .len = 2,
108 .tx_buf = buf,
109 };
110
111 buf[0] = (addr << 8) | data;
112
113 spi_message_init(&msg);
114 spi_message_add_tail(&xfer, &msg);
115
116 return spi_sync(lcd->spi, &msg);
117 }
118
lms501kf03_spi_write(struct lms501kf03 * lcd,unsigned char address,unsigned char command)119 static int lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address,
120 unsigned char command)
121 {
122 return lms501kf03_spi_write_byte(lcd, address, command);
123 }
124
lms501kf03_panel_send_sequence(struct lms501kf03 * lcd,const unsigned char * wbuf,unsigned int len)125 static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd,
126 const unsigned char *wbuf,
127 unsigned int len)
128 {
129 int ret = 0, i = 0;
130
131 while (i < len) {
132 if (i == 0)
133 ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]);
134 else
135 ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]);
136 if (ret)
137 break;
138 i += 1;
139 }
140
141 return ret;
142 }
143
lms501kf03_ldi_init(struct lms501kf03 * lcd)144 static int lms501kf03_ldi_init(struct lms501kf03 *lcd)
145 {
146 int ret, i;
147 static const unsigned char *init_seq[] = {
148 seq_password,
149 seq_power,
150 seq_display,
151 seq_rgb_if,
152 seq_display_inv,
153 seq_vcom,
154 seq_gate,
155 seq_panel,
156 seq_col_mod,
157 seq_w_gamma,
158 seq_rgb_gamma,
159 seq_sleep_out,
160 };
161
162 static const unsigned int size_seq[] = {
163 ARRAY_SIZE(seq_password),
164 ARRAY_SIZE(seq_power),
165 ARRAY_SIZE(seq_display),
166 ARRAY_SIZE(seq_rgb_if),
167 ARRAY_SIZE(seq_display_inv),
168 ARRAY_SIZE(seq_vcom),
169 ARRAY_SIZE(seq_gate),
170 ARRAY_SIZE(seq_panel),
171 ARRAY_SIZE(seq_col_mod),
172 ARRAY_SIZE(seq_w_gamma),
173 ARRAY_SIZE(seq_rgb_gamma),
174 ARRAY_SIZE(seq_sleep_out),
175 };
176
177 for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
178 ret = lms501kf03_panel_send_sequence(lcd, init_seq[i],
179 size_seq[i]);
180 if (ret)
181 break;
182 }
183 /*
184 * According to the datasheet, 120ms delay time is required.
185 * After sleep out sequence, command is blocked for 120ms.
186 * Thus, LDI should wait for 120ms.
187 */
188 msleep(120);
189
190 return ret;
191 }
192
lms501kf03_ldi_enable(struct lms501kf03 * lcd)193 static int lms501kf03_ldi_enable(struct lms501kf03 *lcd)
194 {
195 return lms501kf03_panel_send_sequence(lcd, seq_display_on,
196 ARRAY_SIZE(seq_display_on));
197 }
198
lms501kf03_ldi_disable(struct lms501kf03 * lcd)199 static int lms501kf03_ldi_disable(struct lms501kf03 *lcd)
200 {
201 return lms501kf03_panel_send_sequence(lcd, seq_display_off,
202 ARRAY_SIZE(seq_display_off));
203 }
204
lms501kf03_power_is_on(int power)205 static int lms501kf03_power_is_on(int power)
206 {
207 return (power) <= LCD_POWER_REDUCED;
208 }
209
lms501kf03_power_on(struct lms501kf03 * lcd)210 static int lms501kf03_power_on(struct lms501kf03 *lcd)
211 {
212 int ret = 0;
213 struct lcd_platform_data *pd;
214
215 pd = lcd->lcd_pd;
216
217 if (!pd->power_on) {
218 dev_err(lcd->dev, "power_on is NULL.\n");
219 return -EINVAL;
220 }
221
222 pd->power_on(lcd->ld, 1);
223 msleep(pd->power_on_delay);
224
225 if (!pd->reset) {
226 dev_err(lcd->dev, "reset is NULL.\n");
227 return -EINVAL;
228 }
229
230 pd->reset(lcd->ld);
231 msleep(pd->reset_delay);
232
233 ret = lms501kf03_ldi_init(lcd);
234 if (ret) {
235 dev_err(lcd->dev, "failed to initialize ldi.\n");
236 return ret;
237 }
238
239 ret = lms501kf03_ldi_enable(lcd);
240 if (ret) {
241 dev_err(lcd->dev, "failed to enable ldi.\n");
242 return ret;
243 }
244
245 return 0;
246 }
247
lms501kf03_power_off(struct lms501kf03 * lcd)248 static int lms501kf03_power_off(struct lms501kf03 *lcd)
249 {
250 int ret = 0;
251 struct lcd_platform_data *pd;
252
253 pd = lcd->lcd_pd;
254
255 ret = lms501kf03_ldi_disable(lcd);
256 if (ret) {
257 dev_err(lcd->dev, "lcd setting failed.\n");
258 return -EIO;
259 }
260
261 msleep(pd->power_off_delay);
262
263 pd->power_on(lcd->ld, 0);
264
265 return 0;
266 }
267
lms501kf03_power(struct lms501kf03 * lcd,int power)268 static int lms501kf03_power(struct lms501kf03 *lcd, int power)
269 {
270 int ret = 0;
271
272 if (lms501kf03_power_is_on(power) &&
273 !lms501kf03_power_is_on(lcd->power))
274 ret = lms501kf03_power_on(lcd);
275 else if (!lms501kf03_power_is_on(power) &&
276 lms501kf03_power_is_on(lcd->power))
277 ret = lms501kf03_power_off(lcd);
278
279 if (!ret)
280 lcd->power = power;
281
282 return ret;
283 }
284
lms501kf03_get_power(struct lcd_device * ld)285 static int lms501kf03_get_power(struct lcd_device *ld)
286 {
287 struct lms501kf03 *lcd = lcd_get_data(ld);
288
289 return lcd->power;
290 }
291
lms501kf03_set_power(struct lcd_device * ld,int power)292 static int lms501kf03_set_power(struct lcd_device *ld, int power)
293 {
294 struct lms501kf03 *lcd = lcd_get_data(ld);
295
296 if (power != LCD_POWER_ON && power != LCD_POWER_OFF &&
297 power != LCD_POWER_REDUCED) {
298 dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
299 return -EINVAL;
300 }
301
302 return lms501kf03_power(lcd, power);
303 }
304
305 static const struct lcd_ops lms501kf03_lcd_ops = {
306 .get_power = lms501kf03_get_power,
307 .set_power = lms501kf03_set_power,
308 };
309
lms501kf03_probe(struct spi_device * spi)310 static int lms501kf03_probe(struct spi_device *spi)
311 {
312 struct lms501kf03 *lcd = NULL;
313 struct lcd_device *ld = NULL;
314 int ret = 0;
315
316 lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL);
317 if (!lcd)
318 return -ENOMEM;
319
320 /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */
321 spi->bits_per_word = 9;
322
323 ret = spi_setup(spi);
324 if (ret < 0) {
325 dev_err(&spi->dev, "spi setup failed.\n");
326 return ret;
327 }
328
329 lcd->spi = spi;
330 lcd->dev = &spi->dev;
331
332 lcd->lcd_pd = dev_get_platdata(&spi->dev);
333 if (!lcd->lcd_pd) {
334 dev_err(&spi->dev, "platform data is NULL\n");
335 return -EINVAL;
336 }
337
338 ld = devm_lcd_device_register(&spi->dev, "lms501kf03", &spi->dev, lcd,
339 &lms501kf03_lcd_ops);
340 if (IS_ERR(ld))
341 return PTR_ERR(ld);
342
343 lcd->ld = ld;
344
345 if (!lcd->lcd_pd->lcd_enabled) {
346 /*
347 * if lcd panel was off from bootloader then
348 * current lcd status is powerdown and then
349 * it enables lcd panel.
350 */
351 lcd->power = LCD_POWER_OFF;
352
353 lms501kf03_power(lcd, LCD_POWER_ON);
354 } else {
355 lcd->power = LCD_POWER_ON;
356 }
357
358 spi_set_drvdata(spi, lcd);
359
360 dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n");
361
362 return 0;
363 }
364
lms501kf03_remove(struct spi_device * spi)365 static void lms501kf03_remove(struct spi_device *spi)
366 {
367 struct lms501kf03 *lcd = spi_get_drvdata(spi);
368
369 lms501kf03_power(lcd, LCD_POWER_OFF);
370 }
371
372 #ifdef CONFIG_PM_SLEEP
lms501kf03_suspend(struct device * dev)373 static int lms501kf03_suspend(struct device *dev)
374 {
375 struct lms501kf03 *lcd = dev_get_drvdata(dev);
376
377 dev_dbg(dev, "lcd->power = %d\n", lcd->power);
378
379 /*
380 * when lcd panel is suspend, lcd panel becomes off
381 * regardless of status.
382 */
383 return lms501kf03_power(lcd, LCD_POWER_OFF);
384 }
385
lms501kf03_resume(struct device * dev)386 static int lms501kf03_resume(struct device *dev)
387 {
388 struct lms501kf03 *lcd = dev_get_drvdata(dev);
389
390 lcd->power = LCD_POWER_OFF;
391
392 return lms501kf03_power(lcd, LCD_POWER_ON);
393 }
394 #endif
395
396 static SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend,
397 lms501kf03_resume);
398
lms501kf03_shutdown(struct spi_device * spi)399 static void lms501kf03_shutdown(struct spi_device *spi)
400 {
401 struct lms501kf03 *lcd = spi_get_drvdata(spi);
402
403 lms501kf03_power(lcd, LCD_POWER_OFF);
404 }
405
406 static struct spi_driver lms501kf03_driver = {
407 .driver = {
408 .name = "lms501kf03",
409 .pm = &lms501kf03_pm_ops,
410 },
411 .probe = lms501kf03_probe,
412 .remove = lms501kf03_remove,
413 .shutdown = lms501kf03_shutdown,
414 };
415
416 module_spi_driver(lms501kf03_driver);
417
418 MODULE_AUTHOR("Jingoo Han <[email protected]>");
419 MODULE_DESCRIPTION("lms501kf03 LCD Driver");
420 MODULE_LICENSE("GPL");
421