From c8cdb6107eb46dd13329c70a40d46c87ca168833 Mon Sep 17 00:00:00 2001 From: yxj Date: Mon, 21 Jan 2013 16:23:22 +0800 Subject: [PATCH] edp transmitter dp501 support --- arch/arm/mach-rk30/board-rk30-sdk.c | 75 +++++- drivers/video/display/transmitter/Kconfig | 3 + drivers/video/display/transmitter/Makefile | 1 + drivers/video/display/transmitter/dp501.c | 276 +++++++++++++++++++++ include/linux/dp501.h | 39 +++ 5 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 drivers/video/display/transmitter/dp501.c create mode 100644 include/linux/dp501.h diff --git a/arch/arm/mach-rk30/board-rk30-sdk.c b/arch/arm/mach-rk30/board-rk30-sdk.c index 2a93568cf9a5..04eb4f406910 100755 --- a/arch/arm/mach-rk30/board-rk30-sdk.c +++ b/arch/arm/mach-rk30/board-rk30-sdk.c @@ -77,6 +77,9 @@ #include #endif +#if defined(CONFIG_DP501) //for display port transmitter dp501 +#include +#endif #ifdef CONFIG_THREE_FB_BUFFER #define RK30_FB0_MEM_SIZE 12*SZ_1M #else @@ -234,7 +237,7 @@ static struct spi_board_info board_spi_devices[] = { #define PWM_MUX_NAME GPIO0A3_PWM0_NAME #define PWM_MUX_MODE GPIO0A_PWM0 #define PWM_MUX_MODE_GPIO GPIO0A_GPIO0A3 -#define PWM_GPIO RK30_PIN0_PA3 +#define PWM_GPIO RK30_PIN0_PA3 #define PWM_EFFECT_VALUE 1 #define LCD_DISP_ON_PIN @@ -801,6 +804,67 @@ static struct platform_device device_lcdc1 = { }; #endif +#if defined(CONFIG_DP501) + #define DVDD33_EN_PIN RK30_PIN6_PB4 + #define DVDD33_EN_VALUE GPIO_LOW + + #define DVDD12_EN_PIN RK30_PIN4_PC7 + #define DVDD12_EN_VALUE GPIO_HIGH + + #define EDP_RST_PIN RK30_PIN2_PC4 + static int rk_edp_power_ctl(void) + { + int ret; + ret = gpio_request(DVDD33_EN_PIN, "dvdd33_en_pin"); + if (ret != 0) + { + gpio_free(DVDD33_EN_PIN); + printk(KERN_ERR "request dvdd33 en pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(DVDD33_EN_PIN, DVDD33_EN_VALUE); + } + + ret = gpio_request(DVDD12_EN_PIN, "dvdd18_en_pin"); + if (ret != 0) + { + gpio_free(DVDD12_EN_PIN); + printk(KERN_ERR "request dvdd18 en pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(DVDD12_EN_PIN, DVDD12_EN_VALUE); + } + + ret = gpio_request(EDP_RST_PIN, "edp_rst_pin"); + if (ret != 0) + { + gpio_free(EDP_RST_PIN); + printk(KERN_ERR "request rst pin fail!\n"); + return -1; + } + else + { + gpio_direction_output(EDP_RST_PIN, GPIO_LOW); + msleep(10); + gpio_direction_output(EDP_RST_PIN, GPIO_HIGH); + } + return 0; + + } + static struct dp501_platform_data dp501_platform_data = { + .power_ctl = rk_edp_power_ctl, + .dvdd33_en_pin = DVDD33_EN_PIN, + .dvdd33_en_val = DVDD33_EN_VALUE, + .dvdd18_en_pin = DVDD12_EN_PIN, + .dvdd18_en_val = DVDD12_EN_VALUE, + .edp_rst_pin = EDP_RST_PIN, + }; +#endif + #if defined(CONFIG_MFD_RK610) #define RK610_RST_PIN_MUX_NAME GPIO0C6_TRACECLK_SMCADDR2_NAME #define RK610_RST_PIN_MUX_MODE GPIO0C_GPIO0C6 @@ -1630,6 +1694,15 @@ static struct i2c_board_info __initdata i2c2_info[] = { .platform_data = &cm3217_info, }, #endif + +#if defined(CONFIG_DP501) + { + .type = "dp501", + .addr = 0x30, + .flags = 0, + .platform_data = &dp501_platform_data, + }, +#endif }; #endif diff --git a/drivers/video/display/transmitter/Kconfig b/drivers/video/display/transmitter/Kconfig index ec6bd963b9bf..bca74070441a 100644 --- a/drivers/video/display/transmitter/Kconfig +++ b/drivers/video/display/transmitter/Kconfig @@ -18,5 +18,8 @@ config TC358768_RGB2MIPI config DP_ANX6345 bool "RGB to Display Port transmitter anx6345,anx9804,anx9805 support" + +config DP501 + bool"RGB to Display Port transmitter dp501 support" endchoice diff --git a/drivers/video/display/transmitter/Makefile b/drivers/video/display/transmitter/Makefile index 0a02ea7c5141..284e9c5a54d3 100644 --- a/drivers/video/display/transmitter/Makefile +++ b/drivers/video/display/transmitter/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_RK610_LVDS) += rk610_lcd.o obj-$(CONFIG_TC358768_RGB2MIPI) += tc358768.o obj-$(CONFIG_DP_ANX6345) += dp_anx6345.o +obj-$(CONFIG_DP501) += dp501.o diff --git a/drivers/video/display/transmitter/dp501.c b/drivers/video/display/transmitter/dp501.c new file mode 100644 index 000000000000..6f9c68a4aaff --- /dev/null +++ b/drivers/video/display/transmitter/dp501.c @@ -0,0 +1,276 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +static int dp501_write_reg(struct i2c_client *client,char index,char reg,char val) +{ + int ret; + if(index == 0) //page 0 + { + client->addr = (DP501_P0_ADDR >> 1); + } + else if(index == 1) //page1 + { + client->addr = (DP501_P1_ADDR >> 1); + } + else if(index == 2) //page 2 + { + client->addr = (DP501_P2_ADDR >> 1); + } + else if(index == 3) + { + client->addr = (DP501_P3_ADDR >> 1); + } + else + { + dev_err(&client->dev,"invalid page number\n"); + return -EINVAL; + } + ret = i2c_master_reg8_send(client, reg, &val, 1,DP501_SCL_RATE); + if(ret < 0) + { + + dev_err(&client->dev,"%s page%d:0x%x err\n",__func__,index,reg); + ret = -EINVAL; + } + + return ret; + +} + +static char dp501_read_reg(struct i2c_client *client,char index,char reg) +{ + int ret; + char val; + if(index == 0) //page 0 + { + client->addr = (DP501_P0_ADDR >> 1); + } + else if(index == 1) //page1 + { + client->addr = (DP501_P1_ADDR>>1); + } + else if(index == 2) //page 2 + { + client->addr = (DP501_P2_ADDR>>1); + } + else if(index == 3) + { + client->addr = (DP501_P3_ADDR>>1); + } + else + { + dev_err(&client->dev,"invalid page number\n"); + return -EINVAL; + } + + + ret = i2c_master_reg8_recv(client, reg, &val, 1, DP501_SCL_RATE); + if(ret < 0) + { + dev_err(&client->dev,"%s page%d:0x%x err\n",__func__,index,reg); + return -EINVAL; + } + + return val; + +} +static int get_dp_chip_id(struct i2c_client *client) +{ + char c1,c2; + int id; + c1 = dp501_read_reg(client,2,CHIP_ID_L); + c2 = dp501_read_reg(client,2,CHIP_ID_H); + id = c2; + return (id<<8)|c1; + return 0; +} + +static int dp501_init(struct i2c_client *client) +{ + char val,val1; + dp501_write_reg(client,2,0x24,0x02); + dp501_write_reg(client,2,0x25,0x04); + dp501_write_reg(client,2,0x26,0x10); //PIO setting + + dp501_write_reg(client,0,0x0a,0x0c); //block 74 & 76 + dp501_write_reg(client,0,0x27,0x30); //auto detect CRTC + dp501_write_reg(client,0,0x2f,0x82); //reset tpfifo at v blank + dp501_write_reg(client,0,0x24,0xc0); //DVO mapping ; crtc follow mode + dp501_write_reg(client,0,0x28,0x07); //crtc follow mode + dp501_write_reg(client,0,0x87,0x7f); //aux retry + dp501_write_reg(client,0,0x88,0x1e); //aux retry + dp501_write_reg(client,0,0xbb,0x06); //aux retry + dp501_write_reg(client,0,0x72,0xa9); //DPCD readable + dp501_write_reg(client,0,0x60,0x00); //Scramble on + dp501_write_reg(client,0,0x8f,0x02); //debug select, read P0.0x8d[2] can check HPD + + //second, set up training + dp501_write_reg(client,0,0x5d,0x0A); //training link rate(2.7Gbps) + dp501_write_reg(client,0,0x5e,0x84); //training lane count(4Lanes), + dp501_write_reg(client,0,0x74,0x00); //idle pattern + dp501_write_reg(client,0,0x5f,0x0d); //trigger training + mdelay(100); //delay 100ms + + //then, check training result + val = dp501_read_reg(client,0,0x63); + val1 = dp501_read_reg(client,0,0x64); //Each 4bits stand for one lane, 0x77/0x77 means training succeed with 4Lanes. + dev_info(&client->dev,"training result:>>val:0x%x>>val1:0x%x\n",val,val1); + + return 0; +} + + + +static int edp_reg_show(struct seq_file *s, void *v) +{ + int i = 0; + char val; + struct dp501 *dp501= s->private; + + seq_printf(s,"page 0:\n"); + for(i=0;i< MAX_REG;i++) + { + val = dp501_read_reg(dp501->client,0,i); + seq_printf(s,"0x%02x>>0x%02x\n",i,val); + } + + seq_printf(s,"page 1:\n"); + for(i=0;i< MAX_REG;i++) + { + val = dp501_read_reg(dp501->client,1,i); + seq_printf(s,"0x%02x>>0x%02x\n",i,val); + } + + seq_printf(s,"page 2:\n"); + for(i=0;i< MAX_REG;i++) + { + val = dp501_read_reg(dp501->client,0,i); + seq_printf(s,"0x%02x>>0x%02x\n",2,val); + } + + seq_printf(s,"page 3:\n"); + for(i=0;i< MAX_REG;i++) + { + val = dp501_read_reg(dp501->client,3,i); + seq_printf(s,"0x%02x>>0x%02x\n",i,val); + } + + return 0; +} + +static int edp_reg_open(struct inode *inode, struct file *file) +{ + struct dp501 *dp501 = inode->i_private; + return single_open(file,edp_reg_show,dp501); +} + +static const struct file_operations edp_reg_fops = { + .owner = THIS_MODULE, + .open = edp_reg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void dp501_early_suspend(struct early_suspend *h) +{ + +} + +static void dp501_late_resume(struct early_suspend *h) +{ + +} + +static int dp501_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id) +{ + int ret; + + struct dp501 *dp501 = NULL; + int chip_id; + + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n"); + ret = -ENODEV; + } + dp501 = kzalloc(sizeof(struct dp501), GFP_KERNEL); + if (dp501 == NULL) + { + dev_err(&client->dev,"alloc for struct dp501 fail\n"); + ret = -ENOMEM; + } + + dp501->client = client; + dp501->pdata = client->dev.platform_data; + i2c_set_clientdata(client,dp501); + if(dp501->pdata->power_ctl) + dp501->pdata->power_ctl(); + + debugfs_create_file("edp-reg", S_IRUSR,NULL,dp501,&edp_reg_fops); + +#ifdef CONFIG_HAS_EARLYSUSPEND + dp501->early_suspend.suspend = dp501_early_suspend; + dp501->early_suspend.resume = dp501_late_resume; + dp501->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING; + register_early_suspend(&dp501->early_suspend); +#endif + + chip_id = get_dp_chip_id(client); + dp501->edp_init = dp501_init; + dp501->edp_init(client); + + + printk("edp dp%x probe ok\n",chip_id); + + return ret; +} + +static int __devexit dp501_i2c_remove(struct i2c_client *client) +{ + return 0; +} + + +static const struct i2c_device_id id_table[] = { + {"dp501", 0 }, + { } +}; + +static struct i2c_driver dp501_i2c_driver = { + .driver = { + .name = "dp501", + .owner = THIS_MODULE, + }, + .probe = &dp501_i2c_probe, + .remove = &dp501_i2c_remove, + .id_table = id_table, +}; + + +static int __init dp501_module_init(void) +{ + return i2c_add_driver(&dp501_i2c_driver); +} + +static void __exit dp501_module_exit(void) +{ + i2c_del_driver(&dp501_i2c_driver); +} + +fs_initcall_sync(dp501_module_init); +module_exit(dp501_module_exit); + diff --git a/include/linux/dp501.h b/include/linux/dp501.h new file mode 100644 index 000000000000..2e9fb4a7bf1d --- /dev/null +++ b/include/linux/dp501.h @@ -0,0 +1,39 @@ +#ifndef __DP501_H_ +#define __DP501_H_ + +#include +#include + + +#define DP501_P0_ADDR (0x30) +#define DP501_P1_ADDR (0x32) +#define DP501_P2_ADDR (0x34) +#define DP501_P3_ADDR (0x36) + +#define DP501_SCL_RATE (100*1000) +#define MAX_REG (0xff) + + + +#define CHIP_ID_L (0x80) +#define CHIP_ID_H (0x81) + +struct dp501_platform_data { + unsigned int dvdd33_en_pin; + int dvdd33_en_val; + unsigned int dvdd18_en_pin; + int dvdd18_en_val; + unsigned int edp_rst_pin; + int (*power_ctl)(void); +}; + +struct dp501 { + struct i2c_client *client; + struct dp501_platform_data *pdata; + int (*edp_init)(struct i2c_client *client); +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + +#endif -- 2.34.1