cgroup: superblock can't be released with active dentries
[firefly-linux-kernel-4.4.55.git] / drivers / video / backlight / ams369fg06.c
1 /*
2  * ams369fg06 AMOLED LCD panel driver.
3  *
4  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
5  * Author: Jingoo Han  <jg1.han@samsung.com>
6  *
7  * Derived from drivers/video/s6e63m0.c
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #include <linux/wait.h>
25 #include <linux/module.h>
26 #include <linux/fb.h>
27 #include <linux/delay.h>
28 #include <linux/gpio.h>
29 #include <linux/spi/spi.h>
30 #include <linux/lcd.h>
31 #include <linux/backlight.h>
32
33 #define SLEEPMSEC               0x1000
34 #define ENDDEF                  0x2000
35 #define DEFMASK                 0xFF00
36 #define COMMAND_ONLY            0xFE
37 #define DATA_ONLY               0xFF
38
39 #define MAX_GAMMA_LEVEL         5
40 #define GAMMA_TABLE_COUNT       21
41
42 #define MIN_BRIGHTNESS          0
43 #define MAX_BRIGHTNESS          255
44 #define DEFAULT_BRIGHTNESS      150
45
46 struct ams369fg06 {
47         struct device                   *dev;
48         struct spi_device               *spi;
49         unsigned int                    power;
50         struct lcd_device               *ld;
51         struct backlight_device         *bd;
52         struct lcd_platform_data        *lcd_pd;
53 };
54
55 static const unsigned short seq_display_on[] = {
56         0x14, 0x03,
57         ENDDEF, 0x0000
58 };
59
60 static const unsigned short seq_display_off[] = {
61         0x14, 0x00,
62         ENDDEF, 0x0000
63 };
64
65 static const unsigned short seq_stand_by_on[] = {
66         0x1D, 0xA1,
67         SLEEPMSEC, 200,
68         ENDDEF, 0x0000
69 };
70
71 static const unsigned short seq_stand_by_off[] = {
72         0x1D, 0xA0,
73         SLEEPMSEC, 250,
74         ENDDEF, 0x0000
75 };
76
77 static const unsigned short seq_setting[] = {
78         0x31, 0x08,
79         0x32, 0x14,
80         0x30, 0x02,
81         0x27, 0x01,
82         0x12, 0x08,
83         0x13, 0x08,
84         0x15, 0x00,
85         0x16, 0x00,
86
87         0xef, 0xd0,
88         DATA_ONLY, 0xe8,
89
90         0x39, 0x44,
91         0x40, 0x00,
92         0x41, 0x3f,
93         0x42, 0x2a,
94         0x43, 0x27,
95         0x44, 0x27,
96         0x45, 0x1f,
97         0x46, 0x44,
98         0x50, 0x00,
99         0x51, 0x00,
100         0x52, 0x17,
101         0x53, 0x24,
102         0x54, 0x26,
103         0x55, 0x1f,
104         0x56, 0x43,
105         0x60, 0x00,
106         0x61, 0x3f,
107         0x62, 0x2a,
108         0x63, 0x25,
109         0x64, 0x24,
110         0x65, 0x1b,
111         0x66, 0x5c,
112
113         0x17, 0x22,
114         0x18, 0x33,
115         0x19, 0x03,
116         0x1a, 0x01,
117         0x22, 0xa4,
118         0x23, 0x00,
119         0x26, 0xa0,
120
121         0x1d, 0xa0,
122         SLEEPMSEC, 300,
123
124         0x14, 0x03,
125
126         ENDDEF, 0x0000
127 };
128
129 /* gamma value: 2.2 */
130 static const unsigned int ams369fg06_22_250[] = {
131         0x00, 0x3f, 0x2a, 0x27, 0x27, 0x1f, 0x44,
132         0x00, 0x00, 0x17, 0x24, 0x26, 0x1f, 0x43,
133         0x00, 0x3f, 0x2a, 0x25, 0x24, 0x1b, 0x5c,
134 };
135
136 static const unsigned int ams369fg06_22_200[] = {
137         0x00, 0x3f, 0x28, 0x29, 0x27, 0x21, 0x3e,
138         0x00, 0x00, 0x10, 0x25, 0x27, 0x20, 0x3d,
139         0x00, 0x3f, 0x28, 0x27, 0x25, 0x1d, 0x53,
140 };
141
142 static const unsigned int ams369fg06_22_150[] = {
143         0x00, 0x3f, 0x2d, 0x29, 0x28, 0x23, 0x37,
144         0x00, 0x00, 0x0b, 0x25, 0x28, 0x22, 0x36,
145         0x00, 0x3f, 0x2b, 0x28, 0x26, 0x1f, 0x4a,
146 };
147
148 static const unsigned int ams369fg06_22_100[] = {
149         0x00, 0x3f, 0x30, 0x2a, 0x2b, 0x24, 0x2f,
150         0x00, 0x00, 0x00, 0x25, 0x29, 0x24, 0x2e,
151         0x00, 0x3f, 0x2f, 0x29, 0x29, 0x21, 0x3f,
152 };
153
154 static const unsigned int ams369fg06_22_50[] = {
155         0x00, 0x3f, 0x3c, 0x2c, 0x2d, 0x27, 0x24,
156         0x00, 0x00, 0x00, 0x22, 0x2a, 0x27, 0x23,
157         0x00, 0x3f, 0x3b, 0x2c, 0x2b, 0x24, 0x31,
158 };
159
160 struct ams369fg06_gamma {
161         unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
162 };
163
164 static struct ams369fg06_gamma gamma_table = {
165         .gamma_22_table[0] = (unsigned int *)&ams369fg06_22_50,
166         .gamma_22_table[1] = (unsigned int *)&ams369fg06_22_100,
167         .gamma_22_table[2] = (unsigned int *)&ams369fg06_22_150,
168         .gamma_22_table[3] = (unsigned int *)&ams369fg06_22_200,
169         .gamma_22_table[4] = (unsigned int *)&ams369fg06_22_250,
170 };
171
172 static int ams369fg06_spi_write_byte(struct ams369fg06 *lcd, int addr, int data)
173 {
174         u16 buf[1];
175         struct spi_message msg;
176
177         struct spi_transfer xfer = {
178                 .len            = 2,
179                 .tx_buf         = buf,
180         };
181
182         buf[0] = (addr << 8) | data;
183
184         spi_message_init(&msg);
185         spi_message_add_tail(&xfer, &msg);
186
187         return spi_sync(lcd->spi, &msg);
188 }
189
190 static int ams369fg06_spi_write(struct ams369fg06 *lcd, unsigned char address,
191         unsigned char command)
192 {
193         int ret = 0;
194
195         if (address != DATA_ONLY)
196                 ret = ams369fg06_spi_write_byte(lcd, 0x70, address);
197         if (command != COMMAND_ONLY)
198                 ret = ams369fg06_spi_write_byte(lcd, 0x72, command);
199
200         return ret;
201 }
202
203 static int ams369fg06_panel_send_sequence(struct ams369fg06 *lcd,
204         const unsigned short *wbuf)
205 {
206         int ret = 0, i = 0;
207
208         while ((wbuf[i] & DEFMASK) != ENDDEF) {
209                 if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
210                         ret = ams369fg06_spi_write(lcd, wbuf[i], wbuf[i+1]);
211                         if (ret)
212                                 break;
213                 } else
214                         mdelay(wbuf[i+1]);
215                 i += 2;
216         }
217
218         return ret;
219 }
220
221 static int _ams369fg06_gamma_ctl(struct ams369fg06 *lcd,
222         const unsigned int *gamma)
223 {
224         unsigned int i = 0;
225         int ret = 0;
226
227         for (i = 0 ; i < GAMMA_TABLE_COUNT / 3; i++) {
228                 ret = ams369fg06_spi_write(lcd, 0x40 + i, gamma[i]);
229                 ret = ams369fg06_spi_write(lcd, 0x50 + i, gamma[i+7*1]);
230                 ret = ams369fg06_spi_write(lcd, 0x60 + i, gamma[i+7*2]);
231                 if (ret) {
232                         dev_err(lcd->dev, "failed to set gamma table.\n");
233                         goto gamma_err;
234                 }
235         }
236
237 gamma_err:
238         return ret;
239 }
240
241 static int ams369fg06_gamma_ctl(struct ams369fg06 *lcd, int brightness)
242 {
243         int ret = 0;
244         int gamma = 0;
245
246         if ((brightness >= 0) && (brightness <= 50))
247                 gamma = 0;
248         else if ((brightness > 50) && (brightness <= 100))
249                 gamma = 1;
250         else if ((brightness > 100) && (brightness <= 150))
251                 gamma = 2;
252         else if ((brightness > 150) && (brightness <= 200))
253                 gamma = 3;
254         else if ((brightness > 200) && (brightness <= 255))
255                 gamma = 4;
256
257         ret = _ams369fg06_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
258
259         return ret;
260 }
261
262 static int ams369fg06_ldi_init(struct ams369fg06 *lcd)
263 {
264         int ret, i;
265         static const unsigned short *init_seq[] = {
266                 seq_setting,
267                 seq_stand_by_off,
268         };
269
270         for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
271                 ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]);
272                 if (ret)
273                         break;
274         }
275
276         return ret;
277 }
278
279 static int ams369fg06_ldi_enable(struct ams369fg06 *lcd)
280 {
281         int ret, i;
282         static const unsigned short *init_seq[] = {
283                 seq_stand_by_off,
284                 seq_display_on,
285         };
286
287         for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
288                 ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]);
289                 if (ret)
290                         break;
291         }
292
293         return ret;
294 }
295
296 static int ams369fg06_ldi_disable(struct ams369fg06 *lcd)
297 {
298         int ret, i;
299
300         static const unsigned short *init_seq[] = {
301                 seq_display_off,
302                 seq_stand_by_on,
303         };
304
305         for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
306                 ret = ams369fg06_panel_send_sequence(lcd, init_seq[i]);
307                 if (ret)
308                         break;
309         }
310
311         return ret;
312 }
313
314 static int ams369fg06_power_is_on(int power)
315 {
316         return ((power) <= FB_BLANK_NORMAL);
317 }
318
319 static int ams369fg06_power_on(struct ams369fg06 *lcd)
320 {
321         int ret = 0;
322         struct lcd_platform_data *pd = NULL;
323         struct backlight_device *bd = NULL;
324
325         pd = lcd->lcd_pd;
326         if (!pd) {
327                 dev_err(lcd->dev, "platform data is NULL.\n");
328                 return -EFAULT;
329         }
330
331         bd = lcd->bd;
332         if (!bd) {
333                 dev_err(lcd->dev, "backlight device is NULL.\n");
334                 return -EFAULT;
335         }
336
337         if (!pd->power_on) {
338                 dev_err(lcd->dev, "power_on is NULL.\n");
339                 return -EFAULT;
340         } else {
341                 pd->power_on(lcd->ld, 1);
342                 mdelay(pd->power_on_delay);
343         }
344
345         if (!pd->reset) {
346                 dev_err(lcd->dev, "reset is NULL.\n");
347                 return -EFAULT;
348         } else {
349                 pd->reset(lcd->ld);
350                 mdelay(pd->reset_delay);
351         }
352
353         ret = ams369fg06_ldi_init(lcd);
354         if (ret) {
355                 dev_err(lcd->dev, "failed to initialize ldi.\n");
356                 return ret;
357         }
358
359         ret = ams369fg06_ldi_enable(lcd);
360         if (ret) {
361                 dev_err(lcd->dev, "failed to enable ldi.\n");
362                 return ret;
363         }
364
365         /* set brightness to current value after power on or resume. */
366         ret = ams369fg06_gamma_ctl(lcd, bd->props.brightness);
367         if (ret) {
368                 dev_err(lcd->dev, "lcd gamma setting failed.\n");
369                 return ret;
370         }
371
372         return 0;
373 }
374
375 static int ams369fg06_power_off(struct ams369fg06 *lcd)
376 {
377         int ret = 0;
378         struct lcd_platform_data *pd = NULL;
379
380         pd = lcd->lcd_pd;
381         if (!pd) {
382                 dev_err(lcd->dev, "platform data is NULL\n");
383                 return -EFAULT;
384         }
385
386         ret = ams369fg06_ldi_disable(lcd);
387         if (ret) {
388                 dev_err(lcd->dev, "lcd setting failed.\n");
389                 return -EIO;
390         }
391
392         mdelay(pd->power_off_delay);
393
394         if (!pd->power_on) {
395                 dev_err(lcd->dev, "power_on is NULL.\n");
396                 return -EFAULT;
397         } else
398                 pd->power_on(lcd->ld, 0);
399
400         return 0;
401 }
402
403 static int ams369fg06_power(struct ams369fg06 *lcd, int power)
404 {
405         int ret = 0;
406
407         if (ams369fg06_power_is_on(power) &&
408                 !ams369fg06_power_is_on(lcd->power))
409                 ret = ams369fg06_power_on(lcd);
410         else if (!ams369fg06_power_is_on(power) &&
411                 ams369fg06_power_is_on(lcd->power))
412                 ret = ams369fg06_power_off(lcd);
413
414         if (!ret)
415                 lcd->power = power;
416
417         return ret;
418 }
419
420 static int ams369fg06_get_power(struct lcd_device *ld)
421 {
422         struct ams369fg06 *lcd = lcd_get_data(ld);
423
424         return lcd->power;
425 }
426
427 static int ams369fg06_set_power(struct lcd_device *ld, int power)
428 {
429         struct ams369fg06 *lcd = lcd_get_data(ld);
430
431         if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
432                 power != FB_BLANK_NORMAL) {
433                 dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
434                 return -EINVAL;
435         }
436
437         return ams369fg06_power(lcd, power);
438 }
439
440 static int ams369fg06_get_brightness(struct backlight_device *bd)
441 {
442         return bd->props.brightness;
443 }
444
445 static int ams369fg06_set_brightness(struct backlight_device *bd)
446 {
447         int ret = 0;
448         int brightness = bd->props.brightness;
449         struct ams369fg06 *lcd = dev_get_drvdata(&bd->dev);
450
451         if (brightness < MIN_BRIGHTNESS ||
452                 brightness > bd->props.max_brightness) {
453                 dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
454                         MIN_BRIGHTNESS, MAX_BRIGHTNESS);
455                 return -EINVAL;
456         }
457
458         ret = ams369fg06_gamma_ctl(lcd, bd->props.brightness);
459         if (ret) {
460                 dev_err(&bd->dev, "lcd brightness setting failed.\n");
461                 return -EIO;
462         }
463
464         return ret;
465 }
466
467 static struct lcd_ops ams369fg06_lcd_ops = {
468         .get_power = ams369fg06_get_power,
469         .set_power = ams369fg06_set_power,
470 };
471
472 static const struct backlight_ops ams369fg06_backlight_ops = {
473         .get_brightness = ams369fg06_get_brightness,
474         .update_status = ams369fg06_set_brightness,
475 };
476
477 static int __devinit ams369fg06_probe(struct spi_device *spi)
478 {
479         int ret = 0;
480         struct ams369fg06 *lcd = NULL;
481         struct lcd_device *ld = NULL;
482         struct backlight_device *bd = NULL;
483         struct backlight_properties props;
484
485         lcd = kzalloc(sizeof(struct ams369fg06), GFP_KERNEL);
486         if (!lcd)
487                 return -ENOMEM;
488
489         /* ams369fg06 lcd panel uses 3-wire 16bits SPI Mode. */
490         spi->bits_per_word = 16;
491
492         ret = spi_setup(spi);
493         if (ret < 0) {
494                 dev_err(&spi->dev, "spi setup failed.\n");
495                 goto out_free_lcd;
496         }
497
498         lcd->spi = spi;
499         lcd->dev = &spi->dev;
500
501         lcd->lcd_pd = spi->dev.platform_data;
502         if (!lcd->lcd_pd) {
503                 dev_err(&spi->dev, "platform data is NULL\n");
504                 goto out_free_lcd;
505         }
506
507         ld = lcd_device_register("ams369fg06", &spi->dev, lcd,
508                 &ams369fg06_lcd_ops);
509         if (IS_ERR(ld)) {
510                 ret = PTR_ERR(ld);
511                 goto out_free_lcd;
512         }
513
514         lcd->ld = ld;
515
516         memset(&props, 0, sizeof(struct backlight_properties));
517         props.type = BACKLIGHT_RAW;
518         props.max_brightness = MAX_BRIGHTNESS;
519
520         bd = backlight_device_register("ams369fg06-bl", &spi->dev, lcd,
521                 &ams369fg06_backlight_ops, &props);
522         if (IS_ERR(bd)) {
523                 ret =  PTR_ERR(bd);
524                 goto out_lcd_unregister;
525         }
526
527         bd->props.brightness = DEFAULT_BRIGHTNESS;
528         lcd->bd = bd;
529
530         if (!lcd->lcd_pd->lcd_enabled) {
531                 /*
532                  * if lcd panel was off from bootloader then
533                  * current lcd status is powerdown and then
534                  * it enables lcd panel.
535                  */
536                 lcd->power = FB_BLANK_POWERDOWN;
537
538                 ams369fg06_power(lcd, FB_BLANK_UNBLANK);
539         } else
540                 lcd->power = FB_BLANK_UNBLANK;
541
542         dev_set_drvdata(&spi->dev, lcd);
543
544         dev_info(&spi->dev, "ams369fg06 panel driver has been probed.\n");
545
546         return 0;
547
548 out_lcd_unregister:
549         lcd_device_unregister(ld);
550 out_free_lcd:
551         kfree(lcd);
552         return ret;
553 }
554
555 static int __devexit ams369fg06_remove(struct spi_device *spi)
556 {
557         struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
558
559         ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
560         backlight_device_unregister(lcd->bd);
561         lcd_device_unregister(lcd->ld);
562         kfree(lcd);
563
564         return 0;
565 }
566
567 #if defined(CONFIG_PM)
568 static unsigned int before_power;
569
570 static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg)
571 {
572         int ret = 0;
573         struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
574
575         dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
576
577         before_power = lcd->power;
578
579         /*
580          * when lcd panel is suspend, lcd panel becomes off
581          * regardless of status.
582          */
583         ret = ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
584
585         return ret;
586 }
587
588 static int ams369fg06_resume(struct spi_device *spi)
589 {
590         int ret = 0;
591         struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
592
593         /*
594          * after suspended, if lcd panel status is FB_BLANK_UNBLANK
595          * (at that time, before_power is FB_BLANK_UNBLANK) then
596          * it changes that status to FB_BLANK_POWERDOWN to get lcd on.
597          */
598         if (before_power == FB_BLANK_UNBLANK)
599                 lcd->power = FB_BLANK_POWERDOWN;
600
601         dev_dbg(&spi->dev, "before_power = %d\n", before_power);
602
603         ret = ams369fg06_power(lcd, before_power);
604
605         return ret;
606 }
607 #else
608 #define ams369fg06_suspend      NULL
609 #define ams369fg06_resume       NULL
610 #endif
611
612 static void ams369fg06_shutdown(struct spi_device *spi)
613 {
614         struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
615
616         ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
617 }
618
619 static struct spi_driver ams369fg06_driver = {
620         .driver = {
621                 .name   = "ams369fg06",
622                 .bus    = &spi_bus_type,
623                 .owner  = THIS_MODULE,
624         },
625         .probe          = ams369fg06_probe,
626         .remove         = __devexit_p(ams369fg06_remove),
627         .shutdown       = ams369fg06_shutdown,
628         .suspend        = ams369fg06_suspend,
629         .resume         = ams369fg06_resume,
630 };
631
632 module_spi_driver(ams369fg06_driver);
633
634 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
635 MODULE_DESCRIPTION("ams369fg06 LCD Driver");
636 MODULE_LICENSE("GPL");