androidcomputer: commit scaler code
authorlinjh <linjh@rock-chips.com>
Fri, 11 Oct 2013 06:15:57 +0000 (14:15 +0800)
committerlinjh <linjh@rock-chips.com>
Fri, 11 Oct 2013 06:15:57 +0000 (14:15 +0800)
[reference files]
[modify files]
   arch/arm/configs/rk3188_ac_defconfig
   arch/arm/mach-rk3188/board-rk3188-ac.c
   drivers/misc/Kconfig
   drivers/misc/Makefile
[new files]
   drivers/misc/scaler/Kconfig
   drivers/misc/scaler/Makefile
   drivers/misc/scaler/chips/Kconfig
   drivers/misc/scaler/chips/Makefile
   drivers/misc/scaler/chips/test.c
   drivers/misc/scaler/scaler-core.c
   drivers/misc/scaler/scaler-sysfs.c
   drivers/misc/scaler/scaler-vga.c
   include/linux/scaler-core.h

13 files changed:
arch/arm/configs/rk3188_ac_defconfig
arch/arm/mach-rk3188/board-rk3188-ac.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/scaler/Kconfig [new file with mode: 0755]
drivers/misc/scaler/Makefile [new file with mode: 0644]
drivers/misc/scaler/chips/Kconfig [new file with mode: 0644]
drivers/misc/scaler/chips/Makefile [new file with mode: 0644]
drivers/misc/scaler/chips/test.c [new file with mode: 0644]
drivers/misc/scaler/scaler-core.c [new file with mode: 0644]
drivers/misc/scaler/scaler-sysfs.c [new file with mode: 0644]
drivers/misc/scaler/scaler-vga.c [new file with mode: 0644]
include/linux/scaler-core.h [new file with mode: 0644]

index 9d1815dfc8db0ba9dc17cfa8dc1bc18277a69f07..ea407b8f1ef1842b57ad273f31f2007c4f70f7c5 100644 (file)
@@ -194,6 +194,8 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_MISC_DEVICES=y
 CONFIG_UID_STAT=y
 CONFIG_APANIC=y
+CONFIG_SCALER_DEVICE=y
+CONFIG_SCALER_TEST=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_MULTI_LUN=y
@@ -309,7 +311,7 @@ CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL=y
 CONFIG_LCDC_RK3188=y
 CONFIG_LCDC0_RK3188=y
 CONFIG_LCDC1_RK3188=y
-CONFIG_LCD_DS1006H=y
+CONFIG_LCD_E242868_1024X600=y
 CONFIG_RK_HDMI=y
 CONFIG_HDMI_CAT66121=y
 CONFIG_RK_HDMI_CTL_CODEC=y
@@ -401,7 +403,6 @@ CONFIG_MMC_UNSAFE_RESUME=y
 CONFIG_MMC_EMBEDDED_SDIO=y
 CONFIG_MMC_PARANOID_SD_INIT=y
 CONFIG_SDMMC_RK29=y
-CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD=y
 # CONFIG_SDMMC1_RK29 is not set
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
index 57ef89fee3d03e22ab65c0e603065f8bdd596c90..999ce00d9bbb89a7a3b50110c79cd9171f0ec091 100755 (executable)
@@ -75,6 +75,7 @@
 
 #include "../mach-rk30/board-rk3168-ds1006h-camera.c"
 #include <plat/key.h>
