📄 omap_disp_out.c
字号:
/* * drivers/video/omap/omap2_disp_out.c * * Driver for LCD and TV output on OMAP24xx SDPs * - Tested on OMAP2420 H4 * * Copyright (C) 2005-2006 Texas Instruments, Inc. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. * * History: * 30-Mar-2006 Khasim Added LCD data lines 18/16 support * 15-Apr-2006 Khasim Modified proc fs to sysfs * 20-Apr-2006 Khasim Modified PM/DPM support for Mobi-Linux */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/types.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/i2c.h>#include <linux/proc_fs.h>#include <linux/fb.h>#include <linux/delay.h>#include <asm/hardware.h>#include <asm/uaccess.h>#include <asm/delay.h>#include <linux/delay.h>#include <asm/arch/display.h>#include <asm/arch/gpio.h>#include <asm/arch/clock.h>#include <asm/arch/twl4030.h>#include <linux/workqueue.h>#include <asm/arch/power_companion.h>#include <linux/notifier.h>#include <linux/pm.h>#include <linux/platform_device.h>#include "omap_fb.h"#define DRIVER "omap2_disp_out"#define DRIVER_DESC "OMAP Display output driver"#define OMAP2_LCD_DRIVER "omap2_lcd"#define OMAP2_TV_DRIVER "omap2_tv"#define OMAP24xx_LCD_DEVICE "omap2_lcd"#define OMAP24xx_TV_DEVICE "omap2_tv"#define H4_LCD_XRES 1024 // 1024#define H4_LCD_YRES 768 // 720#define H4_LCD_PIXCLOCK_MAX 41700 /* in pico seconds */#define H4_LCD_PIXCLOCK_MIN 38000 /* in pico seconds */#define H4_TV_XRES 640#define H4_TV_YRES 480#define LCD_PANEL_ENABLE_GPIO 28#define LCD_PANEL_BACKLIGHT_GPIO 24#define CONFIG_OMAP2_LCD#define ENABLE_VDAC_DEDICATED 0x03#define ENABLE_VDAC_DEV_GRP 0x20 #define ENABLE_VPLL2_DEDICATED 0x05#define ENABLE_VPLL2_DEV_GRP 0xE0#define CONFIG_OMAP2_TV#define MENELAUS_I2C_ADAP_ID 0#define CONFIG_TWL4030_CORE_T2#define CONFIG_I2C_TWL4030_COREextern int omap24xx_get_dss1_clock(void);extern ssize_t fb_out_show(struct class_device *cdev, char *buf);extern ssize_t fb_out_store(struct class_device *cdev, const char *buffer, size_t count);extern int fb_out_layer;extern int omap24xxfb_set_output_layer(int layer);extern int twl4030_request_gpio(int gpio);extern int twl4030_free_gpio(int gpio);extern int twl4030_set_gpio_dataout(int gpio, int enable);extern int twl4030_set_gpio_direction(int gpio, int is_input);extern int lpr_enabled;/*---------------------------------------------------------------------------*/static int lcd_in_use;static int lcd_backlight_state=1;static int previous_lcd_backlight_state=1;static void lcd_backlight_off(struct work_struct *work);static void lcd_backlight_on(struct work_struct *work);#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNTDECLARE_WORK(lcd_bklight_on, lcd_backlight_on);DECLARE_WORK(lcd_bklight_off, lcd_backlight_off);static void lcd_panel_enable(struct work_struct *work);static void lcd_panel_disable(struct work_struct *work);DECLARE_WORK(lcd_panel_on, lcd_panel_enable);DECLARE_WORK(lcd_panel_off, lcd_panel_disable);static voidpower_lcd_backlight(int level){ switch (level) { case LCD_OFF: if(!in_interrupt()) lcd_backlight_off(NULL); else schedule_work(&lcd_bklight_off); break; default: if(!in_interrupt()) lcd_backlight_on(NULL); else schedule_work(&lcd_bklight_on); break; }}static voidpower_lcd_panel(int level){ switch (level) { case LCD_OFF: if(!in_interrupt()) lcd_panel_disable(NULL); else schedule_work(&lcd_panel_off); break; default: if(!in_interrupt()) lcd_panel_enable(NULL); else schedule_work(&lcd_panel_on); break; }}static voidlcd_panel_enable(struct work_struct *work){}voidomap2_dss_rgb_enable(void){ if(is_sil_rev_less_than(OMAP3430_REV_ES2_0)) { if( 0 != twl4030_vaux3_ldo_use()) printk(KERN_WARNING "omap2_disp: twl4030_vaux3_ldo_use returns error \n"); } else { twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER, ENABLE_VPLL2_DEDICATED,TWL4030_VPLL2_DEDICATED); twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER, ENABLE_VPLL2_DEV_GRP,TWL4030_VPLL2_DEV_GRP); mdelay(4); }}EXPORT_SYMBOL(omap2_dss_rgb_enable);static voidlcd_panel_disable(struct work_struct *work){}voidomap2_dss_rgb_disable(void){ if(is_sil_rev_less_than(OMAP3430_REV_ES2_0)) { if( 0 != twl4030_vaux3_ldo_unuse()) printk(KERN_WARNING "omap2_disp: twl4030_vaux3_ldo_unuse returns error \n"); } else { twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER, 0x0,TWL4030_VPLL2_DEDICATED); twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER, 0x0,TWL4030_VPLL2_DEV_GRP); mdelay(4); }}EXPORT_SYMBOL(omap2_dss_rgb_disable);static voidlcd_backlight_on(struct work_struct *work){}static voidlcd_backlight_off(struct work_struct *work){}void enable_backlight(void){ /* If already enabled, return*/ if (lcd_in_use) return; if (previous_lcd_backlight_state == LCD_ON) { power_lcd_backlight(LCD_ON); } lcd_in_use = 1;}EXPORT_SYMBOL(enable_backlight);void disable_backlight(void){ /* If LCD is already disabled, return*/ if (!lcd_in_use) return; previous_lcd_backlight_state = lcd_backlight_state; power_lcd_backlight(LCD_OFF); lcd_in_use = 0;}EXPORT_SYMBOL(disable_backlight);static int gpio_reserved = 0;int omap_lcd_init(struct omap_lcd_info *info){ u32 pixclock = H4_LCD_PIXCLOCK_MAX,/* picoseconds */ left_margin = 39, /* pixclocks */ right_margin = 45, /* pixclocks */ upper_margin = 1, /* line clocks */ lower_margin = 0, /* line clocks */ hsync_len = 3, /* pixclocks */ vsync_len = 2, /* line clocks */ sync = 1, /* hsync & vsync polarity */ acb = 0x28, /* AC-bias pin frequency */ ipc = 1, /* Invert pixel clock */ onoff = 1; /* HSYNC/VSYNC Pixel clk Control*/ u32 clkdiv; if (info) { pixclock = info->pixclock, left_margin = info->left_margin, right_margin = info->right_margin, upper_margin = info->upper_margin, lower_margin = info->lower_margin, hsync_len = info->hsync_len, vsync_len = info->vsync_len, sync = info->sync, acb = info->acb, ipc = info->ipc, onoff = info->onoff; } if (gpio_reserved == 1) goto bypass_gpio;bypass_gpio: gpio_reserved = 1; omap2_dss_rgb_enable(); omap2_disp_get_dss(); omap2_disp_set_panel_size(OMAP2_OUTPUT_LCD, H4_LCD_XRES, H4_LCD_YRES); /* clkdiv = pixclock / (omap2 dss1 clock period) */ clkdiv = pixclock / (1000000000UL/omap24xx_get_dss1_clock()); clkdiv /= 1000; omap2_disp_config_lcd(clkdiv, left_margin - 1, // hbp right_margin - 1, // hfp hsync_len - 1, // hsw upper_margin, // vbp lower_margin, // vfp vsync_len - 1 // vsw ); omap2_disp_lcdcfg_polfreq( sync, // horizontal sync active low sync, // vertical sync active low acb, // ACB ipc, // IPC onoff // ONOFF ); omap2_disp_enable_output_dev(OMAP2_OUTPUT_LCD); udelay(20); enable_backlight(); power_lcd_panel(LCD_ON); omap2_disp_put_dss(); printk(KERN_DEBUG DRIVER "LCD panel %dx%d\n", H4_LCD_XRES, H4_LCD_YRES); return 0;}static intlcd_exit(void){ if (!lcd_in_use) return 0; omap2_disp_get_dss(); omap2_disp_disable_output_dev(OMAP2_OUTPUT_LCD); omap2_disp_put_dss(); lcd_in_use = 0; return 0;}/* ------------------------------------------------------------------------------ *//* Power and device Management */static int __initlcd_probe(struct platform_device *odev){ return omap_lcd_init(0);}static int lcd_suspend(struct platform_device *odev, pm_message_t state);static int lcd_resume(struct platform_device *odev);static struct platform_driver omap2_lcd_driver = { .driver = { .name = OMAP2_LCD_DRIVER, }, .probe = lcd_probe, .suspend = lcd_suspend, .resume = lcd_resume,};static struct platform_device lcd_device = { .name = OMAP24xx_LCD_DEVICE, .id = 9,};static intlcd_suspend(struct platform_device *odev, pm_message_t state){ if (!lcd_in_use) return 0; disable_backlight(); omap2_dss_rgb_disable(); return 0;}static intlcd_resume(struct platform_device *odev){ if (lcd_in_use) return 0; omap2_dss_rgb_enable(); udelay(20); enable_backlight(); return 0;}/*---------------------------------------------------------------------------*/static int tv_in_use;static void h4_i2c_tvout_off(struct work_struct *work);static void h4_i2c_tvout_on(struct work_struct *work);DECLARE_WORK(h4_tvout_on, h4_i2c_tvout_on);DECLARE_WORK(h4_tvout_off, h4_i2c_tvout_off);static voidpower_tv(int level){ switch(level) { case TV_OFF: if(!in_interrupt()) h4_i2c_tvout_off(NULL); else schedule_work(&h4_tvout_off); break; default: if(!in_interrupt()) h4_i2c_tvout_on(NULL); else schedule_work(&h4_tvout_on); break; }}static voidh4_i2c_tvout_off(struct work_struct *work){ omap2_disp_get_all_clks(); omap2_disp_set_tvref(TVREF_OFF); omap2_disp_put_all_clks(); omap2_disp_get_all_clks(); omap2_disp_set_tvref(TVREF_OFF); omap2_disp_put_all_clks(); twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER,0x00,TWL4030_VDAC_DEDICATED); twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER,0x00,TWL4030_VDAC_DEV_GRP);}static voidh4_i2c_tvout_on(struct work_struct *work){ omap2_disp_get_all_clks(); omap2_disp_set_tvref(TVREF_ON); omap2_disp_put_all_clks(); omap2_disp_get_all_clks(); omap2_disp_set_tvref(TVREF_ON); omap2_disp_put_all_clks(); twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER, ENABLE_VDAC_DEDICATED,TWL4030_VDAC_DEDICATED); twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECIEVER, ENABLE_VDAC_DEV_GRP,TWL4030_VDAC_DEV_GRP);}static inttv_init(void){ omap2_disp_get_all_clks(); power_tv(TV_ON); omap2_disp_set_tvstandard(NTSC_M); omap2_disp_set_panel_size(OMAP2_OUTPUT_TV, H4_TV_XRES, H4_TV_YRES); omap2_disp_enable_output_dev(OMAP2_OUTPUT_TV); omap2_disp_put_all_clks(); printk(KERN_DEBUG DRIVER "TV %dx%d interlaced\n", H4_TV_XRES, H4_TV_YRES); tv_in_use = 1; return 0;}static inttv_exit(void){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -