aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/board-ventana-panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/board-ventana-panel.c')
-rw-r--r--arch/arm/mach-tegra/board-ventana-panel.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-ventana-panel.c b/arch/arm/mach-tegra/board-ventana-panel.c
new file mode 100644
index 00000000000..4cacd3dc421
--- /dev/null
+++ b/arch/arm/mach-tegra/board-ventana-panel.c
@@ -0,0 +1,457 @@
1/*
2 * arch/arm/mach-tegra/board-ventana-panel.c
3 *
4 * Copyright (c) 2010-2012, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include <linux/delay.h>
22#include <linux/gpio.h>
23#include <linux/regulator/consumer.h>
24#include <linux/resource.h>
25#include <asm/mach-types.h>
26#include <linux/platform_device.h>
27#include <linux/earlysuspend.h>
28#include <linux/pwm_backlight.h>
29#include <linux/nvhost.h>
30#include <mach/nvmap.h>
31#include <mach/irqs.h>
32#include <mach/iomap.h>
33#include <mach/dc.h>
34#include <mach/fb.h>
35
36#include "devices.h"
37#include "gpio-names.h"
38#include "board.h"
39
40#define ventana_bl_enb TEGRA_GPIO_PD4
41#define ventana_lvds_shutdown TEGRA_GPIO_PB2
42#define ventana_hdmi_hpd TEGRA_GPIO_PN7
43#define ventana_hdmi_enb TEGRA_GPIO_PV5
44
45/*panel power on sequence timing*/
46#define ventana_pnl_to_lvds_ms 0
47#define ventana_lvds_to_bl_ms 200
48
49static struct regulator *pnl_pwr;
50
51#ifdef CONFIG_TEGRA_DC
52static struct regulator *ventana_hdmi_reg = NULL;
53static struct regulator *ventana_hdmi_pll = NULL;
54#endif
55
56static int ventana_backlight_init(struct device *dev) {
57 int ret;
58
59 ret = gpio_request(ventana_bl_enb, "backlight_enb");
60 if (ret < 0)
61 return ret;
62
63 ret = gpio_direction_output(ventana_bl_enb, 1);
64 if (ret < 0)
65 gpio_free(ventana_bl_enb);
66 else
67 tegra_gpio_enable(ventana_bl_enb);
68
69 return ret;
70};
71
72static void ventana_backlight_exit(struct device *dev) {
73 gpio_set_value(ventana_bl_enb, 0);
74 gpio_free(ventana_bl_enb);
75 tegra_gpio_disable(ventana_bl_enb);
76}
77
78static int ventana_backlight_notify(struct device *unused, int brightness)
79{
80 gpio_set_value(ventana_bl_enb, !!brightness);
81 return brightness;
82}
83
84static int ventana_disp1_check_fb(struct device *dev, struct fb_info *info);
85
86static struct platform_pwm_backlight_data ventana_backlight_data = {
87 .pwm_id = 2,
88 .max_brightness = 255,
89 .dft_brightness = 224,
90 .pwm_period_ns = 5000000,
91 .init = ventana_backlight_init,
92 .exit = ventana_backlight_exit,
93 .notify = ventana_backlight_notify,
94 /* Only toggle backlight on fb blank notifications for disp1 */
95 .check_fb = ventana_disp1_check_fb,
96};
97
98static struct platform_device ventana_backlight_device = {
99 .name = "pwm-backlight",
100 .id = -1,
101 .dev = {
102 .platform_data = &ventana_backlight_data,
103 },
104};
105
106#ifdef CONFIG_TEGRA_DC
107static int ventana_panel_enable(void)
108{
109 struct regulator *reg = regulator_get(NULL, "vdd_ldo4");
110
111 if (!reg) {
112 regulator_enable(reg);
113 regulator_put(reg);
114 }
115
116 if (pnl_pwr == NULL) {
117 pnl_pwr = regulator_get(NULL, "pnl_pwr");
118 if (WARN_ON(IS_ERR(pnl_pwr)))
119 pr_err("%s: couldn't get regulator pnl_pwr: %ld\n",
120 __func__, PTR_ERR(pnl_pwr));
121 else
122 regulator_enable(pnl_pwr);
123 } else {
124 regulator_enable(pnl_pwr);
125 }
126
127 mdelay(ventana_pnl_to_lvds_ms);
128 gpio_set_value(ventana_lvds_shutdown, 1);
129 mdelay(ventana_lvds_to_bl_ms);
130 return 0;
131}
132
133static int ventana_panel_disable(void)
134{
135 gpio_set_value(ventana_lvds_shutdown, 0);
136 regulator_disable(pnl_pwr);
137 return 0;
138}
139
140static int ventana_hdmi_enable(void)
141{
142 if (!ventana_hdmi_reg) {
143 ventana_hdmi_reg = regulator_get(NULL, "avdd_hdmi"); /* LD07 */
144 if (IS_ERR_OR_NULL(ventana_hdmi_reg)) {
145 pr_err("hdmi: couldn't get regulator avdd_hdmi\n");
146 ventana_hdmi_reg = NULL;
147 return PTR_ERR(ventana_hdmi_reg);
148 }
149 }
150 regulator_enable(ventana_hdmi_reg);
151
152 if (!ventana_hdmi_pll) {
153 ventana_hdmi_pll = regulator_get(NULL, "avdd_hdmi_pll"); /* LD08 */
154 if (IS_ERR_OR_NULL(ventana_hdmi_pll)) {
155 pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n");
156 ventana_hdmi_pll = NULL;
157 regulator_disable(ventana_hdmi_reg);
158 ventana_hdmi_reg = NULL;
159 return PTR_ERR(ventana_hdmi_pll);
160 }
161 }
162 regulator_enable(ventana_hdmi_pll);
163 return 0;
164}
165
166static int ventana_hdmi_disable(void)
167{
168 regulator_disable(ventana_hdmi_reg);
169 regulator_disable(ventana_hdmi_pll);
170 return 0;
171}
172
173static struct resource ventana_disp1_resources[] = {
174 {
175 .name = "irq",
176 .start = INT_DISPLAY_GENERAL,
177 .end = INT_DISPLAY_GENERAL,
178 .flags = IORESOURCE_IRQ,
179 },
180 {
181 .name = "regs",
182 .start = TEGRA_DISPLAY_BASE,
183 .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1,
184 .flags = IORESOURCE_MEM,
185 },
186 {
187 .name = "fbmem",
188 .flags = IORESOURCE_MEM,
189 },
190};
191
192static struct resource ventana_disp2_resources[] = {
193 {
194 .name = "irq",
195 .start = INT_DISPLAY_B_GENERAL,
196 .end = INT_DISPLAY_B_GENERAL,
197 .flags = IORESOURCE_IRQ,
198 },
199 {
200 .name = "regs",
201 .start = TEGRA_DISPLAY2_BASE,
202 .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
203 .flags = IORESOURCE_MEM,
204 },
205 {
206 .name = "fbmem",
207 .flags = IORESOURCE_MEM,
208 },
209 {
210 .name = "hdmi_regs",
211 .start = TEGRA_HDMI_BASE,
212 .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
213 .flags = IORESOURCE_MEM,
214 },
215};
216
217static struct tegra_dc_mode ventana_panel_modes[] = {
218 {
219 .pclk = 72072000,
220 .h_ref_to_sync = 11,
221 .v_ref_to_sync = 1,
222 .h_sync_width = 58,
223 .v_sync_width = 4,
224 .h_back_porch = 58,
225 .v_back_porch = 4,
226 .h_active = 1366,
227 .v_active = 768,
228 .h_front_porch = 58,
229 .v_front_porch = 4,
230 },
231};
232
233static struct tegra_fb_data ventana_fb_data = {
234 .win = 0,
235 .xres = 1366,
236 .yres = 768,
237 .bits_per_pixel = 32,
238 .flags = TEGRA_FB_FLIP_ON_PROBE,
239};
240
241static struct tegra_fb_data ventana_hdmi_fb_data = {
242 .win = 0,
243 .xres = 1366,
244 .yres = 768,
245 .bits_per_pixel = 32,
246 .flags = TEGRA_FB_FLIP_ON_PROBE,
247};
248
249static struct tegra_dc_out ventana_disp1_out = {
250 .type = TEGRA_DC_OUT_RGB,
251
252 .align = TEGRA_DC_ALIGN_MSB,
253 .order = TEGRA_DC_ORDER_RED_BLUE,
254 .depth = 18,
255 .dither = TEGRA_DC_ORDERED_DITHER,
256
257 .modes = ventana_panel_modes,
258 .n_modes = ARRAY_SIZE(ventana_panel_modes),
259
260 .enable = ventana_panel_enable,
261 .disable = ventana_panel_disable,
262};
263
264static struct tegra_dc_out ventana_disp2_out = {
265 .type = TEGRA_DC_OUT_HDMI,
266 .flags = TEGRA_DC_OUT_HOTPLUG_HIGH,
267
268 .dcc_bus = 1,
269 .hotplug_gpio = ventana_hdmi_hpd,
270
271 .max_pixclock = KHZ2PICOS(148500),
272
273 .align = TEGRA_DC_ALIGN_MSB,
274 .order = TEGRA_DC_ORDER_RED_BLUE,
275
276 .enable = ventana_hdmi_enable,
277 .disable = ventana_hdmi_disable,
278};
279
280static struct tegra_dc_platform_data ventana_disp1_pdata = {
281 .flags = TEGRA_DC_FLAG_ENABLED,
282 .default_out = &ventana_disp1_out,
283 .fb = &ventana_fb_data,
284};
285
286static struct tegra_dc_platform_data ventana_disp2_pdata = {
287 .flags = 0,
288 .default_out = &ventana_disp2_out,
289 .fb = &ventana_hdmi_fb_data,
290};
291
292static struct nvhost_device ventana_disp1_device = {
293 .name = "tegradc",
294 .id = 0,
295 .resource = ventana_disp1_resources,
296 .num_resources = ARRAY_SIZE(ventana_disp1_resources),
297 .dev = {
298 .platform_data = &ventana_disp1_pdata,
299 },
300};
301
302static int ventana_disp1_check_fb(struct device *dev, struct fb_info *info)
303{
304 return info->device == &ventana_disp1_device.dev;
305}
306
307static struct nvhost_device ventana_disp2_device = {
308 .name = "tegradc",
309 .id = 1,
310 .resource = ventana_disp2_resources,
311 .num_resources = ARRAY_SIZE(ventana_disp2_resources),
312 .dev = {
313 .platform_data = &ventana_disp2_pdata,
314 },
315};
316#else
317static int ventana_disp1_check_fb(struct device *dev, struct fb_info *info)
318{
319 return 0;
320}
321#endif
322
323#if defined(CONFIG_TEGRA_NVMAP)
324static struct nvmap_platform_carveout ventana_carveouts[] = {
325 [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT,
326 [1] = {
327 .name = "generic-0",
328 .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC,
329 .buddy_size = SZ_32K,
330 },
331};
332
333static struct nvmap_platform_data ventana_nvmap_data = {
334 .carveouts = ventana_carveouts,
335 .nr_carveouts = ARRAY_SIZE(ventana_carveouts),
336};
337
338static struct platform_device ventana_nvmap_device = {
339 .name = "tegra-nvmap",
340 .id = -1,
341 .dev = {
342 .platform_data = &ventana_nvmap_data,
343 },
344};
345#endif
346
347static struct platform_device *ventana_gfx_devices[] __initdata = {
348#if defined(CONFIG_TEGRA_NVMAP)
349 &ventana_nvmap_device,
350#endif
351 &tegra_pwfm2_device,
352 &ventana_backlight_device,
353};
354
355#ifdef CONFIG_HAS_EARLYSUSPEND
356/* put early_suspend/late_resume handlers here for the display in order
357 * to keep the code out of the display driver, keeping it closer to upstream
358 */
359struct early_suspend ventana_panel_early_suspender;
360
361static void ventana_panel_early_suspend(struct early_suspend *h)
362{
363 /* power down LCD, add use a black screen for HDMI */
364 if (num_registered_fb > 0)
365 fb_blank(registered_fb[0], FB_BLANK_POWERDOWN);
366 if (num_registered_fb > 1)
367 fb_blank(registered_fb[1], FB_BLANK_NORMAL);
368#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
369 cpufreq_save_default_governor();
370 cpufreq_set_conservative_governor();
371 cpufreq_set_conservative_governor_param("up_threshold",
372 SET_CONSERVATIVE_GOVERNOR_UP_THRESHOLD);
373
374 cpufreq_set_conservative_governor_param("down_threshold",
375 SET_CONSERVATIVE_GOVERNOR_DOWN_THRESHOLD);
376
377 cpufreq_set_conservative_governor_param("freq_step",
378 SET_CONSERVATIVE_GOVERNOR_FREQ_STEP);
379#endif
380}
381
382static void ventana_panel_late_resume(struct early_suspend *h)
383{
384 unsigned i;
385#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
386 cpufreq_restore_default_governor();
387#endif
388 for (i = 0; i < num_registered_fb; i++)
389 fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
390}
391#endif
392
393int __init ventana_panel_init(void)
394{
395 int err;
396 struct resource __maybe_unused *res;
397
398 gpio_request(ventana_lvds_shutdown, "lvds_shdn");
399 gpio_direction_output(ventana_lvds_shutdown, 1);
400 tegra_gpio_enable(ventana_lvds_shutdown);
401
402 tegra_gpio_enable(ventana_hdmi_enb);
403 gpio_request(ventana_hdmi_enb, "hdmi_5v_en");
404 gpio_direction_output(ventana_hdmi_enb, 1);
405
406 tegra_gpio_enable(ventana_hdmi_hpd);
407 gpio_request(ventana_hdmi_hpd, "hdmi_hpd");
408 gpio_direction_input(ventana_hdmi_hpd);
409
410#ifdef CONFIG_HAS_EARLYSUSPEND
411 ventana_panel_early_suspender.suspend = ventana_panel_early_suspend;
412 ventana_panel_early_suspender.resume = ventana_panel_late_resume;
413 ventana_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
414 register_early_suspend(&ventana_panel_early_suspender);
415#endif
416
417#if defined(CONFIG_TEGRA_NVMAP)
418 ventana_carveouts[1].base = tegra_carveout_start;
419 ventana_carveouts[1].size = tegra_carveout_size;
420#endif
421
422#ifdef CONFIG_TEGRA_GRHOST
423 err = nvhost_device_register(&tegra_grhost_device);
424 if (err)
425 return err;
426#endif
427
428 err = platform_add_devices(ventana_gfx_devices,
429 ARRAY_SIZE(ventana_gfx_devices));
430
431#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
432 res = nvhost_get_resource_byname(&ventana_disp1_device,
433 IORESOURCE_MEM, "fbmem");
434 res->start = tegra_fb_start;
435 res->end = tegra_fb_start + tegra_fb_size - 1;
436
437 res = nvhost_get_resource_byname(&ventana_disp2_device,
438 IORESOURCE_MEM, "fbmem");
439 res->start = tegra_fb2_start;
440 res->end = tegra_fb2_start + tegra_fb2_size - 1;
441#endif
442
443 /* Copy the bootloader fb to the fb. */
444 tegra_move_framebuffer(tegra_fb_start, tegra_bootloader_fb_start,
445 min(tegra_fb_size, tegra_bootloader_fb_size));
446
447#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
448 if (!err)
449 err = nvhost_device_register(&ventana_disp1_device);
450
451 if (!err)
452 err = nvhost_device_register(&ventana_disp2_device);
453#endif
454
455 return err;
456}
457