diff options
Diffstat (limited to 'arch/arm/mach-tegra/board-ventana-panel.c')
-rw-r--r-- | arch/arm/mach-tegra/board-ventana-panel.c | 457 |
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 | |||
49 | static struct regulator *pnl_pwr; | ||
50 | |||
51 | #ifdef CONFIG_TEGRA_DC | ||
52 | static struct regulator *ventana_hdmi_reg = NULL; | ||
53 | static struct regulator *ventana_hdmi_pll = NULL; | ||
54 | #endif | ||
55 | |||
56 | static 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 | |||
72 | static 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 | |||
78 | static int ventana_backlight_notify(struct device *unused, int brightness) | ||
79 | { | ||
80 | gpio_set_value(ventana_bl_enb, !!brightness); | ||
81 | return brightness; | ||
82 | } | ||
83 | |||
84 | static int ventana_disp1_check_fb(struct device *dev, struct fb_info *info); | ||
85 | |||
86 | static 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 | |||
98 | static 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 | ||
107 | static 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 | |||
133 | static int ventana_panel_disable(void) | ||
134 | { | ||
135 | gpio_set_value(ventana_lvds_shutdown, 0); | ||
136 | regulator_disable(pnl_pwr); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static 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 | |||
166 | static int ventana_hdmi_disable(void) | ||
167 | { | ||
168 | regulator_disable(ventana_hdmi_reg); | ||
169 | regulator_disable(ventana_hdmi_pll); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static 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 | |||
192 | static 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 | |||
217 | static 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 | |||
233 | static 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 | |||
241 | static 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 | |||
249 | static 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 | |||
264 | static 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 | |||
280 | static 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 | |||
286 | static 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 | |||
292 | static 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 | |||
302 | static int ventana_disp1_check_fb(struct device *dev, struct fb_info *info) | ||
303 | { | ||
304 | return info->device == &ventana_disp1_device.dev; | ||
305 | } | ||
306 | |||
307 | static 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 | ||
317 | static 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) | ||
324 | static 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 | |||
333 | static struct nvmap_platform_data ventana_nvmap_data = { | ||
334 | .carveouts = ventana_carveouts, | ||
335 | .nr_carveouts = ARRAY_SIZE(ventana_carveouts), | ||
336 | }; | ||
337 | |||
338 | static 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 | |||
347 | static 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 | */ | ||
359 | struct early_suspend ventana_panel_early_suspender; | ||
360 | |||
361 | static 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 | |||
382 | static 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 | |||
393 | int __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 | |||