edp transmitter dp501 support
authoryxj <yxj@rock-chips.com>
Mon, 21 Jan 2013 08:23:22 +0000 (16:23 +0800)
committeryxj <yxj@rock-chips.com>
Mon, 21 Jan 2013 08:24:39 +0000 (16:24 +0800)
arch/arm/mach-rk30/board-rk30-sdk.c
drivers/video/display/transmitter/Kconfig
drivers/video/display/transmitter/Makefile
drivers/video/display/transmitter/dp501.c [new file with mode: 0644]
include/linux/dp501.h [new file with mode: 0644]

index 2a93568cf9a529cbb73082ffdae4b5f0f21c94e4..04eb4f406910b393038e62e8646e198d9184f2aa 100755 (executable)
@@ -77,6 +77,9 @@
 #include <linux/gps.h>
 #endif
 
+#if defined(CONFIG_DP501)   //for display port transmitter dp501
+#include<linux/dp501.h>
+#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
 
index ec6bd963b9bf3e497ef1163c6877fd65c55a32fd..bca74070441aa0528b9b95a9cd7bc147fa69adb4 100644 (file)
@@ -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
index 0a02ea7c5141fcd8ec168f8116c3f69605df1a30..284e9c5a54d37bcebff272f2d738c5918f6d5b5c 100644 (file)
@@ -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 (file)
index 0000000..6f9c68a
--- /dev/null
@@ -0,0 +1,276 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/dp501.h>
+#include <linux/debugfs.h>
+
+
+
+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 (file)
index 0000000..2e9fb4a
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __DP501_H_
+#define __DP501_H_
+
+#include <linux/i2c.h>
+#include<linux/earlysuspend.h>
+
+
+#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