add vga support on rockchip platform
authoryxj <yxj@rock-chips.com>
Mon, 18 Aug 2014 12:12:35 +0000 (20:12 +0800)
committeryxj <yxj@rock-chips.com>
Wed, 3 Sep 2014 10:16:40 +0000 (18:16 +0800)
drivers/video/rockchip/transmitter/Kconfig
drivers/video/rockchip/transmitter/Makefile
drivers/video/rockchip/transmitter/vga.c [new file with mode: 0644]

index 295a8cbff33cb2935aa02c3c48a512771f30045c..b773db1c2c8a583eafd0c34610067960498f23b1 100755 (executable)
@@ -45,13 +45,20 @@ config RK32_DP
        bool "RK32 RGB to DisplayPort transmitter support "
        depends on RK_TRSM
 
+config RK_VGA
+         bool "VGA support on RockChip platform"
+         depends on RK_TRSM
+         default y
+         help
+           say y here will enable VGA on RockChip platform
+
 config MIPI_DSI
        depends on RK_TRSM
        bool "Rockchip MIPI DSI support"
 
 config TC358768_RGB2MIPI
         tristate "toshiba TC358768 RGB to MIPI DSI"
-               depends on MIPI_DSI
+       depends on MIPI_DSI
         help
         "a chip that change RGB interface parallel signal into DSI serial signal"
 
@@ -73,4 +80,5 @@ config RK616_MIPI_DSI_RST
        depends on MFD_RK616 && RK616_MIPI_DSI && RK616_USE_MCLK_12M
        default y
        help
-        if you say y here: inset the hdmi, mipi lcd will be reset.  
+        if you say y here: inset the hdmi, mipi lcd will be reset. 
+
index a1bfe0078f8b49ea2f99bcae89b3189e2eefc095..c4cb48850ac46691e8fbf7c81e598442989c00fe 100755 (executable)
@@ -12,7 +12,8 @@ obj-$(CONFIG_DP501)           += dp501.o
 obj-$(CONFIG_RK32_DP)          += rk32_dp.o rk32_dp_reg.o
 obj-$(CONFIG_MIPI_DSI)         += mipi_dsi.o 
 obj-$(CONFIG_RK616_MIPI_DSI)   += rk616_mipi_dsi.o
-obj-$(CONFIG_RK32_MIPI_DSI)            += rk32_mipi_dsi.o
+obj-$(CONFIG_RK32_MIPI_DSI)    += rk32_mipi_dsi.o
 obj-$(CONFIG_TC358768_RGB2MIPI)        += tc358768.o
 obj-$(CONFIG_SSD2828_RGB2MIPI) += ssd2828.o
+obj-$(CONFIG_RK_VGA)           += vga.o
 
