add vga support on rockchip platform

This commit is contained in:
yxj
2014-08-18 20:12:35 +08:00
parent db3919580c
commit f0a3d836ca
3 changed files with 354 additions and 3 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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);