29cdaa9fe9fb0bf9aed11cae9082bc9e19164cef
[linux-2.6.git] / arch / arm / mach-tegra / board-ventana-panel.c
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 #ifdef CONFIG_HAS_EARLYSUSPEND
28 #include <linux/earlysuspend.h>
29 #endif
30 #include <linux/pwm_backlight.h>
31 #include <linux/nvhost.h>
32 #include <linux/nvmap.h>
33 #include <mach/gpio-tegra.h>
34 #include <mach/irqs.h>
35 #include <mach/iomap.h>
36 #include <mach/dc.h>
37 #include <mach/fb.h>
38
39 #include "devices.h"
40 #include "gpio-names.h"
41 #include "board.h"
42
43 #define ventana_bl_enb          TEGRA_GPIO_PD4
44 #define ventana_lvds_shutdown   TEGRA_GPIO_PB2
45 #define ventana_hdmi_hpd        TEGRA_GPIO_PN7
46 #define ventana_hdmi_enb        TEGRA_GPIO_PV5
47
48 /*panel power on sequence timing*/
49 #define ventana_pnl_to_lvds_ms  0
50 #define ventana_lvds_to_bl_ms   200
51
52 static struct regulator *pnl_pwr;
53
54 #ifdef CONFIG_TEGRA_DC
55 static struct regulator *ventana_hdmi_reg = NULL;
56 static struct regulator *ventana_hdmi_pll = NULL;
57 #endif
58
59 static int ventana_backlight_init(struct device *dev) {
60         int ret;
61
62         ret = gpio_request(ventana_bl_enb, "backlight_enb");
63         if (ret < 0)
64                 return ret;
65
66         ret = gpio_direction_output(ventana_bl_enb, 1);
67         if (ret < 0)
68                 gpio_free(ventana_bl_enb);
69
70         return ret;
71 };
72
73 static void ventana_backlight_exit(struct device *dev) {
74         gpio_set_value(ventana_bl_enb, 0);
75         gpio_free(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           = 640,
244         .yres           = 480,
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_store_default_gov();
370         if (cpufreq_change_gov(cpufreq_conservative_gov))
371                 pr_err("Early_suspend: Error changing governor to %s\n",
372                                 cpufreq_conservative_gov);
373 #endif
374 }
375
376 static void ventana_panel_late_resume(struct early_suspend *h)
377 {
378         unsigned i;
379 #ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
380         if (cpufreq_restore_default_gov())
381                 pr_err("Early_suspend: Unable to restore governor\n");
382 #endif
383         for (i = 0; i < num_registered_fb; i++)
384                 fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
385 }
386 #endif
387
388 int __init ventana_panel_init(void)
389 {
390         int err;
391         struct resource __maybe_unused *res;
392
393         gpio_request(ventana_lvds_shutdown, "lvds_shdn");
394         gpio_direction_output(ventana_lvds_shutdown, 1);
395
396         gpio_request(ventana_hdmi_enb, "hdmi_5v_en");
397         gpio_direction_output(ventana_hdmi_enb, 1);
398
399         gpio_request(ventana_hdmi_hpd, "hdmi_hpd");
400         gpio_direction_input(ventana_hdmi_hpd);
401
402 #ifdef CONFIG_HAS_EARLYSUSPEND
403         ventana_panel_early_suspender.suspend = ventana_panel_early_suspend;
404         ventana_panel_early_suspender.resume = ventana_panel_late_resume;
405         ventana_panel_early_suspender.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
406         register_early_suspend(&ventana_panel_early_suspender);
407 #endif
408
409 #if defined(CONFIG_TEGRA_NVMAP)
410         ventana_carveouts[1].base = tegra_carveout_start;
411         ventana_carveouts[1].size = tegra_carveout_size;
412 #endif
413
414 #ifdef CONFIG_TEGRA_GRHOST
415         err = nvhost_device_register(&tegra_grhost_device);
416         if (err)
417                 return err;
418 #endif
419
420         err = platform_add_devices(ventana_gfx_devices,
421                                    ARRAY_SIZE(ventana_gfx_devices));
422
423 #if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
424         res = nvhost_get_resource_byname(&ventana_disp1_device,
425                 IORESOURCE_MEM, "fbmem");
426         res->start = tegra_fb_start;
427         res->end = tegra_fb_start + tegra_fb_size - 1;
428
429         res = nvhost_get_resource_byname(&ventana_disp2_device,
430                 IORESOURCE_MEM, "fbmem");
431         res->start = tegra_fb2_start;
432         res->end = tegra_fb2_start + tegra_fb2_size - 1;
433 #endif
434
435         /* Copy the bootloader fb to the fb. */
436         tegra_move_framebuffer(tegra_fb_start, tegra_bootloader_fb_start,
437                 min(tegra_fb_size, tegra_bootloader_fb_size));
438
439         /* Copy the bootloader fb to the fb2. */
440         tegra_move_framebuffer(tegra_fb2_start, tegra_bootloader_fb_start,
441                 min(tegra_fb2_size, tegra_bootloader_fb_size));
442
443
444 #if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
445         if (!err)
446                 err = nvhost_device_register(&ventana_disp1_device);
447
448         if (!err)
449                 err = nvhost_device_register(&ventana_disp2_device);
450 #endif
451
452         return err;
453 }
454