diff --git a/drivers/video/rockchip/transmitter/vga.c b/drivers/video/rockchip/transmitter/vga.c
new file mode 100644 (file)
index 0000000..f5a6fc8
--- /dev/null
@@ -0,0 +1,342 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/display-sys.h>
+#include <linux/rk_screen.h>
+#include <linux/rk_fb.h>
+#ifdef CONFIG_OF
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#endif
+
+#include "../../edid.h"
+
+#ifdef CONFIG_SWITCH
+#include <linux/switch.h>
+#endif
+       
+
+#define DDC_ADDR               0x50
+#define DDC_I2C_RATE           100*1000
+#define INVALID_GPIO           -1
+#define GPIO_HIGH              1
+#define GPIO_LOW               0
+#define DISPLAY_SOURCE_LCDC0    0
+#define DISPLAY_SOURCE_LCDC1    1
+
+//static char *vgaenvent[] = {"INTERFACE=VGA", NULL}; 
+
+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)
+{      "1024x768p@60Hz",       60,             1024,   768,    KHZ2PICOS(65000),       160,    24,     29,     3,      136,    6,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   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(116500),      232,    80,     25,     3,      152,    6,              FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,                   0,              0       },
+{      "1680x1050p@60Hz",      60,             1680,   1050,   KHZ2PICOS(146250),      280,    104,    30,     3,      176,    6,              FB_SYNC_HOR_HIGH_ACT | 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       },
+};
+
+struct rockchip_vga {
+       struct device            *dev;  /*i2c device*/
+       struct rk_display_device *ddev; /*display device*/
+       struct i2c_client        *client;
+       struct list_head         modelist;
+       struct fb_monspecs       specs;
+       struct rk_screen         screen;
+       int                      indx;
+       int                      en_pin;
+       int                      en_val;
+       int                      lcdc_id;
+#ifdef CONFIG_SWITCH
+       struct switch_dev        switch_vga;
+#endif
+};
+
+static int i2c_master_reg8_recv(const struct i2c_client *client,
+               const char reg, char *buf, int count, int scl_rate)
+{
+        struct i2c_adapter *adap=client->adapter;
+        struct i2c_msg msgs[2];
+        int ret;
+        char reg_buf = reg;
+
+        msgs[0].addr = client->addr;
+        msgs[0].flags = client->flags;
+        msgs[0].len = 1;
+        msgs[0].buf = &reg_buf;
+        msgs[0].scl_rate = scl_rate;
+
+        msgs[1].addr = client->addr;
+        msgs[1].flags = client->flags | I2C_M_RD;
+        msgs[1].len = count;
+        msgs[1].buf = (char *)buf;
+        msgs[1].scl_rate = scl_rate;
+
+        ret = i2c_transfer(adap, msgs, 2);
+
+        return (ret == 2)? count : ret;
+}
+
+
+
+static unsigned char *rk29fb_ddc_read(struct i2c_client *client)
+{
+       int rc;
+       unsigned char *buf = kzalloc(EDID_LENGTH, GFP_KERNEL);
+       if (!buf) {
+               dev_err(&client->dev, "unable to allocate memory for EDID\n");
+               return NULL;
+       }
+       
+       /*Check ddc i2c communication is available or not*/
+       rc = i2c_master_reg8_recv(client, 0, buf, 6, DDC_I2C_RATE);
+       if (rc == 6) {
+               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_err(&client->dev, "unable to read EDID block.\n");
+       kfree(buf);
+       return NULL;
+}
+
+static int vga_mode2screen(struct fb_videomode *modedb, struct rk_screen *screen)
+{
+       if(modedb == NULL || screen == NULL)
+               return -1;
+               
+       memset(screen, 0, sizeof(struct rk_screen));
+       memcpy(&screen->mode, modedb, sizeof(*modedb));
+       screen->mode.pixclock = PICOS2KHZ(screen->mode.pixclock);
+       screen->mode.pixclock /= 250;
+       screen->mode.pixclock *= 250;
+       screen->mode.pixclock *= 1000;
+       screen->xsize = screen->mode.xres;
+       screen->ysize = screen->mode.yres;
+       screen->overscan.left = 100;
+       screen->overscan.top = 100;
+       screen->overscan.right = 100;
+       screen->overscan.bottom = 100;
+       /* screen type & face */
+       screen->type = SCREEN_RGB;
+       screen->face = OUT_P888;
+
+       screen->pin_vsync = (screen->mode.sync & FB_SYNC_VERT_HIGH_ACT) ? 1:0;
+       screen->pin_hsync = (screen->mode.sync & FB_SYNC_HOR_HIGH_ACT) ? 1:0;
+       screen->pin_den = 0;
+       screen->pin_dclk = 0;
+
+       /* 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 vga_switch_screen(struct rockchip_vga *vga, int indx)
+{
+       struct fb_videomode *mode = &vga->specs.modedb[indx];
+       struct rk_screen *screen = &vga->screen;
+       vga_mode2screen(mode, screen);
+       rk_fb_switch_screen(screen, 1 ,vga->lcdc_id);
+       vga->indx = indx;
+       return 0;
+       
+       
+}
+static int vga_get_screen_info(struct rockchip_vga *vga)
+{
+       u8 *edid;
+       int i;
+       struct fb_monspecs *specs = &vga->specs;
+       struct list_head *modelist = &vga->modelist;
+       edid = rk29fb_ddc_read(vga->client);
+       if (!edid) {
+               dev_info(vga->dev, "get edid failed!\n");
+               return -EINVAL;
+       }
+       fb_edid_to_monspecs(edid,specs);
+       INIT_LIST_HEAD(modelist);
+       for (i = 0; i < specs->modedb_len; i++) {
+               fb_add_videomode(&specs->modedb[i], modelist);
+               dev_dbg(vga->dev, "%4dx%4d@%d---dclk:%ld\n",
+                       specs->modedb[i].xres, specs->modedb[i].yres,
+                       specs->modedb[i].refresh,
+                       (PICOS2KHZ(specs->modedb[i].pixclock)/250)*250*1000);
+       }
+       return 0;
+       
+}
+
+
+
+static int vga_get_modelist(struct rk_display_device *device,
+                            struct list_head **modelist)
+{
+       struct rockchip_vga *vga = device->priv_data;
+       *modelist = &vga->modelist;
+       return 0;
+}
+
+static int vga_set_mode(struct rk_display_device *device,
+                        struct fb_videomode *mode)
+{
+       struct rockchip_vga *vga = device->priv_data;
+       struct rk_screen *screen = &vga->screen;
+       vga_mode2screen(mode, screen);
+       rk_fb_switch_screen(screen, 1 ,vga->lcdc_id);
+       return 0;
+}
+
+static int vga_get_mode(struct rk_display_device *device,
+                        struct fb_videomode *mode)
+{
+       //struct vga *vga = device->priv_data;
+       //struct fb_videomode *vmode;
+
+       return 0;
+}
+
+struct rk_display_ops vga_display_ops = {
+       .getmodelist = vga_get_modelist,
+       .setmode = vga_set_mode,
+       .getmode = vga_get_mode,
+};
+
+static int vga_display_probe(struct rk_display_device *device, void *devdata)
+{
+       device->owner = THIS_MODULE;
+       strcpy(device->type, "VGA");
+       device->priority = DISPLAY_PRIORITY_VGA;
+       device->priv_data = devdata;
+       device->ops = &vga_display_ops;
+       return 1;
+}
+
+static struct rk_display_driver display_vga = {
+       .probe = vga_display_probe,
+};
+
+
+
+struct rk_display_device * vga_register_display_sysfs(struct rockchip_vga *vga)
+{
+       return rk_display_device_register(&display_vga, vga->dev, vga);
+}
+
+void vga_unregister_display_sysfs(struct rockchip_vga *vga)
+{
+       if (vga->ddev)
+               rk_display_device_unregister(vga->ddev);
+}
+
+
+static int vga_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
+{    
+       int ret;
+       struct rockchip_vga *vga;
+       struct device_node *np = client->dev.of_node;
+       enum of_gpio_flags pwr_flags;
+
+       if (!np) {
+               dev_err(&client->dev, "no device node found!\n");
+               return -EINVAL;
+       } 
+
+       vga = devm_kzalloc(&client->dev, sizeof(*vga), GFP_KERNEL);
+       if (!vga) {
+               dev_err(&client->dev, "allocate for vga failed!\n");
+               return -ENOMEM;
+       }
+
+       vga->client = client;
+       vga->dev = &client->dev;
+       i2c_set_clientdata(client, vga);
+       vga->ddev = vga_register_display_sysfs(vga);
+       if (IS_ERR(vga->ddev))
+               dev_warn(vga->dev, "Unable to create device for vga :%ld",
+                       PTR_ERR(vga->ddev));
+       
+       vga->en_pin = of_get_named_gpio_flags(np, "pwr_gpio", 0, &pwr_flags);
+       if (!gpio_is_valid(vga->en_pin)) {
+               dev_err(vga->dev, "failed to get pwr_gpio!\n");
+               ret =  -EINVAL;
+               goto err;
+       }
+
+       vga->en_val = (pwr_flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+       vga->lcdc_id = DISPLAY_SOURCE_LCDC1;
+       
+       ret = devm_gpio_request(vga->dev, vga->en_pin, "pwr_pin");
+       if(ret < 0) {
+               dev_err(vga->dev, "request for pwr_pin failed!\n ");
+               goto err;
+       }
+       gpio_direction_output(vga->en_pin, vga->en_val);
+       ret = vga_get_screen_info(vga);
+       if (ret < 0)
+               goto err;
+       vga_switch_screen(vga, 7);
+       
+       printk("VGA probe successful\n");
+       return 0;
+err:
+       vga_unregister_display_sysfs(vga);
+       return ret;
+       
+}
+
+
+static int vga_i2c_remove(struct i2c_client *client)
+{
+       return 0;
+}
+
+
+#if defined(CONFIG_OF)
+static struct of_device_id vga_dt_ids[] = {
+       {.compatible = "rockchip,vga" },
+       { }
+};
+#endif
+
+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,
+#if defined(CONFIG_OF)
+               .of_match_table = of_match_ptr(vga_dt_ids),
+#endif
+       },
+       .probe          = &vga_i2c_probe,
+       .remove         = &vga_i2c_remove,
+       .id_table       = vga_id,
+};
+
+static int __init rockchip_vga_init(void)
+{
+    return i2c_add_driver(&vga_i2c_driver);
+}
+
+static void __exit rockchip_vga_exit(void)
+{
+    i2c_del_driver(&vga_i2c_driver);
+}
+
+module_init(rockchip_vga_init);
+module_exit(rockchip_vga_exit);