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