Revert "Merge commit 'main-jb-2012.08.03-B4' into t114-0806"
[linux-2.6.git] / arch / arm / mach-tegra / board-harmony-panel.c
1 /*
2  * arch/arm/mach-tegra/board-harmony-panel.c
3  *
4  * Copyright (c) 2010-2012, NVIDIA Corporation.
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/delay.h>
18 #include <linux/resource.h>
19 #include <linux/platform_device.h>
20 #include <asm/mach-types.h>
21 #include <linux/nvhost.h>
22 #include <linux/gpio.h>
23 #include <linux/regulator/consumer.h>
24 #include <linux/pwm_backlight.h>
25
26 #include <mach/dc.h>
27 #include <mach/irqs.h>
28 #include <mach/iomap.h>
29 #include <linux/nvmap.h>
30 #include <mach/tegra_fb.h>
31 #include <mach/fb.h>
32 #include <mach/gpio-tegra.h>
33
34 #include "devices.h"
35 #include "gpio-names.h"
36 #include "board.h"
37 #include "tegra2_host1x_devices.h"
38
39 #define harmony_bl_enb          TEGRA_GPIO_PB5
40 #define harmony_lvds_shutdown   TEGRA_GPIO_PB2
41 #define harmony_en_vdd_pnl      TEGRA_GPIO_PC6
42 #define harmony_bl_vdd          TEGRA_GPIO_PW0
43 #define harmony_bl_pwm          TEGRA_GPIO_PB4
44 #define harmony_hdmi_hpd        TEGRA_GPIO_PN7
45
46 /* panel power on sequence timing */
47 #define harmony_pnl_to_lvds_ms  0
48 #define harmony_lvds_to_bl_ms   200
49
50 static int harmony_backlight_init(struct device *dev)
51 {
52         int ret;
53
54         ret = gpio_request(harmony_bl_enb, "backlight_enb");
55         if (ret < 0)
56                 return ret;
57
58         ret = gpio_direction_output(harmony_bl_enb, 1);
59         if (ret < 0)
60                 gpio_free(harmony_bl_enb);
61         else
62                 tegra_gpio_enable(harmony_bl_enb);
63
64         return ret;
65 }
66
67 static void harmony_backlight_exit(struct device *dev)
68 {
69         gpio_set_value(harmony_bl_enb, 0);
70         gpio_free(harmony_bl_enb);
71         tegra_gpio_disable(harmony_bl_enb);
72 }
73
74 static int harmony_backlight_notify(struct device *unused, int brightness)
75 {
76         gpio_set_value(harmony_en_vdd_pnl, !!brightness);
77         gpio_set_value(harmony_lvds_shutdown, !!brightness);
78         gpio_set_value(harmony_bl_enb, !!brightness);
79         return brightness;
80 }
81
82 static int harmony_disp1_check_fb(struct device *dev, struct fb_info *info);
83
84 static struct platform_pwm_backlight_data harmony_backlight_data = {
85         .pwm_id         = 0,
86         .max_brightness = 255,
87         .dft_brightness = 224,
88         .pwm_period_ns  = 5000000,
89         .init           = harmony_backlight_init,
90         .exit           = harmony_backlight_exit,
91         .notify         = harmony_backlight_notify,
92         /* Only toggle backlight on fb blank notifications for disp1 */
93         .check_fb       = harmony_disp1_check_fb,
94 };
95
96 static struct platform_device harmony_backlight_device = {
97         .name   = "pwm-backlight",
98         .id     = -1,
99         .dev    = {
100                 .platform_data = &harmony_backlight_data,
101         },
102 };
103
104 static int harmony_panel_enable(void)
105 {
106         gpio_set_value(harmony_en_vdd_pnl, 1);
107         mdelay(harmony_pnl_to_lvds_ms);
108         gpio_set_value(harmony_lvds_shutdown, 1);
109         mdelay(harmony_lvds_to_bl_ms);
110         return 0;
111 }
112
113 static int harmony_panel_disable(void)
114 {
115         gpio_set_value(harmony_lvds_shutdown, 0);
116         gpio_set_value(harmony_en_vdd_pnl, 0);
117         return 0;
118 }
119
120 static int harmony_set_hdmi_power(bool enable)
121 {
122         static struct {
123                 struct regulator *regulator;
124                 const char *name;
125         } regs[] = {
126                 { .name = "avdd_hdmi" },
127                 { .name = "avdd_hdmi_pll" },
128         };
129         int i;
130
131         for (i = 0; i < ARRAY_SIZE(regs); i++) {
132                 if (!regs[i].regulator) {
133                         regs[i].regulator = regulator_get(NULL, regs[i].name);
134
135                         if (IS_ERR(regs[i].regulator)) {
136                                 int ret = PTR_ERR(regs[i].regulator);
137                                 regs[i].regulator = NULL;
138                                 return ret;
139                         }
140                 }
141
142                 if (enable)
143                         regulator_enable(regs[i].regulator);
144                 else
145                         regulator_disable(regs[i].regulator);
146         }
147
148         return 0;
149 }
150
151 static int harmony_hdmi_enable(void)
152 {
153         return harmony_set_hdmi_power(true);
154 }
155
156 static int harmony_hdmi_disable(void)
157 {
158         return harmony_set_hdmi_power(false);
159 }
160
161 static struct resource harmony_disp1_resources[] = {
162         {
163                 .name = "irq",
164                 .start  = INT_DISPLAY_GENERAL,
165                 .end    = INT_DISPLAY_GENERAL,
166                 .flags  = IORESOURCE_IRQ,
167         },
168         {
169                 .name = "regs",
170                 .start  = TEGRA_DISPLAY_BASE,
171                 .end    = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE-1,
172                 .flags  = IORESOURCE_MEM,
173         },
174         {
175                 .name = "fbmem",
176                 .flags  = IORESOURCE_MEM,
177         },
178 };
179
180 static struct resource harmony_disp2_resources[] = {
181         {
182                 .name   = "irq",
183                 .start  = INT_DISPLAY_B_GENERAL,
184                 .end    = INT_DISPLAY_B_GENERAL,
185                 .flags  = IORESOURCE_IRQ,
186         },
187         {
188                 .name   = "regs",
189                 .start  = TEGRA_DISPLAY2_BASE,
190                 .end    = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
191                 .flags  = IORESOURCE_MEM,
192         },
193         {
194                 .name   = "fbmem",
195                 .flags  = IORESOURCE_MEM,
196         },
197         {
198                 .name   = "hdmi_regs",
199                 .start  = TEGRA_HDMI_BASE,
200                 .end    = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
201                 .flags  = IORESOURCE_MEM,
202         },
203 };
204
205 static struct tegra_dc_mode harmony_panel_modes[] = {
206         {
207                 .pclk = 42430000,
208                 .h_ref_to_sync = 4,
209                 .v_ref_to_sync = 2,
210                 .h_sync_width = 136,
211                 .v_sync_width = 4,
212                 .h_back_porch = 138,
213                 .v_back_porch = 21,
214                 .h_active = 1024,
215                 .v_active = 600,
216                 .h_front_porch = 34,
217                 .v_front_porch = 4,
218         },
219 };
220
221 static struct tegra_fb_data harmony_fb_data = {
222         .win            = 0,
223         .xres           = 1024,
224         .yres           = 600,
225         .bits_per_pixel = 32,
226         .flags          = TEGRA_FB_FLIP_ON_PROBE,
227 };
228
229 static struct tegra_fb_data harmony_hdmi_fb_data = {
230         .win            = 0,
231         .xres           = 1280,
232         .yres           = 720,
233         .bits_per_pixel = 16,
234 };
235
236 static struct tegra_dc_out harmony_disp1_out = {
237         .type           = TEGRA_DC_OUT_RGB,
238
239         .align          = TEGRA_DC_ALIGN_MSB,
240         .order          = TEGRA_DC_ORDER_RED_BLUE,
241         .depth          = 18,
242         .dither         = TEGRA_DC_ORDERED_DITHER,
243
244         .modes          = harmony_panel_modes,
245         .n_modes        = ARRAY_SIZE(harmony_panel_modes),
246
247         .enable         = harmony_panel_enable,
248         .disable        = harmony_panel_disable,
249 };
250
251 static struct tegra_dc_out harmony_disp2_out = {
252         .type           = TEGRA_DC_OUT_HDMI,
253         .flags          = TEGRA_DC_OUT_HOTPLUG_HIGH,
254
255         .dcc_bus        = 1,
256         .hotplug_gpio   = harmony_hdmi_hpd,
257
258         .align          = TEGRA_DC_ALIGN_MSB,
259         .order          = TEGRA_DC_ORDER_RED_BLUE,
260
261         .enable         = harmony_hdmi_enable,
262         .disable        = harmony_hdmi_disable,
263 };
264
265 static struct tegra_dc_platform_data harmony_disp1_pdata = {
266         .flags          = TEGRA_DC_FLAG_ENABLED,
267         .default_out    = &harmony_disp1_out,
268         .fb             = &harmony_fb_data,
269 };
270
271 static struct tegra_dc_platform_data harmony_disp2_pdata = {
272         .flags          = 0,
273         .default_out    = &harmony_disp2_out,
274         .fb             = &harmony_hdmi_fb_data,
275 };
276
277 static struct nvhost_device harmony_disp1_device = {
278         .name           = "tegradc",
279         .id             = 0,
280         .resource       = harmony_disp1_resources,
281         .num_resources  = ARRAY_SIZE(harmony_disp1_resources),
282         .dev = {
283                 .platform_data = &harmony_disp1_pdata,
284         },
285 };
286
287 static int harmony_disp1_check_fb(struct device *dev, struct fb_info *info)
288 {
289         return info->device == &harmony_disp1_device.dev;
290 }
291
292 static struct nvhost_device harmony_disp2_device = {
293         .name           = "tegradc",
294         .id             = 1,
295         .resource       = harmony_disp2_resources,
296         .num_resources  = ARRAY_SIZE(harmony_disp2_resources),
297         .dev = {
298                 .platform_data = &harmony_disp2_pdata,
299         },
300 };
301
302 #if defined(CONFIG_TEGRA_NVMAP)
303 static struct nvmap_platform_carveout harmony_carveouts[] = {
304         [0] = NVMAP_HEAP_CARVEOUT_IRAM_INIT,
305         [1] = {
306                 .name           = "generic-0",
307                 .usage_mask     = NVMAP_HEAP_CARVEOUT_GENERIC,
308                 .buddy_size     = SZ_32K,
309         },
310 };
311
312 static struct nvmap_platform_data harmony_nvmap_data = {
313         .carveouts      = harmony_carveouts,
314         .nr_carveouts   = ARRAY_SIZE(harmony_carveouts),
315 };
316
317 static struct platform_device harmony_nvmap_device = {
318         .name   = "tegra-nvmap",
319         .id     = -1,
320         .dev    = {
321                 .platform_data = &harmony_nvmap_data,
322         },
323 };
324 #endif
325
326 static struct platform_device *harmony_gfx_devices[] __initdata = {
327 #if defined(CONFIG_TEGRA_NVMAP)
328         &harmony_nvmap_device,
329 #endif
330         &tegra_pwfm0_device,
331         &harmony_backlight_device,
332 };
333
334 int __init harmony_panel_init(void)
335 {
336         int err;
337         struct resource *res;
338
339         gpio_request(harmony_en_vdd_pnl, "en_vdd_pnl");
340         gpio_direction_output(harmony_en_vdd_pnl, 1);
341         tegra_gpio_enable(harmony_en_vdd_pnl);
342
343         gpio_request(harmony_bl_vdd, "bl_vdd");
344         gpio_direction_output(harmony_bl_vdd, 1);
345         tegra_gpio_enable(harmony_bl_vdd);
346
347         gpio_request(harmony_lvds_shutdown, "lvds_shdn");
348         gpio_direction_output(harmony_lvds_shutdown, 1);
349         tegra_gpio_enable(harmony_lvds_shutdown);
350
351         gpio_request(harmony_hdmi_hpd, "hdmi_hpd");
352         gpio_direction_input(harmony_hdmi_hpd);
353         tegra_gpio_enable(harmony_hdmi_hpd);
354
355 #if defined(CONFIG_TEGRA_NVMAP)
356         harmony_carveouts[1].base = tegra_carveout_start;
357         harmony_carveouts[1].size = tegra_carveout_size;
358 #endif
359
360 #ifdef CONFIG_TEGRA_GRHOST
361         err = tegra2_register_host1x_devices();
362         if (err)
363                 return err;
364 #endif
365
366         err = platform_add_devices(harmony_gfx_devices,
367                                    ARRAY_SIZE(harmony_gfx_devices));
368         if (err)
369                 return err;
370
371         res = nvhost_get_resource_byname(&harmony_disp1_device,
372                 IORESOURCE_MEM, "fbmem");
373         if (res) {
374                 res->start = tegra_fb_start;
375                 res->end = tegra_fb_start + tegra_fb_size - 1;
376         }
377
378         res = nvhost_get_resource_byname(&harmony_disp2_device,
379                 IORESOURCE_MEM, "fbmem");
380         if (res) {
381                 res->start = tegra_fb2_start;
382                 res->end = tegra_fb2_start + tegra_fb2_size - 1;
383         }
384
385         /* Copy the bootloader fb to the fb. */
386         if (tegra_bootloader_fb_start)
387                 tegra_move_framebuffer(tegra_fb_start,
388                         tegra_bootloader_fb_start,
389                         min(tegra_fb_size, tegra_bootloader_fb_size));
390         err = nvhost_device_register(&harmony_disp1_device);
391         if (err)
392                 return err;
393
394         err = nvhost_device_register(&harmony_disp2_device);
395         if (err)
396                 return err;
397
398         return 0;
399 }
400