]> Git Repo - J-linux.git/blob - drivers/video/backlight/lms501kf03.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.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  <[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
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
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
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
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
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
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
205 static int lms501kf03_power_is_on(int power)
206 {
207         return (power) <= LCD_POWER_REDUCED;
208 }
209
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
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
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
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
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
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
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
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
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
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");
This page took 0.051688 seconds and 4 git commands to generate.