+#include <linux/scaler-core.h>
 
 static struct rk29_keys_button key_button[] = {
        {
@@ -505,8 +506,8 @@ static int rk_fb_io_enable(void)
        return 0;
 }
 
-#if defined(CONFIG_LCDC0_RK3188)
-struct rk29fb_info lcdc0_screen_info = {
+#if defined(CONFIG_LCDC1_RK3188)
+struct rk29fb_info lcdc1_screen_info = {
        .prop           = EXTEND,       //extend display device
        .lcd_info  = NULL,
        .set_screen_info = hdmi_init_lcdc,
@@ -514,8 +515,8 @@ struct rk29fb_info lcdc0_screen_info = {
 };
 #endif
 
-#if defined(CONFIG_LCDC1_RK3188)
-struct rk29fb_info lcdc1_screen_info = {
+#if defined(CONFIG_LCDC0_RK3188)
+struct rk29fb_info lcdc0_screen_info = {
        .prop      = PRMRY,             //primary display device
        .io_init   = rk_fb_io_init,
        .io_disable = rk_fb_io_disable,
@@ -1748,7 +1749,50 @@ static  struct pmu_info  tps65910_ldo_info[] = {
 #include "../mach-rk30/board-pmu-tps65910.c"
 #endif
 
+#if defined(CONFIG_SCALER_TEST) 
+//the fisrt port is default 
+struct scaler_output_port tst_oports[] ={
+       {
+               .led_gpio = INVALID_GPIO,
+               .type = SCALER_OUT_VGA,
+       },
+};
+
+//the fisrt port is default 
+struct scaler_input_port tst_iports[] = {
+       {
+               //RK
+               .led_gpio = RK30_PIN0_PD4,
+               .type = SCALER_IN_VGA,
+       },
+       {
+               //pc
+               .led_gpio = RK30_PIN0_PD5,
+               .type = SCALER_IN_VGA,
+       },
+};
+
+struct scaler_platform_data test_data = {
+       .func_type = SCALER_FUNC_SWITCH,
+
+       .iports = tst_iports,
+       .iport_size = ARRAY_SIZE(tst_iports),
+       .oports = tst_oports,
+       .oport_size = ARRAY_SIZE(tst_oports),
+
+       .power_gpio = RK30_PIN2_PD7,
+};
+#endif
+
 static struct i2c_board_info __initdata i2c1_info[] = {
+#if defined(CONFIG_SCALER_TEST) 
+       {
+               .type           = "aswitch",
+               .addr           = 0x57,
+               .flags          = 0,
+               .platform_data = &test_data,
+       },
+#endif
 #if defined (CONFIG_REGULATOR_ACT8846)
        {
                .type                   = "act8846",
@@ -1871,6 +1915,13 @@ void  rk30_pwm_resume_voltage_set(void)
 
 #ifdef CONFIG_I2C2_RK30
 static struct i2c_board_info __initdata i2c2_info[] = {
+#if defined(CONFIG_SCALER_DEVICE) 
+       {
+               .type           = "vga_i2c",
+               .addr           = 0x50,
+               .flags          = 0,
+       },
+#endif
 #if defined (CONFIG_CT36X_TS)
        {
                .type          = CT36X_NAME,
index 3034dceb187de6dff10d48df758d1f2f9eac35ad..4e90a6d47c23a74374f1ad1b00bf5a95cc6e35e8 100755 (executable)
@@ -576,4 +576,5 @@ source "drivers/misc/carma/Kconfig"
 source "drivers/misc/bp/Kconfig"
 source "drivers/misc/rk2928_callpad_misc/Kconfig"
 source "drivers/misc/3g_module/Kconfig"
+source "drivers/misc/scaler/Kconfig"
 endif # MISC_DEVICES
index 4614251b5d6fb4d929cf5a29b6a64dd56d89aa93..ff2e22c7a33d40c99db9ca7e6ed4114164d97a2a 100644 (file)
@@ -63,3 +63,4 @@ obj-$(CONFIG_RK29_SC8800)     +=      sc8800.o
 obj-y += rk2928_callpad_misc/
 obj-$(CONFIG_MODEM_SOUND) += modem_sound.o
 obj-$(CONFIG_TCC_BT_DEV)       += tcc_bt_dev.o
+obj-$(CONFIG_SCALER_DEVICE)            += scaler/
diff --git a/drivers/misc/scaler/Kconfig b/drivers/misc/scaler/Kconfig
new file mode 100755 (executable)
index 0000000..4cb0b09
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# all auto modem control drivers configuration\r
+#
+
+menuconfig SCALER_DEVICE
+       bool "Scaler Device Support"
+       default n       
+
+if SCALER_DEVICE
+source "drivers/misc/scaler/chips/Kconfig"
+endif
diff --git a/drivers/misc/scaler/Makefile b/drivers/misc/scaler/Makefile
new file mode 100644 (file)
index 0000000..9f813fd
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the display core.
+#
+
+obj-$(CONFIG_SCALER_DEVICE) += chips/ 
+obj-$(CONFIG_SCALER_DEVICE) += scaler-core.o
+obj-$(CONFIG_SCALER_DEVICE) += scaler-sysfs.o
+obj-$(CONFIG_SCALER_DEVICE) += scaler-vga.o
diff --git a/drivers/misc/scaler/chips/Kconfig b/drivers/misc/scaler/chips/Kconfig
new file mode 100644 (file)
index 0000000..c6a8282
--- /dev/null
@@ -0,0 +1,11 @@
+#
+#config tv5735 support inport type and output type
+#
+
+config SCALER_TV5735
+       bool "Support tv5735 chip"
+       default n       
+
+config SCALER_TEST
+       bool "test chip"
+       default n       
diff --git a/drivers/misc/scaler/chips/Makefile b/drivers/misc/scaler/chips/Makefile
new file mode 100644 (file)
index 0000000..3667cad
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SCALER_TV5735) += tv5735.o
+obj-$(CONFIG_SCALER_TEST) += test.o
diff --git a/drivers/misc/scaler/chips/test.c b/drivers/misc/scaler/chips/test.c
new file mode 100644 (file)
index 0000000..19069b6
--- /dev/null
@@ -0,0 +1,168 @@
+/*\r
+       Copyright (c) 2010 by Rockchip.\r
+*/\r
+#include <linux/module.h>\r
+#include <linux/input.h>\r
+#include <linux/i2c.h>\r
+#include <linux/delay.h>\r
+#include <linux/kthread.h>\r
+#include <linux/sched.h>\r
+#include <linux/slab.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/irq.h>\r
+#include <linux/cdev.h>\r
+#include <asm/uaccess.h>\r
+#include <linux/version.h>\r
+#include <linux/gpio.h>\r
+#include <linux/io.h>\r
+#include <linux/regulator/consumer.h>\r
+#include <mach/iomux.h>\r
+#include <mach/gpio.h>\r
+#ifdef CONFIG_HAS_EARLYSUSPEND\r
+#include <linux/earlysuspend.h>\r
+#include <linux/wakelock.h>\r
+#endif\r
+#include <linux/scaler-core.h>\r
+\r
+struct scaler_chip_dev *chip = NULL;\r
+extern char *scaler_input_name[];\r
+\r
+\r
+//enbale chip to process image\r
+static void set_cur_inport(void) \r
+{\r
+       struct scaler_input_port *iport = NULL;\r
+       \r
+       list_for_each_entry(iport, &chip->iports, next) {\r
+               if (iport->id == chip->cur_inport_id) {\r
+                       gpio_set_value(iport->led_gpio, GPIO_HIGH);\r
+               }else {\r
+                       gpio_set_value(iport->led_gpio, GPIO_LOW);\r
+               }\r
+       }\r
+\r
+       //pc\r
+       if (chip->cur_inport_id == 2)\r
+               gpio_set_value(RK30_PIN0_PB4, GPIO_LOW);\r
+       else\r
+       //rk\r
+               gpio_set_value(RK30_PIN0_PB4, GPIO_HIGH);\r
+}\r
+\r
+static int parse_cmd(unsigned int cmd, unsigned long arg)\r
+{\r
+       printk("test: parse scaler cmd %u\n",cmd);\r
+\r
+       switch (cmd) {\r
+               case SCALER_IOCTL_SET_CUR_INPUT:\r
+                       set_cur_inport();\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int test_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)\r
+{\r
+       struct scaler_platform_data  *pdata = client->dev.platform_data;\r
+\r
+       if (!pdata) {\r
+               printk("%s: client private data not define\n", __func__);\r
+               return -1;\r
+       }\r
+\r
+       chip = alloc_scaler_chip();\r
+       if (!chip) {\r
+               printk("%s: alloc scaler chip memory failed.\n", __func__);\r
+               return -1;\r
+       }\r
+       chip->client = client;\r
+       memcpy((void *)chip->name, (void *)client->name, (strlen(client->name) + 1));\r
+       //implement parse cmd function\r
+       init_scaler_chip(chip, pdata);\r
+       chip->parse_cmd = parse_cmd;\r
+\r
+       //vga 5v en\r
+       if (!gpio_request(RK30_PIN3_PD7, NULL))\r
+               gpio_direction_output(RK30_PIN3_PD7, GPIO_HIGH); \r
+       else\r
+               printk("%s: request vga5ven power gpio failed\n", __func__);\r
+       msleep(20);\r
+\r
+       //power\r
+       if (!gpio_request(RK30_PIN2_PD7, NULL))\r
+               gpio_direction_output(RK30_PIN2_PD7, GPIO_HIGH); \r
+       else\r
+               printk("%s: request vga power gpio failed\n", __func__);\r
+       msleep(20);\r
+\r
+       //vga sel\r
+       if (!gpio_request(RK30_PIN0_PB4, NULL))\r
+               gpio_direction_output(RK30_PIN0_PB4, GPIO_HIGH); //rk output\r
+       else\r
+               printk("%s: request vga switch gpio failed\n", __func__);\r
+       msleep(20);\r
+\r
+       //\r
+       if (!gpio_request(RK30_PIN1_PD6, NULL))\r
+               gpio_direction_output(RK30_PIN1_PD6, GPIO_HIGH); \r
+       else\r
+               printk("%s: request XNN223_PWN gpio failed\n", __func__);\r
+       msleep(20);\r
+\r
+       //register\r
+       register_scaler_chip(chip);\r
+\r
+       return 0;\r
+}\r
+\r
+static int test_i2c_remove(struct i2c_client *client)\r
+{\r
+\r
+       printk("%s: \n", __func__);\r
+       unregister_scaler_chip(chip);\r
+       free_scaler_chip(chip);\r
+       chip = NULL;\r
+       return 0;\r
+}\r
+\r
+\r
+static const struct i2c_device_id test_i2c_id[] ={\r
+       {"aswitch", 0}, \r
+       {}\r
+};\r
+MODULE_DEVICE_TABLE(i2c, test_i2c_id);\r
+\r
+static struct i2c_driver test_i2c_driver = {\r
+       .driver = {\r
+               .name = "aswitch"\r
+       },\r
+       .probe = test_i2c_probe,\r
+       .remove = test_i2c_remove,\r
+       .id_table = test_i2c_id,\r
+};\r
+\r
+static int __init test_init(void)\r
+{\r
+       int ret = 0;\r
+       printk("%s: \n", __func__);\r
+\r
+       ret = i2c_add_driver(&test_i2c_driver);\r
+       if(ret < 0){\r
+               printk("%s, register i2c device, error\n", __func__);\r
+               return ret;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static void __exit test_exit(void)\r
+{\r
+       printk("%s: \n", __func__);\r
+}\r
+\r
+module_init(test_init);\r
+module_exit(test_exit);\r
+\r
diff --git a/drivers/misc/scaler/scaler-core.c b/drivers/misc/scaler/scaler-core.c
new file mode 100644 (file)
index 0000000..57f5091
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ *
+ * Copyright (C) 2012 Rockchip
+ *
+ *---------------------------------
+ * version 1.0 2012-9-13
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/version.h>
+#include <linux/pm_runtime.h>
+#include <asm/uaccess.h>
+#include <linux/scaler-core.h>
+
+#define SCALER_CORE_VERSION "v1.0.0"
+#define SCALER_DEV_NAME "scaler-ctrl"
+
+static DEFINE_MUTEX(mutex_chips);
+static DEFINE_MUTEX(mutex_ports);
+
+static struct scaler_device *sdev = NULL;
+static unsigned short chip_ids = 0;       //<id only grow>只增不减
+static unsigned int port_ids = 0;
+extern int scaler_sysfs_create(struct scaler_device *sdev);
+extern int scaler_sysfs_remove(struct scaler_device *sdev);
+
+static const char const *scaler_output_name[] = {
+       "output type",
+       "LVDS",
+       "VGA",
+       "RGB",
+       "HDMI",
+       "DP",
+};
+
+const char const *scaler_input_name[] = {
+       "input tpye",
+       "VGA",
+       "RGB",
+       "HDMI",
+       "DP",
+       "DVI",
+       "YPBPR",
+       "YCBCR",
+       "MYDP",
+       "IDP",
+};
+
+static const char const *scaler_func_name[] ={
+       "This Scaler Function Type Is:",
+       "convertor",
+       "switch",
+       "full function",
+};
+
+static void scaler_led_on(int gpio)
+{
+       gpio_set_value(gpio, GPIO_HIGH);        
+}
+static void scaler_led_off(int gpio)
+{
+       gpio_set_value(gpio, GPIO_LOW); 
+}
+
+static void default_start(void)
+{
+}
+
+static void default_stop(void)
+{
+}
+
+static int default_read(unsigned short reg, int bytes, void *desc)
+{
+       return 0;
+}
+
+static int default_write(unsigned short reg, int bytes, void *desc)
+{
+       return 0;
+}
+
+static int default_parse_cmd(unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+//alloc chip dev memory and init default value
+struct scaler_chip_dev *alloc_scaler_chip(void)
+{
+       struct scaler_chip_dev *p = kzalloc(sizeof(struct scaler_chip_dev), GFP_KERNEL);
+       if (p) {
+               strcpy(p->name, "unknown");
+               //init default operation function
+               p->start = default_start;
+               p->stop = default_stop;
+               p->read = default_read;
+               p->write = default_write;
+               p->parse_cmd = default_parse_cmd;
+               //init list head
+               INIT_LIST_HEAD(&p->next);
+               INIT_LIST_HEAD(&p->oports);
+               INIT_LIST_HEAD(&p->iports);
+       }
+       return p;
+}
+
+int init_scaler_chip(struct scaler_chip_dev *chip, struct scaler_platform_data *pdata)
+{
+       int i;
+       struct scaler_output_port *oport = NULL;
+       struct scaler_input_port *iport = NULL;
+
+       if (!chip || !pdata) {
+               printk("%s: chip or pdata is null.\n", __func__);
+               return -1;
+       }
+       
+       //set scaler function type
+       if (pdata->func_type > SCALER_FUNC_INVALID && 
+                       pdata->func_type < SCALER_FUNC_NUMS) {
+               chip->func_type = pdata->func_type;
+       }else {
+               printk("%s: not defined scaer function type\n", __func__);
+               chip->func_type = SCALER_FUNC_FULL;
+       }
+       printk("%s: %s %s\n", chip->name, scaler_func_name[0], scaler_func_name[chip->func_type]);
+
+       //set scaler support input type
+       for (i = 0; i < pdata->iport_size; i++) {
+               iport = kzalloc(sizeof(struct scaler_input_port), GFP_KERNEL);
+               if (!iport) {
+                   printk("%s: kzalloc input port memeory failed.\n", __func__);
+                   return -1;
+               }else {
+                       iport->max_hres = 1920;
+                       iport->max_vres = 1080;
+                       iport->freq = 60;
+                       //input port id
+                       mutex_lock(&mutex_ports);
+                       iport->id = ++port_ids;
+                       mutex_unlock(&mutex_ports);
+                       //input port type
+                       iport->type = pdata->iports[i].type;
+                       //the first input port is default 
+                       if (!chip->cur_inport_id) {
+                               chip->cur_in_type = iport->type;
+                               chip->cur_inport_id = iport->id;
+                               printk("%s:  default %s %s\n", chip->name, scaler_input_name[0], scaler_input_name[iport->type]);
+                       }
+
+                       //init and request input gpio of indicator lamp 
+                       if (pdata->iports[i].led_gpio > 0) {
+                               iport->led_gpio = pdata->iports[i].led_gpio;
+                               if (!gpio_request(iport->led_gpio, NULL)) {
+                                       gpio_direction_output(iport->led_gpio, GPIO_HIGH);      
+                               }else {
+                                       printk("%s:  request %s<id,%d> gpio failed\n", chip->name, 
+                                                          scaler_input_name[pdata->iports[i].type], iport->id);
+                               }
+                       }
+
+                       //add input of chip
+                       list_add_tail(&iport->next, &chip->iports);
+                       printk("%s:  support %s %s<id,%d> led_gpio %d\n", chip->name, scaler_input_name[0], 
+                                            scaler_input_name[pdata->iports[i].type], iport->id, iport->led_gpio);
+               }//if (!iport)
+       }//for()
+
+       //set scaler output type
+       for (i = 0; i < pdata->oport_size; i++) {
+               oport = kzalloc(sizeof(struct scaler_output_port), GFP_KERNEL);
+               if (!oport) {
+                   printk("%s: kzalloc output port memeory failed.\n", __func__);
+                   return -1;
+               }else {
+                       oport->max_hres = 1920;
+                       oport->max_vres = 1080;
+                       oport->freq = 60;
+                       //output port id
+                       mutex_lock(&mutex_ports);
+                       oport->id = ++port_ids;
+                       mutex_unlock(&mutex_ports);
+                       //output port type
+                       oport->type = pdata->oports[i].type;
+                       //the first output port is default 
+                       if (!chip->cur_outport_id) {
+                               chip->cur_out_type = oport->type;
+                               chip->cur_outport_id = oport->id;
+                               printk("%s:  default %s %s\n", chip->name, scaler_output_name[0], scaler_output_name[oport->type]);
+                       }
+
+                       //init and request output gpio of indicator lamp 
+                       if (pdata->oports[i].led_gpio > 0) {
+                               oport->led_gpio = pdata->oports[i].led_gpio;
+                               if (!gpio_request(oport->led_gpio, NULL)) {
+                                       gpio_direction_output(oport->led_gpio, GPIO_HIGH);      
+                               }else {
+                                       printk("%s:  request %s<id,%d> gpio failed\n", chip->name, scaler_output_name[pdata->oports[i].type], oport->id);
+                               }
+                       }
+
+                       list_add_tail(&oport->next, &chip->oports);
+                       printk("%s:  support %s %s<id,%d> led_gpio %d\n", chip->name, scaler_output_name[0], 
+                                         scaler_output_name[pdata->oports[i].type], oport->id, oport->led_gpio);
+               }// if (!oport)
+       }//for()
+
+       return 0;
+}
+
+//free scaler chip memory
+void free_scaler_chip(struct scaler_chip_dev *chip)
+{
+       struct scaler_output_port *out = NULL;
+       struct scaler_input_port *in = NULL;
+       if (chip) {
+
+               list_for_each_entry(out, &chip->oports, next) {
+                       kfree(out);
+               }
+
+               list_for_each_entry(in, &chip->iports, next) {
+                       if (in->led_gpio > 0)
+                               gpio_free(in->led_gpio);
+                       kfree(in);
+               }
+
+               kfree(chip);
+       }
+}
+
+//register chip to scaler core
+int register_scaler_chip(struct scaler_chip_dev *chip)
+{
+       int res = -1;
+       struct scaler_input_port *in;
+       struct scaler_output_port *out;
+       
+       if (chip && sdev) {
+               res = 0;
+
+               //start chip to process
+               chip->start();
+
+               //power on input indicator lamp
+               list_for_each_entry(in, &chip->iports, next){
+                       if (in->id == chip->cur_inport_id)
+                               scaler_led_on(in->led_gpio);
+                       else
+                               scaler_led_off(in->led_gpio);
+               }
+
+               //power on output indicator lamp
+               list_for_each_entry(out, &chip->oports, next){
+                       if (out->id == chip->cur_outport_id)
+                               scaler_led_on(out->led_gpio);
+                       else
+                               scaler_led_off(out->led_gpio);
+               }
+               //add chip to scaler core
+               mutex_lock(&mutex_chips);
+               chip->id = ++chip_ids;  //chip id only grow
+               list_add_tail(&chip->next, &sdev->chips);
+               mutex_unlock(&mutex_chips);
+               printk("%s: register scaler chip %s success.\n", __func__, chip->name);
+       }
+
+       return res;
+}
+
+//unregister chip to scaler core
+int unregister_scaler_chip(struct scaler_chip_dev *chip)
+{
+       int res = -1;
+       struct scaler_input_port *in;
+       struct scaler_output_port *out;
+       
+       if (chip && sdev) {
+               res = 0;
+
+               chip->stop();
+
+               //power off input indicator lamp
+               list_for_each_entry(in, &chip->iports, next){
+                       if (in->id == chip->cur_inport_id)
+                               scaler_led_off(in->led_gpio);
+               }
+
+               //power off output indicator lamp
+               list_for_each_entry(out, &chip->oports, next){
+                       if (out->id == chip->cur_outport_id)
+                               scaler_led_off(out->led_gpio);
+               }
+
+               //del chip from scaler core
+               mutex_lock(&mutex_chips);
+               list_del(&chip->next);
+               mutex_unlock(&mutex_chips);
+               printk("%s: unregister scaler chip %s success.\n", __func__, chip->name);
+       }
+
+       return res;
+}
+
+/***        cdev operate ***/
+static int scaler_file_open(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+static int scaler_file_close(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+static ssize_t scaler_file_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
+{
+       return 0;
+}
+
+static ssize_t scaler_file_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
+{
+       return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+static long scaler_file_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+#else
+static int  scaler_file_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+#endif
+{
+       int iport_id;
+       struct scaler_chip_dev *chip = NULL;
+       struct scaler_input_port *iport = NULL;
+
+
+       switch(cmd) {
+               case 0:
+                       printk("get cur input cmd %#x\n", SCALER_IOCTL_GET_CUR_INPUT);
+                       printk("set cur input cmd %#x\n", SCALER_IOCTL_SET_CUR_INPUT);
+                       break;
+               case SCALER_IOCTL_SET_CUR_INPUT:
+                       //choose input channel;
+                       copy_from_user(&iport_id, arg, sizeof(int));
+
+                       list_for_each_entry(chip, &sdev->chips, next) {
+                               if (chip->cur_inport_id != iport_id) {
+                                       list_for_each_entry(iport, &chip->iports, next) {//if iport belong to this chip
+                                               if (iport->id == iport_id) {
+                                                       chip->cur_inport_id = iport_id;
+                                                       chip->parse_cmd(cmd, arg);
+                                                       break;
+                                               }
+                                       }//list iports
+                               }
+                       }//list chips
+
+                       break;
+               case SCALER_IOCTL_GET_CUR_INPUT:
+                       list_for_each_entry(chip, &sdev->chips, next) {
+                               iport_id = chip->cur_inport_id;
+                       }//list chips
+                       copy_to_user(arg, &iport_id, sizeof(int));
+                       printk("current input port id %d\n", iport_id);
+                       break;
+               default:
+                       //default_parse_cmd(cmd, arg);
+                       break;
+       }
+
+
+       return 0;
+}
+
+struct file_operations scaler_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
+               .unlocked_ioctl =scaler_file_ioctl,
+#else
+               .ioctl =scaler_file_ioctl,          //定义所有对scaler操作的cmd
+#endif
+               .read =scaler_file_read,
+               .write = scaler_file_write,
+               .open = scaler_file_open,
+               .release = scaler_file_close,
+};
+
+//注册一个scaler的字符设备 供别的设备操作scaler
+static int scaler_register_chrdev(void)
+{
+    int ret = 0;
+
+    ret = alloc_chrdev_region(&sdev->devno, 0, 1, SCALER_DEV_NAME);
+    if(ret != 0){
+        printk("%s, can't allocate chrdev devno.\n", __func__);
+        return ret;
+    }else {
+        printk("%s: Scaler chrdev devno(%d,%d).\n", __func__, MAJOR(sdev->devno), MINOR(sdev->devno));
+    }   
+                                   
+    // initialize character device driver
+       sdev->cdev = cdev_alloc();
+       if (!sdev->cdev) {
+               printk("%s: cdev alloc failed.\n", __func__);
+               goto err1;
+       }
+
+    cdev_init(sdev->cdev, &scaler_fops);
+    sdev->cdev->owner = THIS_MODULE;
+    ret = cdev_add(sdev->cdev, sdev->devno, 1); 
+    if(ret < 0){ 
+        printk("%s, add character device error, ret %d\n", __func__, ret);
+        goto err2;
+    }   
+
+    sdev->class = class_create(THIS_MODULE, "scaler");
+    if(!sdev->class){
+        printk("%s, create class failed\n", __func__);
+        goto err3;
+    }   
+
+    sdev->dev = device_create(sdev->class, NULL, sdev->devno, sdev, SCALER_DEV_NAME);
+       if (!sdev->dev) {
+               printk("%s: create device failed\n", __func__);
+               goto err4;
+       }
+       
+
+    return 0;
+
+err4:
+       class_destroy(sdev->class);
+err3:
+       cdev_del(sdev->cdev);
+err2:
+       kfree(sdev->cdev);
+err1:
+       unregister_chrdev_region(sdev->devno, 1);
+
+       return -1;
+}
+
+static void scaler_unregister_chrdev(void)
+{
+       cdev_del(sdev->cdev);
+       unregister_chrdev_region(sdev->devno, 1);
+       kfree(sdev->cdev);
+       device_destroy(sdev->class, sdev->devno);
+       class_destroy(sdev->class);
+}
+
+static int __init rk_scaler_init(void)
+{
+       printk("%s: SCALER CORE VERSION: %s\n", __func__, SCALER_CORE_VERSION);
+
+       sdev = kzalloc(sizeof(struct scaler_device), GFP_KERNEL);
+       if (!sdev) {
+               printk("%s: malloc scaler devices failed.\n", __func__);
+               return -1;
+       }else {
+               INIT_LIST_HEAD(&sdev->chips);
+       }
+
+       if (scaler_register_chrdev() < 0) {
+               printk("%s:  scaler register chrdev failed.\n", __func__);
+               goto err1;
+       }
+
+       if (scaler_sysfs_create(sdev) < 0) {
+               printk("%s: scaler sysfs create faild.\n", __func__);
+               goto err2;
+       }
+
+       return 0;
+err2:
+       scaler_unregister_chrdev();
+err1:
+       kfree(sdev);
+
+       return -1;
+}
+
+static void  __exit rk_scaler_exit(void)
+{
+       printk("%s\n", __func__);
+       scaler_sysfs_remove(sdev);
+       scaler_unregister_chrdev();
+       kfree(sdev);
+}
+
+subsys_initcall(rk_scaler_init);
+module_exit(rk_scaler_exit);
+
+MODULE_AUTHOR("linjh <linjh@rock-chips.com>");
+MODULE_DESCRIPTION("RK Scaler Device Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/scaler/scaler-sysfs.c b/drivers/misc/scaler/scaler-sysfs.c
new file mode 100644 (file)
index 0000000..a84701f
--- /dev/null
@@ -0,0 +1,105 @@
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/scaler-core.h>
+#include <linux/slab.h>
+extern const char const *scaler_input_name[];
+static ssize_t scaler_iport_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       int iports = 0;
+       struct scaler_chip_dev *chip = NULL;
+       struct scaler_input_port *in = NULL;
+       struct scaler_device *sdev = dev_get_drvdata(dev);
+
+       list_for_each_entry(chip, &sdev->chips, next) {
+
+               list_for_each_entry(in, &chip->iports, next) {
+                       iports++;
+                       printk("id = %d type = %s gpio = %d\n", in->id, 
+                                           scaler_input_name[in->type], in->led_gpio);
+               }
+       }
+
+       return sprintf(buf, "%d\n", iports);
+}
+
+static ssize_t scaler_iport_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return 0;
+}
+static DEVICE_ATTR(iports, 0664, scaler_iport_show, NULL);
+
+static ssize_t scaler_cur_iport_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct scaler_chip_dev *chip = NULL;
+       struct scaler_input_port *in = NULL;
+       struct scaler_device *sdev = dev_get_drvdata(dev);
+
+       list_for_each_entry(chip, &sdev->chips, next) {
+
+               printk("id = %d type = %s\n", chip->cur_inport_id, 
+                               scaler_input_name[chip->cur_in_type]);
+       }
+       return 0;
+}
+static DEVICE_ATTR(cur_iport, 0664, scaler_cur_iport_show, NULL);
+
+static ssize_t scaler_oport_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       printk("%s: scaler sysfs test.\n", __func__);
+       return 0;
+}
+
+static ssize_t scaler_oport_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       return 0;
+}
+
+static DEVICE_ATTR(oports, 0664, scaler_oport_show, NULL);
+
+
+static struct attribute *scaler_attributes[] = {
+       &dev_attr_iports.attr,
+       &dev_attr_cur_iport.attr,
+       &dev_attr_oports.attr,
+       NULL
+};
+
+static mode_t scaler_attr_is_visible(struct kobject *kobj,
+                                    struct attribute *attr, int n)
+{
+       mode_t mode = attr->mode;
+
+       return mode;
+}
+
+static const struct attribute_group scaler_attr_group = {
+       .is_visible     = scaler_attr_is_visible,
+       .attrs          = scaler_attributes,
+};
+
+
+int scaler_sysfs_create(struct scaler_device *sdev)
+{
+       int err;
+
+       //sdev->kobj = kobject_create_and_add("attr", &sdev->dev->kobj);
+       //err = sysfs_create_group(sdev->kobj, &scaler_attr_group);
+       err = sysfs_create_group(&sdev->dev->kobj, &scaler_attr_group);
+
+       return err;
+}
+
+int scaler_sysfs_remove(struct scaler_device *sdev)
+{
+       sysfs_remove_group(&sdev->dev->kobj, &scaler_attr_group);
+       //dev_set_drvdata(sdev->dev, NULL);
+       //kobject_put(sdev->kobj);
+       return 0;
+}
diff --git a/drivers/misc/scaler/scaler-vga.c b/drivers/misc/scaler/scaler-vga.c
new file mode 100644 (file)
index 0000000..61c147c
--- /dev/null
@@ -0,0 +1,480 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/display-sys.h>
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+#include <mach/board.h>
+
+#include <linux/rk_screen.h>
+#include <linux/rk_fb.h>
+#include "../../video/edid.h"
+
+#define DDC_I2C_BUS                    1
+#define DDC_ADDR                       0x50
+#define DDC_I2C_RATE           100*1000
+
+static const struct fb_videomode rk29_mode[] = {
+       //name                          refresh         xres    yres    pixclock                        h_bp    h_fp    v_bp    v_fp    h_pw    v_pw    polariry        PorI    flag(used for vic)
+#if defined(CONFIG_CLK_RK30_BOX)
+{      "1024x768p@60Hz",       60,                     1024,   768,    KHZ2PICOS(65000),       160,    24,             29,             3,              136,    6,              0,                      0,              0       },
+{      "1280x720p@60Hz",       60,                     1280,   720,    KHZ2PICOS(74250),       220,    110,    20,             5,              40,             5,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              0       },      
+{      "1280x1024p@60Hz",      60,                     1280,   1024,   KHZ2PICOS(108000),      248,    48,             38,             1,              112,    3,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              0       },
+{      "1366x768p@60Hz",       60,                     1366,   768,    KHZ2PICOS(85500),       213,    70,             24,             3,              143,    3,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              0       },
+{      "1440x900p@60Hz",       60,                     1440,   900,    KHZ2PICOS(106500),      232,    80,             25,             3,              152,    6,              FB_SYNC_VERT_HIGH_ACT,                  0,              0       },
+{      "1680x1050p@60Hz",      60,                     1680,   1050,   KHZ2PICOS(146250),      280,    104,    30,             3,              176,    6,              FB_SYNC_VERT_HIGH_ACT,                  0,              0       },
+{      "1920x1080p@60Hz",      60,                     1920,   1080,   KHZ2PICOS(148500),      148,    88,             36,             4,              44,             5,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              0       },
+#else
+//{    "640x480p@60Hz",        60,                     640,    480,    KHZ2PICOS(25175),       48,             16,             33,             10,             96,             2,              0,                      0,              1       },
+{      "720x480p@60Hz",        60,                     720,    480,    KHZ2PICOS(27000),       60,             16,             30,             9,              62,             6,              0,                      0,              2       },
+{      "720x576p@50Hz",        50,                     720,    576,    KHZ2PICOS(27000),       68,             12,             39,             5,              64,             5,              0,                      0,              17      },
+{      "1280x720p@50Hz",       50,                     1280,   720,    KHZ2PICOS(74250),       220,    440,    20,             5,              40,             5,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              19      },
+{      "1280x720p@60Hz",       60,                     1280,   720,    KHZ2PICOS(74250),       220,    110,    20,             5,              40,             5,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              4       },      
+{      "1920x1080p@50Hz",      50,                     1920,   1080,   KHZ2PICOS(148500),      148,    528,    36,             4,              44,             5,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              31      },
+{      "1920x1080p@60Hz",      60,                     1920,   1080,   KHZ2PICOS(148500),      148,    88,             36,             4,              44,             5,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              16      },
+#endif
+};
+
+struct rk29_monspecs {
+       struct i2c_client                       *i2c_client;
+       struct rk_display_device        *ddev;
+       int     io_enable_pin;
+       int video_source;
+       int property;
+       struct fb_monspecs                      monspecs;
+       struct list_head                        modelist;
+       struct fb_videomode                     *mode;
+       int enable;
+};
+
+static struct rk29_monspecs rk29_monspec;
+
+#ifdef CONFIG_ARCH_RK29
+extern int FB_Switch_Screen( struct rk29fb_screen *screen, u32 enable );
+#else
+static int FB_Switch_Screen( struct rk29fb_screen *screen, u32 enable )
+{
+       return rk_fb_switch_screen(screen, enable , rk29_monspec.video_source);
+}
+#endif
+
+static unsigned char *rk29fb_ddc_read(struct i2c_client *client)
+{
+       unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+       int rc;
+       
+       if (!buf) {
+               dev_warn(&client->dev, "unable to allocate memory for EDID "
+                        "block.\n");
+               return NULL;
+       }
+       // Check ddc i2c communication is available or not.
+       memset(buf, 0, EDID_LENGTH);
+       rc = i2c_master_reg8_recv(client, 0, buf, 6, DDC_I2C_RATE);
+       if(rc == 6)
+       {
+               // Read EDID.
+               memset(buf, 0, EDID_LENGTH);
+               rc = i2c_master_reg8_recv(client, 0, buf, EDID_LENGTH, DDC_I2C_RATE);
+               if(rc == EDID_LENGTH)
+                       return buf;
+       }
+
+       dev_warn(&client->dev, "unable to read EDID block.\n");
+       kfree(buf);
+       return NULL;
+}
+
+static struct fb_videomode *rk29fb_set_default_modelist(void)
+{
+       int i;
+       struct fb_videomode *mode = NULL;
+       struct list_head        *modelist = &rk29_monspec.modelist;
+       
+       fb_destroy_modelist(modelist);
+       for(i = 0; i < ARRAY_SIZE(rk29_mode); i++)
+       {
+               mode = (struct fb_videomode *)&rk29_mode[i];    
+               //display_add_videomode(mode, modelist);
+               fb_add_videomode(mode, modelist);
+       }
+       rk29_monspec.mode = (struct fb_videomode *)&rk29_mode[3];
+       return rk29_monspec.mode;
+}
+
+/*
+ * Find monitor prefered video mode. If not find, 
+ * set first mode as default mode. 
+ */
+static struct fb_videomode *rk29fb_find_default_mode(void)
+{
+       struct fb_monspecs *specs = &rk29_monspec.monspecs;
+       struct fb_videomode *modedb = NULL;
+       int i, pixclock;
+       
+       if(specs->modedb_len) {
+#if 1
+               /* Get max resolution timing */
+               modedb = &specs->modedb[0];
+               for (i = 0; i < specs->modedb_len; i++) {
+                       if(specs->modedb[i].xres > modedb->xres)
+                               modedb = &specs->modedb[i];
+                       else if( (specs->modedb[i].xres == modedb->xres) && (specs->modedb[i].yres > modedb->yres) )
+                               modedb = &specs->modedb[i];
+               }
+               // For some monitor, the max pixclock read from EDID is smaller
+               // than the clock of max resolution mode supported. We fix it.
+               pixclock = PICOS2KHZ(modedb->pixclock);
+               pixclock /= 250;
+               pixclock *= 250;
+               pixclock *= 1000;
+               if(pixclock == 148250000)
+                       pixclock = 148500000;
+               if(pixclock > specs->dclkmax)
+                       specs->dclkmax = pixclock;
+#else  
+               /* get preferred timing */
+               if (specs->misc & FB_MISC_1ST_DETAIL) {
+       
+                       for (i = 0; i < specs->modedb_len; i++) {
+                               if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
+                                       modedb = &specs->modedb[i];
+                                       break;
+                               }
+                       }
+               } else {
+                       /* otherwise, get first mode in database */
+                       modedb = &specs->modedb[0];
+               }
+#endif
+       }
+       else
+               modedb = rk29fb_set_default_modelist();
+       return modedb;
+}
+
+/*
+ * Check mode 1920x1080p@60Hz is in modedb or not.  
+ * If exist, set it as output moe.
+ * If not exist, try mode 1280x720p@60Hz.
+ * If both mode not exist, try 720x480p@60Hz.
+ */
+static int rk29fb_check_mode(void)
+{
+       struct fb_monspecs      *specs = &rk29_monspec.monspecs;
+       struct list_head        *modelist = &rk29_monspec.modelist;
+       struct fb_videomode *modedb = NULL, *mode = NULL;
+       unsigned int pixclock;
+       
+       fb_destroy_modelist(modelist);
+       modedb = rk29fb_find_default_mode();
+       
+       if(modedb)
+       {
+               int i;
+               
+               for(i = 0; i < ARRAY_SIZE(rk29_mode); i++)
+               {
+                       pixclock = PICOS2KHZ(rk29_mode[i].pixclock);
+                       pixclock /= 250;
+                       pixclock *= 250;
+                       pixclock *= 1000;
+                       if( (pixclock <= specs->dclkmax) &&     
+                               (rk29_mode[i].xres <= modedb->xres) &&
+                               (rk29_mode[i].yres <= modedb->yres) &&
+                               (rk29_mode[i].refresh <= specs->vfmax) &&
+                               (rk29_mode[i].refresh >= specs->vfmin)
+                         )
+                       {
+                               mode = (struct fb_videomode *)&rk29_mode[i];    
+                               //display_add_videomode(mode, modelist);
+                               fb_add_videomode(mode, modelist);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Probe monitor information using E-EDID.
+ */
+static int rk29fb_probe_screens(struct i2c_client *client)
+{
+       struct fb_monspecs      *spec = &rk29_monspec.monspecs;
+       struct list_head        *modelist = &rk29_monspec.modelist;
+       u8 *edid;
+       struct fb_videomode *defaultmode, *mode;
+       
+       if (client)
+               edid = rk29fb_ddc_read(client);
+       else
+               edid = NULL;
+
+       fb_destroy_modelist(modelist);
+       INIT_LIST_HEAD(modelist);
+       if(spec->modedb)
+               kfree(spec->modedb);
+       memset(spec, 0, sizeof(struct fb_monspecs));
+       if(edid)
+       {
+               fb_edid_to_monspecs(edid, spec);
+               kfree(edid);
+               rk29fb_check_mode();            
+               defaultmode = rk29fb_find_default_mode();
+               if(defaultmode)
+                       mode = (struct fb_videomode *)fb_find_nearest_mode(defaultmode, &rk29_monspec.modelist);
+               else
+                       mode = (struct fb_videomode *)&rk29_mode[3];            
+               rk29_monspec.mode = mode;
+               return 0;
+       }
+       else
+       {
+               rk29fb_set_default_modelist();
+               return 1;
+       }
+}
+
+static int rk29_mode2screen(struct fb_videomode *modedb, struct rk29fb_screen *screen)
+{
+       if(modedb == NULL || screen == NULL)
+               return -1;
+               
+       memset(screen, 0, sizeof(struct rk29fb_screen));
+       /* screen type & face */
+    screen->type = SCREEN_HDMI;
+    screen->face = OUT_P888;
+       
+       /* Screen size */
+       screen->x_res = modedb->xres;
+    screen->y_res = modedb->yres;
+//     screen->xpos = 0;
+//    screen->ypos = 0;
+    /* Timing */
+    screen->pixclock = PICOS2KHZ(modedb->pixclock);
+    screen->pixclock /= 250;
+    screen->pixclock *= 250;
+    screen->pixclock *= 1000;
+    printk("pixclock is %d\n", screen->pixclock);
+       screen->lcdc_aclk = 500000000;
+       screen->left_margin = modedb->left_margin;
+       screen->right_margin = modedb->right_margin;
+       screen->hsync_len = modedb->hsync_len;
+       screen->upper_margin = modedb->upper_margin;
+       screen->lower_margin = modedb->lower_margin;
+       screen->vsync_len = modedb->vsync_len;
+
+       /* Pin polarity */
+       if(FB_SYNC_HOR_HIGH_ACT & modedb->sync)
+               screen->pin_hsync = 1;
+       else
+               screen->pin_hsync = 0;
+       if(FB_SYNC_VERT_HIGH_ACT & modedb->sync)
+               screen->pin_vsync = 1;
+       else
+               screen->pin_vsync = 0;  
+       screen->pin_den = 0;
+       screen->pin_dclk = 1;
+
+       /* Swap rule */
+    screen->swap_rb = 0;
+    screen->swap_rg = 0;
+    screen->swap_gb = 0;
+    screen->swap_delta = 0;
+    screen->swap_dumy = 0;
+
+    /* Operation function*/
+    screen->init = NULL;
+    screen->standby = NULL;    
+       return 0;
+}
+
+static int rk29_set_enable(struct rk_display_device *device, int enable)
+{
+       struct rk29_monspecs *rk29_monspec = device->priv_data;
+       printk("[%s] set enable %d\n", __FUNCTION__, enable);
+       if(enable != rk29_monspec->enable)
+       {
+               if(rk29_monspec->io_enable_pin != INVALID_GPIO) {
+                       gpio_set_value(rk29_monspec->io_enable_pin, enable?GPIO_HIGH:GPIO_LOW);
+               }
+               rk29_monspec->enable = enable;
+       }
+       
+       return 0;
+}
+
+static int rk29_get_enable(struct rk_display_device *device)
+{
+       struct rk29_monspecs *rk29_monspec = device->priv_data;
+       return rk29_monspec->enable;
+}
+
+static int rk29_get_status(struct rk_display_device *device)
+{
+       return (rk29fb_probe_screens(rk29_monspec.i2c_client))? 0:1;
+}
+
+static int rk29_get_modelist(struct rk_display_device *device, struct list_head **modelist)
+{
+       *modelist = &rk29_monspec.modelist;
+       return 0;
+}
+
+static int rk29_get_mode(struct rk_display_device *device, struct fb_videomode *mode)
+{
+       if(rk29_monspec.mode)
+       {
+               memcpy(mode, rk29_monspec.mode, sizeof(struct fb_videomode));
+               return 0;
+       }
+       else
+               return -1;
+}
+
+static int rk29_set_mode(struct rk_display_device *device, struct fb_videomode *mode)
+{
+       int i;
+       for(i = 0; i < ARRAY_SIZE(rk29_mode); i++)
+       {
+               if(fb_mode_is_equal(&rk29_mode[i], mode))
+               {       
+                       struct rk29fb_screen screen;    
+                       rk29_mode2screen(mode, &screen);
+                       FB_Switch_Screen(&screen, 1);
+                       rk29_monspec.mode = mode;
+                       return 0;
+               }
+       }
+       return -1;
+}
+struct rk_display_ops rk29_display_ops = {
+       .setenable = rk29_set_enable,
+       .getenable = rk29_get_enable,
+       .getstatus = rk29_get_status,
+       .getmodelist = rk29_get_modelist,
+       .setmode = rk29_set_mode,
+       .getmode = rk29_get_mode,
+};
+
+static int rk29_display_probe(struct rk_display_device *device, void *devdata)
+{
+       printk("%s: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n", __func__);
+       device->owner = THIS_MODULE;
+       strcpy(device->type, "VGA");
+       device->name = "vga";
+       //device->property = rk29_monspec.property;
+       device->priority = DISPLAY_PRIORITY_VGA;
+       device->priv_data = devdata;
+       device->ops = &rk29_display_ops;
+
+       return 1;
+}
+
+static struct rk_display_driver display_rk29 = {
+       .probe = rk29_display_probe,
+};
+
+static int vga_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
+{    
+    int ret;
+    //struct rkdisplay_platform_data *vga_data;
+       printk("%s: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n", __func__);
+    
+    memset(&rk29_monspec, 0, sizeof(struct rk29_monspecs));
+    rk29_monspec.i2c_client = client;
+    rk29_monspec.enable = 0;
+    
+    /*if(client->dev.platform_data) {
+       vga_data = client->dev.platform_data;
+       rk29_monspec.io_enable_pin = vga_data->io_switch_pin;
+       rk29_monspec.video_source = vga_data->video_source;
+               rk29_monspec.property = vga_data->property;
+    }
+       else*/ {
+               rk29_monspec.io_enable_pin = INVALID_GPIO;
+               rk29_monspec.video_source = 0;
+               rk29_monspec.property = 0;
+    }
+    if(rk29_monspec.io_enable_pin != INVALID_GPIO)
+    {
+        ret = gpio_request(rk29_monspec.io_enable_pin, NULL);
+        if(ret != 0)
+        {
+            gpio_free(rk29_monspec.io_enable_pin);
+            printk(">>>>>> vag enable gpio_request err \n ");
+            return -1;
+        }
+               gpio_direction_output(rk29_monspec.io_enable_pin, GPIO_LOW);
+    }
+    INIT_LIST_HEAD(&rk29_monspec.modelist);
+    rk29_monspec.ddev = rk_display_device_register(&display_rk29, &client->dev, &rk29_monspec);
+       if(rk29_monspec.ddev == NULL)
+       {
+               printk("[%s] registor display error\n", __FUNCTION__);
+               return -1;
+       }
+       rk_display_device_enable(rk29_monspec.ddev);
+       //if(rk29_monspec.enable)
+       if(1)
+       {
+               struct fb_videomode *defaultmode, *mode;
+               defaultmode = rk29fb_find_default_mode();
+               if(defaultmode)
+                       mode = (struct fb_videomode *)fb_find_nearest_mode(defaultmode, &rk29_monspec.modelist);
+               else
+                       mode = (struct fb_videomode *)&rk29_mode[0];
+printk("%s:  xres,yres(%d, %d)\n=============================\n\n\n", __func__, mode->xres, mode->yres);
+               if(mode)
+               {
+                       struct rk29fb_screen screen;    
+                       rk29_mode2screen(mode, &screen);
+                       printk("%s: lcdc id = %d video_source = %d\n", __func__, screen.lcdc_id, rk29_monspec.video_source);
+                       FB_Switch_Screen(&screen, 1);
+                       rk29_monspec.mode = mode;
+               }
+       }
+       return 0;
+}
+
+static int __devexit vga_i2c_remove(struct i2c_client *client)
+{
+       struct fb_monspecs      *spec = &rk29_monspec.monspecs;
+       struct list_head        *modelist = &rk29_monspec.modelist;
+       fb_destroy_modelist(modelist);
+       if(spec->modedb)
+               kfree(spec->modedb);
+       rk_display_device_unregister(rk29_monspec.ddev);
+       return 0;
+}
+
+static const struct i2c_device_id vga_id[] = {
+       { "vga_i2c", 0 },
+       { }
+};
+
+static struct i2c_driver vga_i2c_driver  = {
+    .driver = {
+        .name  = "vga_i2c",
+        .owner = THIS_MODULE,
+    },
+    .probe =    &vga_i2c_probe,
+    .remove     = &vga_i2c_remove,
+    .id_table  = vga_id,
+};
+
+static int __init rk29_vga_init(void)
+{
+       printk("%s: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n", __func__);
+    return i2c_add_driver(&vga_i2c_driver);
+}
+
+static void __exit rk29_vga_exit(void)
+{
+    i2c_del_driver(&vga_i2c_driver);
+}
+
+module_init(rk29_vga_init);
+module_exit(rk29_vga_exit);
diff --git a/include/linux/scaler-core.h b/include/linux/scaler-core.h
new file mode 100644 (file)
index 0000000..cc9d36d
--- /dev/null
@@ -0,0 +1,164 @@
+#ifndef __SCALER_CORE_H__
+#define __SCALER_CORE_H__
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include <linux/list.h>
+
+
+struct display_edid {
+       char *data;
+       char *ext_data;
+};
+
+enum scaler_output_type {
+       SCALER_OUT_INVALID = 0,
+       SCALER_OUT_LVDS,
+       SCALER_OUT_VGA,
+       SCALER_OUT_RGB,
+       SCALER_OUT_HDMI,
+       SCALER_OUT_DP,
+       SCALER_OUT_NUMS,
+};
+
+enum scaler_input_type {
+       SCALER_IN_INVALID = 0,
+       SCALER_IN_VGA,
+       SCALER_IN_RGB,
+       SCALER_IN_HDMI,
+       SCALER_IN_DP,
+       SCALER_IN_DVI,
+       SCALER_IN_YPBPR,
+       SCALER_IN_YCBCR,
+       SCALER_IN_MYDP,
+       SCALER_IN_IDP,
+       SCALER_IN_NUMS,
+};
+
+enum scaler_bus_type {
+       SCALER_BUS_TYPE_INVALID = 0,
+       SCALER_BUS_TYPE_UART,
+       SCALER_BUS_TYPE_I2C,
+       SCALER_BUS_TYPE_SPI,
+       SCALER_BUS_TYPE_NUMS,
+};
+
+/*
+ * the function of scaler, for example convertor or switch 
+*/
+enum scaler_function_type {
+       SCALER_FUNC_INVALID = 0,
+       SCALER_FUNC_CONVERTOR,   //转换器
+       SCALER_FUNC_SWITCH,      //切换开关多选一输出 
+       SCALER_FUNC_FULL,        //全功能
+       SCALER_FUNC_NUMS,
+};
+
+struct scaler_output_port {
+       int id;
+       int max_hres;
+       int max_vres;
+       int freq;
+       int led_gpio;   //working led
+       enum scaler_output_type type;
+       struct list_head next; 
+};
+
+struct scaler_input_port {
+       int id;
+       int max_hres;
+       int max_vres;
+       int freq;       //HZ
+       int led_gpio;   //working led
+       enum scaler_input_type type;
+       struct list_head next; 
+};
+
+struct scaler_chip_dev {
+       char id;
+       char name[I2C_NAME_SIZE];
+       struct i2c_client *client;
+       
+       enum scaler_function_type func_type;
+
+       int int_gpio;
+       int reset_gpio;
+       int power_gpio;
+       int status_gpio;
+       char reg_size;  //8bit = 1, 16bit = 2, 24bit = 3,32bit = 4.
+
+       struct list_head iports; //config all support input type by make menuconfig
+       struct list_head oports; //config all support output type by make menuconfig
+       enum scaler_input_type cur_in_type;
+       int cur_inport_id;
+       enum scaler_output_type cur_out_type;
+       int cur_outport_id;
+
+       //init hardware(gpio etc.)
+       int (*init_hw)(void);
+       int (*exit_hw)(void);
+
+       //enable chip to process image
+       void (*start)(void);
+       //disable chip to process image
+       void (*stop)(void);
+       void (*reset)(char active);
+       void (*suspend)(void);
+       void (*resume)(void);
+
+       //
+       int (*read)(unsigned short reg, int bytes, void *dest);
+       int (*write)(unsigned short reg, int bytes, void *src);
+       int (*parse_cmd)(unsigned int cmd, unsigned long arg);
+       int (*update_firmware)(void *data);
+
+       //scaler chip dev list
+       struct list_head next;
+};
+
+struct scaler_platform_data {
+       int int_gpio;
+       int reset_gpio;
+       int power_gpio;
+       int status_gpio; //check chip if work on lower power mode or normal mode.
+
+       char *firmware; 
+       //function type
+       enum scaler_function_type func_type;
+
+       //config in and out 
+       struct scaler_input_port  *iports;
+       struct scaler_output_port *oports;
+       int iport_size;
+       int oport_size;
+
+       int (*init_hw)(void);
+       int (*exit_hw)(void);
+};
+
+struct scaler_device {
+       struct class *class;
+       struct device *dev;
+       struct cdev *cdev;
+       dev_t devno;
+
+       struct display_edid edid;
+
+       struct list_head chips;
+};
+
+struct scaler_chip_dev *alloc_scaler_chip(void);
+//free chip memory and port memory
+void free_scaler_chip(struct scaler_chip_dev *chip);
+int init_scaler_chip(struct scaler_chip_dev *chip, struct scaler_platform_data *pdata);
+//
+int register_scaler_chip(struct scaler_chip_dev *chip);
+int unregister_scaler_chip(struct scaler_chip_dev *chip);
+
+#define SCALER_IOCTL_MAGIC 's'
+#define SCALER_IOCTL_POWER _IOW(SCALER_IOCTL_MAGIC, 0x00, char)
+#define SCALER_IOCTL_GET_CUR_INPUT _IOR(SCALER_IOCTL_MAGIC, 0x01, int)
+#define SCALER_IOCTL_SET_CUR_INPUT _IOW(SCALER_IOCTL_MAGIC, 0x02, int)
+
+#endif