temp revert rk change
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-tegra / board-stingray-panel.c
1 /*
2  * arch/arm/mach-tegra/board-stingray-panel.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/gpio.h>
18 #include <linux/i2c.h>
19 #include <linux/leds-auo-panel-backlight.h>
20 #include <linux/resource.h>
21 #include <linux/leds-lp8550.h>
22 #include <linux/platform_device.h>
23 #include <linux/earlysuspend.h>
24 #include <linux/delay.h>
25 #include <linux/keyreset.h>
26 #include <linux/input.h>
27 #include <asm/mach-types.h>
28 #include <mach/irqs.h>
29 #include <mach/iomap.h>
30 #include <mach/dc.h>
31 #include <mach/fb.h>
32 #include <mach/nvhost.h>
33 #include <linux/regulator/consumer.h>
34 #include <linux/regulator/machine.h>
35 #include <linux/regulator/fixed.h>
36
37 #include "board.h"
38 #include "board-stingray.h"
39 #include "gpio-names.h"
40
41 #define STINGRAY_AUO_DISP_BL    TEGRA_GPIO_PD0
42 #define STINGRAY_LVDS_SHDN_B    TEGRA_GPIO_PB2
43 #define STINGRAY_HDMI_5V_EN     TEGRA_GPIO_PC4
44 #define STINGRAY_HDMI_HPD       TEGRA_GPIO_PN7
45
46 /* Display Controller */
47 static struct resource stingray_disp1_resources[] = {
48         {
49                 .name   = "irq",
50                 .start  = INT_DISPLAY_GENERAL,
51                 .end    = INT_DISPLAY_GENERAL,
52                 .flags  = IORESOURCE_IRQ,
53         },
54         {
55                 .name   = "regs",
56                 .start  = TEGRA_DISPLAY_BASE,
57                 .end    = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1,
58                 .flags  = IORESOURCE_MEM,
59         },
60         {
61                 .name   = "fbmem",
62                 /* .start and .end to be filled in later */
63                 .flags  = IORESOURCE_MEM,
64         },
65 };
66
67 static struct resource stingray_disp2_resources[] = {
68         {
69                 .name   = "irq",
70                 .start  = INT_DISPLAY_B_GENERAL,
71                 .end    = INT_DISPLAY_B_GENERAL,
72                 .flags  = IORESOURCE_IRQ,
73         },
74         {
75                 .name   = "regs",
76                 .start  = TEGRA_DISPLAY2_BASE,
77                 .end    = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE-1,
78                 .flags  = IORESOURCE_MEM,
79         },
80         {
81                 .name   = "fbmem",
82                 /* .start and .end to be filled in later */
83                 .flags  = IORESOURCE_MEM,
84         },
85         {
86                 .name   = "hdmi_regs",
87                 .start  = TEGRA_HDMI_BASE,
88                 .end    = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE-1,
89                 .flags  = IORESOURCE_MEM,
90         },
91 };
92
93 static struct tegra_dc_mode stingray_panel_modes_p0[] = {
94         {
95                 .pclk = 62200000,
96                 .h_ref_to_sync = 11,
97                 .v_ref_to_sync = 1,
98                 .h_sync_width = 42,
99                 .v_sync_width = 6,
100                 .h_back_porch = 43,
101                 .v_back_porch = 5,
102                 .h_active = 1280,
103                 .v_active = 720,
104                 .h_front_porch = 43,
105                 .v_front_porch = 5,
106         },
107 };
108
109 static struct tegra_dc_mode stingray_panel_modes[] = {
110         {
111                 .pclk = 65000000,
112                 .h_ref_to_sync = 11,
113                 .v_ref_to_sync = 1,
114                 .h_sync_width = 26,
115                 .v_sync_width = 6,
116                 .h_back_porch = 12,
117                 .v_back_porch = 3,
118                 .h_active = 1280,
119                 .v_active = 800,
120                 .h_front_porch = 45,
121                 .v_front_porch = 3,
122         },
123 };
124
125 static struct tegra_fb_data stingray_fb_data_p0 = {
126         .win            = 0,
127         .xres           = 1280,
128         .yres           = 720,
129         .bits_per_pixel = -1,
130         .flags          = TEGRA_FB_FLIP_ON_PROBE,
131 };
132
133 static struct tegra_fb_data stingray_fb_data = {
134         .win            = 0,
135         .xres           = 1280,
136         .yres           = 800,
137         .bits_per_pixel = -1,
138         .flags          = TEGRA_FB_FLIP_ON_PROBE,
139 };
140
141 #define LCD_MANFID_MAX_LEN 3
142 static char lcd_manfid[LCD_MANFID_MAX_LEN + 1];
143 int __init board_lcd_manfid_init(char *s)
144 {
145         strncpy(lcd_manfid, s, LCD_MANFID_MAX_LEN);
146         lcd_manfid[LCD_MANFID_MAX_LEN] = '\0';
147         printk(KERN_INFO "lcd_manfid=%s\n", lcd_manfid);
148         return 1;
149 }
150 __setup("lcd_manfid=", board_lcd_manfid_init);
151
152 /* Disgusting hack to deal with the fact that there are a set of pull down
153  * resistors on the panel end of the i2c bus.  These cause a voltage
154  * divider on the i2c bus which can cause these devices to fail to recognize
155  * their addresses when power to the display is cut.  This creates a dependency
156  * between these devices and the power to the panel.
157  */
158 static struct regulator_consumer_supply stingray_panel_reg_consumer_supply[] = {
159         { .supply = "vdd_panel", .dev_name = NULL, },
160         { .supply = "vio", .dev_name = "0-0077" /* barometer */},
161         { .supply = "vio", .dev_name = "0-002c" /* lighting */},
162         { .supply = "vio", .dev_name = "0-005b" /* touch */},
163         { .supply = "vio", .dev_name = "0-004b" /* als */},
164 };
165
166 static struct regulator_init_data stingray_panel_reg_initdata = {
167         .consumer_supplies = stingray_panel_reg_consumer_supply,
168         .num_consumer_supplies = ARRAY_SIZE(stingray_panel_reg_consumer_supply),
169         .constraints = {
170                 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
171         },
172 };
173
174 static struct fixed_voltage_config stingray_panel_reg_config = {
175         .supply_name            = "stingray_panel_reg",
176         .microvolts             = 5000000,
177         .gpio                   = STINGRAY_LVDS_SHDN_B,
178         .startup_delay          = 200000,
179         .enable_high            = 1,
180         .enabled_at_boot        = 1,
181         .init_data              = &stingray_panel_reg_initdata,
182 };
183
184 static struct platform_device stingray_panel_reg_device = {
185         .name   = "reg-fixed-voltage",
186         .id     = 0,
187         .dev    = {
188                 .platform_data = &stingray_panel_reg_config,
189         },
190 };
191
192 static struct regulator *stingray_panel_regulator = NULL;
193 static int stingray_panel_enable(void)
194 {
195         if (IS_ERR_OR_NULL(stingray_panel_regulator)) {
196                 stingray_panel_regulator = regulator_get(NULL, "vdd_panel");
197                 if (IS_ERR_OR_NULL(stingray_panel_regulator)) {
198                         pr_err("%s: Could not get panel regulator\n", __func__);
199                         return PTR_ERR(stingray_panel_regulator);
200                 }
201         }
202
203         return regulator_enable(stingray_panel_regulator);
204 }
205
206 static int stingray_panel_disable(void)
207 {
208         if (!IS_ERR_OR_NULL(stingray_panel_regulator))
209                 regulator_disable(stingray_panel_regulator);
210         return 0;
211 }
212
213 static void stingray_panel_early_reg_disable(struct work_struct *work)
214 {
215         stingray_panel_disable();
216 }
217
218 static DECLARE_DELAYED_WORK(stingray_panel_early_reg_disable_work,
219         stingray_panel_early_reg_disable);
220
221 static void stingray_panel_early_reg_enable(struct work_struct *work)
222 {
223         /*
224          * If the regulator was previously enabled, the work function to
225          * disable the work will be pending, cancel_delayed_work_sync
226          * will return true, and the regulator will not get enabled again.
227          */
228         if (!cancel_delayed_work_sync(&stingray_panel_early_reg_disable_work))
229                 stingray_panel_enable();
230
231         /*
232          * After the cancel_delay_work_sync, there is no outstanding work
233          * to disable the regulator, so queue the disable in 1 second.
234          * If no other driver calls regulator_enable on stingray_panel_regulator
235          * before 1 second has elapsed, the bridge chip will power down.
236          */
237         queue_delayed_work(system_nrt_wq,
238                 &stingray_panel_early_reg_disable_work,
239                 msecs_to_jiffies(1000));
240 }
241
242 static DECLARE_WORK(stingray_panel_early_reg_enable_work,
243         stingray_panel_early_reg_enable);
244 static bool stingray_panel_early_reg_in_resume;
245
246 static int stingray_panel_early_reg_resume_noirq(struct device *dev)
247 {
248         stingray_panel_early_reg_in_resume = true;
249         smp_wmb();
250         return 0;
251 }
252
253 static void stingray_panel_early_reg_resume_complete(struct device *dev)
254 {
255         stingray_panel_early_reg_in_resume = false;
256         smp_wmb();
257 }
258
259 static int stingray_panel_early_reg_suspend(struct device *dev)
260 {
261         cancel_work_sync(&stingray_panel_early_reg_enable_work);
262         flush_delayed_work(&stingray_panel_early_reg_disable_work);
263
264         return 0;
265 }
266
267 /*
268  * If the power button key event is detected during the resume process,
269  * the screen will get turned on later.  Immediately start the LVDS bridge chip
270  * turning on to reduce time spent waiting for it later in resume.
271  */
272 static int stingray_panel_early_reg_power(void)
273 {
274         smp_rmb();
275         if (stingray_panel_early_reg_in_resume)
276                 queue_work(system_nrt_wq, &stingray_panel_early_reg_enable_work);
277
278         return 0;
279 }
280
281 static struct dev_pm_ops stingray_panel_early_reg_pm_ops = {
282         .resume_noirq = stingray_panel_early_reg_resume_noirq,
283         .complete = stingray_panel_early_reg_resume_complete,
284         .suspend = stingray_panel_early_reg_suspend,
285 };
286
287 static struct keyreset_platform_data stingray_panel_early_reg_keyreset = {
288         .reset_fn = stingray_panel_early_reg_power,
289         .keys_down = {
290                 KEY_END,
291                 0
292         },
293 };
294
295 struct platform_device stingray_panel_early_reg_keyreset_device = {
296         .name   = KEYRESET_NAME,
297         .id     = -1,
298         .dev    = {
299                 .platform_data = &stingray_panel_early_reg_keyreset,
300         },
301 };
302
303 static struct platform_driver stingray_panel_early_reg_driver = {
304         .driver = {
305                 .name   = "stingray-panel-early-reg",
306                 .owner  = THIS_MODULE,
307                 .pm = &stingray_panel_early_reg_pm_ops,
308         }
309 };
310
311 static struct platform_device stingray_panel_early_reg_device = {
312         .name = "stingray-panel-early-reg",
313 };
314
315 static struct tegra_dc_out stingray_disp1_out = {
316         .type = TEGRA_DC_OUT_RGB,
317
318         .align = TEGRA_DC_ALIGN_MSB,
319         .order = TEGRA_DC_ORDER_RED_BLUE,
320         .depth = 24,
321
322         .height = 136, /* mm */
323         .width = 217, /* mm */
324
325         .modes = stingray_panel_modes,
326         .n_modes = ARRAY_SIZE(stingray_panel_modes),
327
328         .enable = stingray_panel_enable,
329         .disable = stingray_panel_disable,
330 };
331
332 static struct tegra_dc_platform_data stingray_disp1_pdata = {
333         .flags          = TEGRA_DC_FLAG_ENABLED,
334         .emc_clk_rate   = 300000000,
335         .default_out    = &stingray_disp1_out,
336         .fb             = &stingray_fb_data,
337 };
338
339 static struct nvhost_device stingray_disp1_device = {
340         .name           = "tegradc",
341         .id             = 0,
342         .resource       = stingray_disp1_resources,
343         .num_resources  = ARRAY_SIZE(stingray_disp1_resources),
344         .dev = {
345                 .platform_data = &stingray_disp1_pdata,
346         },
347 };
348
349 static int stingray_hdmi_init(void)
350 {
351         tegra_gpio_enable(STINGRAY_HDMI_5V_EN);
352         gpio_request(STINGRAY_HDMI_5V_EN, "hdmi_5v_en");
353         gpio_direction_output(STINGRAY_HDMI_5V_EN, 1);
354
355         tegra_gpio_enable(STINGRAY_HDMI_HPD);
356         gpio_request(STINGRAY_HDMI_HPD, "hdmi_hpd");
357         gpio_direction_input(STINGRAY_HDMI_HPD);
358
359
360         return 0;
361 }
362
363 static struct tegra_dc_out stingray_disp2_out = {
364         .type = TEGRA_DC_OUT_HDMI,
365         .flags = TEGRA_DC_OUT_HOTPLUG_HIGH,
366
367         .dcc_bus = 1,
368         .hotplug_gpio = STINGRAY_HDMI_HPD,
369
370         .align = TEGRA_DC_ALIGN_MSB,
371         .order = TEGRA_DC_ORDER_RED_BLUE,
372 };
373
374 static struct tegra_fb_data stingray_disp2_fb_data = {
375         .win            = 0,
376         .xres           = 1280,
377         .yres           = 720,
378         .bits_per_pixel = 32,
379 };
380
381 static struct tegra_dc_platform_data stingray_disp2_pdata = {
382         .flags          = 0,
383         .emc_clk_rate   = ULONG_MAX,
384         .default_out    = &stingray_disp2_out,
385         .fb             = &stingray_disp2_fb_data,
386 };
387
388 static struct nvhost_device stingray_disp2_device = {
389         .name           = "tegradc",
390         .id             = 1,
391         .resource       = stingray_disp2_resources,
392         .num_resources  = ARRAY_SIZE(stingray_disp2_resources),
393         .dev = {
394                 .platform_data = &stingray_disp2_pdata,
395         },
396 };
397
398
399 static void stingray_backlight_enable(void)
400 {
401         gpio_set_value(STINGRAY_AUO_DISP_BL, 1);
402 }
403
404 static void stingray_backlight_disable(void)
405 {
406         gpio_set_value(STINGRAY_AUO_DISP_BL, 0);
407 }
408
409 struct auo_panel_bl_platform_data stingray_auo_backlight_data = {
410         .bl_enable = stingray_backlight_enable,
411         .bl_disable = stingray_backlight_disable,
412         .pwm_enable = NULL,
413         .pwm_disable = NULL,
414 };
415
416 static struct platform_device stingray_panel_bl_driver = {
417         .name = LD_AUO_PANEL_BL_NAME,
418         .id = -1,
419         .dev = {
420                 .platform_data = &stingray_auo_backlight_data,
421                 },
422 };
423
424 struct lp8550_eeprom_data stingray_lp8550_eeprom_data[] = {
425         /* Set the backlight current to 19mA each step is .12mA */
426         {0xa1},
427         /* Boost freq 312khz, PWM controled w/constant current,
428         thermal deration disabled, brightness slope 500mS */
429         {0x67},
430         /* Adaptive mode for light loads, advanced slope enabled, 50% mode selected,
431         Adaptive mode enabled, Boost is enabled, Boost Imax is 2.5A */
432         {0xbf},
433         /* UVLO is disabled, phase shift PWM enabled, PWM Freq 19232 */
434         {0x3f},
435         /* LED current resistor disabled, LED Fault = 3.3V */
436         {0x08},
437         /* Vsync is enabled, Dither enabled, Boost voltage 20V */
438         {0xea},
439         /* PLL 13-bit counter */
440         {0x64},
441         /* 1-bit hysteresis w/10 bit resolution, PWM output freq is set with
442         PWM_FREQ EEPROM bits */
443         {0x2a},
444 };
445
446 struct lp8550_platform_data stingray_lp8550_backlight_data = {
447         .power_up_brightness = 0x80,
448         .dev_ctrl_config = 0x04,
449         .brightness_control = 0x80,
450         .dev_id = 0xfc,
451         .direct_ctrl = 0x01,
452         .eeprom_table = stingray_lp8550_eeprom_data,
453         .eeprom_tbl_sz = ARRAY_SIZE(stingray_lp8550_eeprom_data),
454         .scaling_factor = 690, /* For SHP and default */
455 };
456
457 static int stingray_lp8550_init(void)
458 {
459         struct lp8550_platform_data *pdata =
460                          &stingray_lp8550_backlight_data;
461         if (!strncmp(lcd_manfid, "AUO", 3))
462                 pdata->scaling_factor = 726;
463
464         return 0;
465 }
466
467 static struct i2c_board_info __initdata stingray_i2c_bus1_led_info[] = {
468          {
469                 I2C_BOARD_INFO(LD_LP8550_NAME, 0x2c),
470                 .platform_data = &stingray_lp8550_backlight_data,
471          },
472 };
473
474 #ifdef CONFIG_HAS_EARLYSUSPEND
475 /* put early_suspend/late_resume handlers here for the display in order
476  * to keep the code out of the display driver, keeping it closer to upstream
477  */
478 struct early_suspend stingray_panel_early_suspender;
479
480 static void stingray_panel_early_suspend(struct early_suspend *h)
481 {
482         if (num_registered_fb > 0)
483                 fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
484 }
485
486 static void stingray_panel_late_resume(struct early_suspend *h)
487 {
488         if (num_registered_fb > 0)
489                 fb_blank(registered_fb[0], FB_BLANK_UNBLANK);
490 }
491 #endif
492
493 static struct regulator *stingray_csi_reg;
494
495 int __init stingray_panel_init(void)
496 {
497         struct resource *res;
498
499         if (stingray_revision() < STINGRAY_REVISION_P1) {
500                 tegra_gpio_enable(STINGRAY_AUO_DISP_BL);
501                 gpio_request(STINGRAY_AUO_DISP_BL, "auo_disp_bl");
502                 gpio_direction_output(STINGRAY_AUO_DISP_BL, 1);
503                 platform_device_register(&stingray_panel_bl_driver);
504                 stingray_disp1_pdata.fb = &stingray_fb_data_p0;
505                 stingray_disp1_out.modes = stingray_panel_modes_p0;
506         } else {
507                 if (stingray_revision() >= STINGRAY_REVISION_P3)
508                         stingray_lp8550_backlight_data.dev_ctrl_config = 0x02;
509                 i2c_register_board_info(0, stingray_i2c_bus1_led_info,
510                         ARRAY_SIZE(stingray_i2c_bus1_led_info));
511         }
512
513         platform_device_register(&stingray_panel_reg_device);
514
515         platform_driver_register(&stingray_panel_early_reg_driver);
516         platform_device_register(&stingray_panel_early_reg_device);
517         platform_device_register(&stingray_panel_early_reg_keyreset_device);
518
519         stingray_hdmi_init();
520         stingray_lp8550_init();
521
522         stingray_csi_reg = regulator_get(NULL, "vcsi");
523         if (IS_ERR(stingray_csi_reg)) {
524                 pr_err("hdmi: couldn't get regulator vcsi");
525         } else {
526                 regulator_enable(stingray_csi_reg);
527         }
528
529 #ifdef CONFIG_HAS_EARLYSUSPEND
530         stingray_panel_early_suspender.suspend = stingray_panel_early_suspend;
531         stingray_panel_early_suspender.resume = stingray_panel_late_resume;
532         stingray_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
533         register_early_suspend(&stingray_panel_early_suspender);
534 #endif
535
536
537         res = nvhost_get_resource_byname(&stingray_disp1_device,
538                 IORESOURCE_MEM, "fbmem");
539         res->start = tegra_fb_start;
540         res->end = tegra_fb_start + tegra_fb_size - 1;
541
542         res = nvhost_get_resource_byname(&stingray_disp2_device,
543                 IORESOURCE_MEM, "fbmem");
544         res->start = tegra_fb2_start;
545         res->end = tegra_fb2_start + tegra_fb2_size - 1;
546
547         tegra_move_framebuffer(tegra_fb_start, tegra_bootloader_fb_start,
548                 min(tegra_fb_size, tegra_bootloader_fb_size));
549
550         nvhost_device_register(&stingray_disp1_device);
551         return  nvhost_device_register(&stingray_disp2_device);
552 }
553