From: Wu Zhangjin <wuzhangjin@xxxxxxxxx> This patch adds Video Output Driver, it provides standard interface(/sys/class/video_output) to turn on/off the video output of LCD, CRT. Acked-by: Pavel Machek <pavel@xxxxxx> Signed-off-by: Wu Zhangjin <wuzhangjin@xxxxxxxxx> --- drivers/platform/mips/Kconfig | 1 + drivers/platform/mips/yeeloong_laptop.c | 139 +++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 0 deletions(-) diff --git a/drivers/platform/mips/Kconfig b/drivers/platform/mips/Kconfig index d4ce744..e1285f7 100644 --- a/drivers/platform/mips/Kconfig +++ b/drivers/platform/mips/Kconfig @@ -19,6 +19,7 @@ config LEMOTE_YEELOONG2F depends on LEMOTE_MACH2F select BACKLIGHT_CLASS_DEVICE select HWMON + select VIDEO_OUTPUT_CONTROL help YeeLoong netbook is a mini laptop made by Lemote, which is basically compatible to FuLoong2F mini PC, but it has an extra Embedded diff --git a/drivers/platform/mips/yeeloong_laptop.c b/drivers/platform/mips/yeeloong_laptop.c index 7182580..4f11bc1 100644 --- a/drivers/platform/mips/yeeloong_laptop.c +++ b/drivers/platform/mips/yeeloong_laptop.c @@ -14,6 +14,7 @@ #include <linux/fb.h> #include <linux/hwmon.h> /* for hwmon subdriver */ #include <linux/hwmon-sysfs.h> +#include <linux/video_output.h> /* for video output subdriver */ #include <ec_kb3310b.h> @@ -321,6 +322,136 @@ static void yeeloong_hwmon_exit(void) } } +/* video output subdriver */ + +static int lcd_video_output_get(struct output_device *od) +{ + return ec_read(REG_DISPLAY_LCD); +} + +#define LCD 0 +#define CRT 1 + +static void display_vo_set(int display, int on) +{ + int addr; + unsigned long value; + + addr = (display == LCD) ? 0x31 : 0x21; + + outb(addr, 0x3c4); + value = inb(0x3c5); + + if (display == LCD) + value |= (on ? 0x03 : 0x02); + else { + if (on) + clear_bit(7, &value); + else + set_bit(7, &value); + } + + outb(addr, 0x3c4); + outb(value, 0x3c5); +} + +static int lcd_video_output_set(struct output_device *od) +{ + unsigned long status; + + status = !!od->request_state; + + display_vo_set(LCD, status); + ec_write(REG_BACKLIGHT_CTRL, status); + + return 0; +} + +static struct output_properties lcd_output_properties = { + .set_state = lcd_video_output_set, + .get_status = lcd_video_output_get, +}; + +static int crt_video_output_get(struct output_device *od) +{ + return ec_read(REG_CRT_DETECT); +} + +static int crt_video_output_set(struct output_device *od) +{ + unsigned long status; + + status = !!od->request_state; + + if (ec_read(REG_CRT_DETECT) == BIT_CRT_DETECT_PLUG) + display_vo_set(CRT, status); + + return 0; +} + +static struct output_properties crt_output_properties = { + .set_state = crt_video_output_set, + .get_status = crt_video_output_get, +}; + +static struct output_device *lcd_output_dev, *crt_output_dev; + +static void yeeloong_lcd_vo_set(int status) +{ + lcd_output_dev->request_state = status; + lcd_video_output_set(lcd_output_dev); +} + +static void yeeloong_crt_vo_set(int status) +{ + crt_output_dev->request_state = status; + crt_video_output_set(crt_output_dev); +} + +static int yeeloong_vo_init(void) +{ + int ret; + + /* Register video output device: lcd, crt */ + lcd_output_dev = video_output_register("LCD", NULL, NULL, + &lcd_output_properties); + + if (IS_ERR(lcd_output_dev)) { + ret = PTR_ERR(lcd_output_dev); + lcd_output_dev = NULL; + return ret; + } + /* Ensure LCD is on by default */ + yeeloong_lcd_vo_set(BIT_DISPLAY_LCD_ON); + + crt_output_dev = video_output_register("CRT", NULL, NULL, + &crt_output_properties); + + if (IS_ERR(crt_output_dev)) { + ret = PTR_ERR(crt_output_dev); + crt_output_dev = NULL; + return ret; + } + + /* Turn off CRT by default, and will be enabled when the CRT + * connectting event reported by SCI */ + yeeloong_crt_vo_set(BIT_CRT_DETECT_UNPLUG); + + return 0; +} + +static void yeeloong_vo_exit(void) +{ + if (lcd_output_dev) { + video_output_unregister(lcd_output_dev); + lcd_output_dev = NULL; + } + if (crt_output_dev) { + video_output_unregister(crt_output_dev); + crt_output_dev = NULL; + } +} + static struct platform_device_id platform_device_ids[] = { { .name = "yeeloong_laptop", @@ -365,11 +496,19 @@ static int __init yeeloong_init(void) return ret; } + ret = yeeloong_vo_init(); + if (ret) { + pr_err("Fail to register yeeloong video output driver.\n"); + yeeloong_vo_exit(); + return ret; + } + return 0; } static void __exit yeeloong_exit(void) { + yeeloong_vo_exit(); yeeloong_hwmon_exit(); yeeloong_backlight_exit(); platform_driver_unregister(&platform_driver); -- 1.6.6