2 * arch/arm/mach-tegra/board-stingray-panel.c
4 * Copyright (C) 2010 Google, Inc.
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.
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.
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>
32 #include <mach/nvhost.h>
33 #include <linux/regulator/consumer.h>
34 #include <linux/regulator/machine.h>
35 #include <linux/regulator/fixed.h>
38 #include "board-stingray.h"
39 #include "gpio-names.h"
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
46 /* Display Controller */
47 static struct resource stingray_disp1_resources[] = {
50 .start = INT_DISPLAY_GENERAL,
51 .end = INT_DISPLAY_GENERAL,
52 .flags = IORESOURCE_IRQ,
56 .start = TEGRA_DISPLAY_BASE,
57 .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1,
58 .flags = IORESOURCE_MEM,
62 /* .start and .end to be filled in later */
63 .flags = IORESOURCE_MEM,
67 static struct resource stingray_disp2_resources[] = {
70 .start = INT_DISPLAY_B_GENERAL,
71 .end = INT_DISPLAY_B_GENERAL,
72 .flags = IORESOURCE_IRQ,
76 .start = TEGRA_DISPLAY2_BASE,
77 .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE-1,
78 .flags = IORESOURCE_MEM,
82 /* .start and .end to be filled in later */
83 .flags = IORESOURCE_MEM,
87 .start = TEGRA_HDMI_BASE,
88 .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE-1,
89 .flags = IORESOURCE_MEM,
93 static struct tegra_dc_mode stingray_panel_modes_p0[] = {
109 static struct tegra_dc_mode stingray_panel_modes[] = {
125 static struct tegra_fb_data stingray_fb_data_p0 = {
129 .bits_per_pixel = -1,
130 .flags = TEGRA_FB_FLIP_ON_PROBE,
133 static struct tegra_fb_data stingray_fb_data = {
137 .bits_per_pixel = -1,
138 .flags = TEGRA_FB_FLIP_ON_PROBE,
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)
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);
150 __setup("lcd_manfid=", board_lcd_manfid_init);
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.
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 */},
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),
170 .valid_ops_mask = REGULATOR_CHANGE_STATUS,
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,
180 .enabled_at_boot = 1,
181 .init_data = &stingray_panel_reg_initdata,
184 static struct platform_device stingray_panel_reg_device = {
185 .name = "reg-fixed-voltage",
188 .platform_data = &stingray_panel_reg_config,
192 static struct regulator *stingray_panel_regulator = NULL;
193 static int stingray_panel_enable(void)
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);
203 return regulator_enable(stingray_panel_regulator);
206 static int stingray_panel_disable(void)
208 if (!IS_ERR_OR_NULL(stingray_panel_regulator))
209 regulator_disable(stingray_panel_regulator);
213 static void stingray_panel_early_reg_disable(struct work_struct *work)
215 stingray_panel_disable();
218 static DECLARE_DELAYED_WORK(stingray_panel_early_reg_disable_work,
219 stingray_panel_early_reg_disable);
221 static void stingray_panel_early_reg_enable(struct work_struct *work)
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.
228 if (!cancel_delayed_work_sync(&stingray_panel_early_reg_disable_work))
229 stingray_panel_enable();
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.
237 queue_delayed_work(system_nrt_wq,
238 &stingray_panel_early_reg_disable_work,
239 msecs_to_jiffies(1000));
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;
246 static int stingray_panel_early_reg_resume_noirq(struct device *dev)
248 stingray_panel_early_reg_in_resume = true;
253 static void stingray_panel_early_reg_resume_complete(struct device *dev)
255 stingray_panel_early_reg_in_resume = false;
259 static int stingray_panel_early_reg_suspend(struct device *dev)
261 cancel_work_sync(&stingray_panel_early_reg_enable_work);
262 flush_delayed_work(&stingray_panel_early_reg_disable_work);
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.
272 static int stingray_panel_early_reg_power(void)
275 if (stingray_panel_early_reg_in_resume)
276 queue_work(system_nrt_wq, &stingray_panel_early_reg_enable_work);
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,
287 static struct keyreset_platform_data stingray_panel_early_reg_keyreset = {
288 .reset_fn = stingray_panel_early_reg_power,
295 struct platform_device stingray_panel_early_reg_keyreset_device = {
296 .name = KEYRESET_NAME,
299 .platform_data = &stingray_panel_early_reg_keyreset,
303 static struct platform_driver stingray_panel_early_reg_driver = {
305 .name = "stingray-panel-early-reg",
306 .owner = THIS_MODULE,
307 .pm = &stingray_panel_early_reg_pm_ops,
311 static struct platform_device stingray_panel_early_reg_device = {
312 .name = "stingray-panel-early-reg",
315 static struct tegra_dc_out stingray_disp1_out = {
316 .type = TEGRA_DC_OUT_RGB,
318 .align = TEGRA_DC_ALIGN_MSB,
319 .order = TEGRA_DC_ORDER_RED_BLUE,
322 .height = 136, /* mm */
323 .width = 217, /* mm */
325 .modes = stingray_panel_modes,
326 .n_modes = ARRAY_SIZE(stingray_panel_modes),
328 .enable = stingray_panel_enable,
329 .disable = stingray_panel_disable,
332 static struct tegra_dc_platform_data stingray_disp1_pdata = {
333 .flags = TEGRA_DC_FLAG_ENABLED,
334 .emc_clk_rate = 400000000,
335 .default_out = &stingray_disp1_out,
336 .fb = &stingray_fb_data,
339 static struct nvhost_device stingray_disp1_device = {
342 .resource = stingray_disp1_resources,
343 .num_resources = ARRAY_SIZE(stingray_disp1_resources),
345 .platform_data = &stingray_disp1_pdata,
349 static int stingray_hdmi_init(void)
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);
355 tegra_gpio_enable(STINGRAY_HDMI_HPD);
356 gpio_request(STINGRAY_HDMI_HPD, "hdmi_hpd");
357 gpio_direction_input(STINGRAY_HDMI_HPD);
363 static struct tegra_dc_out stingray_disp2_out = {
364 .type = TEGRA_DC_OUT_HDMI,
365 .flags = TEGRA_DC_OUT_HOTPLUG_HIGH,
368 .hotplug_gpio = STINGRAY_HDMI_HPD,
370 .align = TEGRA_DC_ALIGN_MSB,
371 .order = TEGRA_DC_ORDER_RED_BLUE,
374 static struct tegra_fb_data stingray_disp2_fb_data = {
378 .bits_per_pixel = 32,
381 static struct tegra_dc_platform_data stingray_disp2_pdata = {
383 .emc_clk_rate = ULONG_MAX,
384 .default_out = &stingray_disp2_out,
385 .fb = &stingray_disp2_fb_data,
388 static struct nvhost_device stingray_disp2_device = {
391 .resource = stingray_disp2_resources,
392 .num_resources = ARRAY_SIZE(stingray_disp2_resources),
394 .platform_data = &stingray_disp2_pdata,
399 static void stingray_backlight_enable(void)
401 gpio_set_value(STINGRAY_AUO_DISP_BL, 1);
404 static void stingray_backlight_disable(void)
406 gpio_set_value(STINGRAY_AUO_DISP_BL, 0);
409 struct auo_panel_bl_platform_data stingray_auo_backlight_data = {
410 .bl_enable = stingray_backlight_enable,
411 .bl_disable = stingray_backlight_disable,
416 static struct platform_device stingray_panel_bl_driver = {
417 .name = LD_AUO_PANEL_BL_NAME,
420 .platform_data = &stingray_auo_backlight_data,
424 struct lp8550_eeprom_data stingray_lp8550_eeprom_data[] = {
425 /* Set the backlight current to 19mA each step is .12mA */
427 /* Boost freq 312khz, PWM controled w/constant current,
428 thermal deration disabled, brightness slope 500mS */
430 /* Adaptive mode for light loads, advanced slope enabled, 50% mode selected,
431 Adaptive mode enabled, Boost is enabled, Boost Imax is 2.5A */
433 /* UVLO is disabled, phase shift PWM enabled, PWM Freq 19232 */
435 /* LED current resistor disabled, LED Fault = 3.3V */
437 /* Vsync is enabled, Dither enabled, Boost voltage 20V */
439 /* PLL 13-bit counter */
441 /* 1-bit hysteresis w/10 bit resolution, PWM output freq is set with
442 PWM_FREQ EEPROM bits */
446 struct lp8550_platform_data stingray_lp8550_backlight_data = {
447 .power_up_brightness = 0x80,
448 .dev_ctrl_config = 0x04,
449 .brightness_control = 0x80,
452 .eeprom_table = stingray_lp8550_eeprom_data,
453 .eeprom_tbl_sz = ARRAY_SIZE(stingray_lp8550_eeprom_data),
456 static struct i2c_board_info __initdata stingray_i2c_bus1_led_info[] = {
458 I2C_BOARD_INFO(LD_LP8550_NAME, 0x2c),
459 .platform_data = &stingray_lp8550_backlight_data,
463 #ifdef CONFIG_HAS_EARLYSUSPEND
464 /* put early_suspend/late_resume handlers here for the display in order
465 * to keep the code out of the display driver, keeping it closer to upstream
467 struct early_suspend stingray_panel_early_suspender;
469 static void stingray_panel_early_suspend(struct early_suspend *h)
471 if (num_registered_fb > 0)
472 fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
475 static void stingray_panel_late_resume(struct early_suspend *h)
477 if (num_registered_fb > 0)
478 fb_blank(registered_fb[0], FB_BLANK_UNBLANK);
482 static struct regulator *stingray_csi_reg;
484 int __init stingray_panel_init(void)
486 struct resource *res;
488 if (stingray_revision() < STINGRAY_REVISION_P1) {
489 tegra_gpio_enable(STINGRAY_AUO_DISP_BL);
490 gpio_request(STINGRAY_AUO_DISP_BL, "auo_disp_bl");
491 gpio_direction_output(STINGRAY_AUO_DISP_BL, 1);
492 platform_device_register(&stingray_panel_bl_driver);
493 stingray_disp1_pdata.fb = &stingray_fb_data_p0;
494 stingray_disp1_out.modes = stingray_panel_modes_p0;
496 if (stingray_revision() >= STINGRAY_REVISION_P3)
497 stingray_lp8550_backlight_data.dev_ctrl_config = 0x02;
498 i2c_register_board_info(0, stingray_i2c_bus1_led_info,
499 ARRAY_SIZE(stingray_i2c_bus1_led_info));
502 platform_device_register(&stingray_panel_reg_device);
504 platform_driver_register(&stingray_panel_early_reg_driver);
505 platform_device_register(&stingray_panel_early_reg_device);
506 platform_device_register(&stingray_panel_early_reg_keyreset_device);
508 stingray_hdmi_init();
510 stingray_csi_reg = regulator_get(NULL, "vcsi");
511 if (IS_ERR(stingray_csi_reg)) {
512 pr_err("hdmi: couldn't get regulator vcsi");
514 regulator_enable(stingray_csi_reg);
517 #ifdef CONFIG_HAS_EARLYSUSPEND
518 stingray_panel_early_suspender.suspend = stingray_panel_early_suspend;
519 stingray_panel_early_suspender.resume = stingray_panel_late_resume;
520 stingray_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
521 register_early_suspend(&stingray_panel_early_suspender);
525 res = nvhost_get_resource_byname(&stingray_disp1_device,
526 IORESOURCE_MEM, "fbmem");
527 res->start = tegra_fb_start;
528 res->end = tegra_fb_start + tegra_fb_size - 1;
530 res = nvhost_get_resource_byname(&stingray_disp2_device,
531 IORESOURCE_MEM, "fbmem");
532 res->start = tegra_fb2_start;
533 res->end = tegra_fb2_start + tegra_fb2_size - 1;
535 tegra_move_framebuffer(tegra_fb_start, tegra_bootloader_fb_start,
536 min(tegra_fb_size, tegra_bootloader_fb_size));
538 nvhost_device_register(&stingray_disp1_device);
539 return nvhost_device_register(&stingray_disp2_device);