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