From ed0e765a5422485e815539390120411132575fbd Mon Sep 17 00:00:00 2001 From: yxj Date: Wed, 3 Apr 2013 18:08:40 +0800 Subject: [PATCH] add mfd rk616 --- drivers/mfd/Kconfig | 9 + drivers/mfd/Makefile | 1 + drivers/mfd/rk616-core.c | 159 ++++++++++++++++++ drivers/video/display/transmitter/Kconfig | 6 + drivers/video/display/transmitter/Makefile | 1 + .../video/display/transmitter/rk616_lvds.c | 157 +++++++++++++++++ include/linux/mfd/rk616.h | 85 ++++++++++ 7 files changed, 418 insertions(+) create mode 100644 drivers/mfd/rk616-core.c create mode 100644 drivers/video/display/transmitter/rk616_lvds.c create mode 100644 include/linux/mfd/rk616.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9d7295794c9b..6aa29681a06d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -831,6 +831,15 @@ config MFD_RK610 help if you say yes here you get support for the RK610, with func as HDMI LCD LVDS TVOUT CODEC. + +config MFD_RK616 + bool "RK616(Jetta B) Multifunction device support" + depends on I2C=y + select MFD_CORE + help + if you say yes here you get support for the RK616, with func as + HDMI、LCD、LVDS、CODEC、MIPI. + endif # MFD_SUPPORT menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ef1239130589..b810c78978c7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -109,3 +109,4 @@ obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_RK610) += rk610-core.o obj-$(CONFIG_MFD_RK808) += rk808.o rk808-irq.o +obj-$(CONFIG_MFD_RK616) += rk616-core.o diff --git a/drivers/mfd/rk616-core.c b/drivers/mfd/rk616-core.c new file mode 100644 index 000000000000..5848bee62ce6 --- /dev/null +++ b/drivers/mfd/rk616-core.c @@ -0,0 +1,159 @@ + +#include +#include +#include +#include +#include +#include +#include + + +static struct mfd_cell rk616_devs[] = { + { + .name = "rk616-lvds", + .id = 0, + }, + { + .name = "rk616-codec", + .id = 1, + }, + { + .name = "rk616-hdmi", + .id = 2, + }, + { + .name = "rk616-mipi", + .id = 3, + }, +}; + +static int rk616_i2c_read_reg(struct mfd_rk616 *rk616, u16 reg,u32 *pval) +{ + struct i2c_client * client = rk616->client; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msgs[2]; + int ret; + char reg_buf[2]; + + memcpy(reg_buf, ®, 2); + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; + msgs[0].len = 2; + msgs[0].buf = reg_buf; + msgs[0].scl_rate = rk616->pdata->scl_rate; + msgs[0].udelay = client->udelay; + + msgs[1].addr = client->addr; + msgs[1].flags = client->flags | I2C_M_RD; + msgs[1].len = 4; + msgs[1].buf = (char *)pval; + msgs[1].scl_rate = rk616->pdata->scl_rate; + msgs[1].udelay = client->udelay; + + ret = i2c_transfer(adap, msgs, 2); + + + return (ret == 2)? 4 : ret; + +} + +static int rk616_i2c_write_reg(struct mfd_rk616 *rk616, u16 reg,u32 *pval) +{ + struct i2c_client *client = rk616->client; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg; + int ret; + char *tx_buf = (char *)kmalloc(6, GFP_KERNEL); + if(!tx_buf) + return -ENOMEM; + + memcpy(tx_buf, ®, 2); + memcpy(tx_buf+2, (char *)pval, 4); + + msg.addr = client->addr; + msg.flags = client->flags; + msg.len = 6; + msg.buf = (char *)tx_buf; + msg.scl_rate = rk616->pdata->scl_rate; + msg.udelay = client->udelay; + + ret = i2c_transfer(adap, &msg, 1); + kfree(tx_buf); + + + return (ret == 1) ? 4 : ret; +} + +static int rk616_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id) +{ + int ret; + struct mfd_rk616 *rk616 = NULL; + + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n"); + ret = -ENODEV; + } + rk616 = kzalloc(sizeof(struct mfd_rk616), GFP_KERNEL); + if (rk616 == NULL) + { + printk(KERN_ALERT "alloc for struct rk616 fail\n"); + ret = -ENOMEM; + } + + rk616->dev = &client->dev; + rk616->pdata = client->dev.platform_data; + rk616->client = client; + i2c_set_clientdata(client, rk616); + dev_set_drvdata(rk616->dev,rk616); + + if(rk616->pdata->power_init) + rk616->pdata->power_init(); + + rk616->read_dev = rk616_i2c_read_reg; + rk616->write_dev = rk616_i2c_write_reg; + ret = mfd_add_devices(rk616->dev, -1, + rk616_devs, ARRAY_SIZE(rk616_devs), + NULL, rk616->irq_base); + + printk("%s.........\n",__func__); + return 0; +} + +static int __devexit rk616_i2c_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id id_table[] = { + {"rk616", 0 }, + { } +}; + +static struct i2c_driver rk616_i2c_driver = { + .driver = { + .name = "rk616", + .owner = THIS_MODULE, + }, + .probe = &rk616_i2c_probe, + .remove = &rk616_i2c_remove, + .id_table = id_table, +}; + + +static int __init rk616_module_init(void) +{ + return i2c_add_driver(&rk616_i2c_driver); +} + +static void __exit rk616_module_exit(void) +{ + i2c_del_driver(&rk616_i2c_driver); +} + +subsys_initcall_sync(rk616_module_init); +module_exit(rk616_module_exit); + + diff --git a/drivers/video/display/transmitter/Kconfig b/drivers/video/display/transmitter/Kconfig index 7d8b93478814..0d16b082b927 100644 --- a/drivers/video/display/transmitter/Kconfig +++ b/drivers/video/display/transmitter/Kconfig @@ -10,6 +10,12 @@ config RK610_LVDS depends on MFD_RK610 help Support Jetta(RK610) to output LCD1 and LVDS. + +config RK616_LVDS + bool "RK616(Jetta B) lvds,lcd,scaler transmitter support" + depends on MFD_RK616 + help + RK616(Jetta B) LVDS,LCD,scaler transmitter support. config DP_ANX6345 diff --git a/drivers/video/display/transmitter/Makefile b/drivers/video/display/transmitter/Makefile index 9188597200a0..7c9ccf2a360c 100644 --- a/drivers/video/display/transmitter/Makefile +++ b/drivers/video/display/transmitter/Makefile @@ -2,6 +2,7 @@ # Makefile for display transmitter like lvds edp mipi # obj-$(CONFIG_RK610_LVDS) += rk610_lcd.o +obj-$(CONFIG_RK616_LVDS) += rk616_lvds.o obj-$(CONFIG_TC358768_RGB2MIPI) += mipi_dsi.o tc358768.o obj-$(CONFIG_SSD2828_RGB2MIPI) += mipi_dsi.o ssd2828.o obj-$(CONFIG_DP_ANX6345) += dp_anx6345.o diff --git a/drivers/video/display/transmitter/rk616_lvds.c b/drivers/video/display/transmitter/rk616_lvds.c new file mode 100644 index 000000000000..d7e2fb53581b --- /dev/null +++ b/drivers/video/display/transmitter/rk616_lvds.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include + +struct mfd_rk616 *g_rk616; + + +/*rk616 video interface config*/ +static int rk616_vif_cfg(struct mfd_rk616 *rk616,rk_screen *screen,int id) +{ + int ret = 0; + u32 val = 0; + int offset = 0; + if(id == 0) //video interface 0 + { + offset = 0; + } + else //vide0 interface 1 + { + offset = 0x18; + } + + val &= ((~VIF0_DDR_CLK_EN) & (~VIF0_DDR_PHASEN_EN) & (~VIF0_DDR_MODE_EN))| + (VIF0_EN); + val |= (VIF0_DDR_CLK_EN <<16) | (VIF0_DDR_PHASEN_EN << 16) | (VIF0_DDR_MODE_EN << 16)| + (VIF0_EN <<16); + + ret = rk616->write_dev(rk616,VIF0_REG0 + offset,&val); + + val = (screen->hsync_len + screen->left_margin) | ((screen->vsync_len + screen->upper_margin)<<16); + ret = rk616->write_dev(rk616,VIF0_REG1 + offset,&val); + + val = (screen->hsync_len << 16) | (screen->hsync_len + screen->left_margin + + screen->right_margin + screen->x_res); + ret = rk616->write_dev(rk616,VIF0_REG2 + offset,&val); + + + val = ((screen->hsync_len + screen->left_margin + screen->x_res)<<16) | + (screen->hsync_len + screen->left_margin); + ret = rk616->write_dev(rk616,VIF0_REG3 + offset,&val); + + val = (screen->vsync_len << 16) | (screen->vsync_len + screen->upper_margin + + screen->lower_margin + screen->y_res); + ret = rk616->write_dev(rk616,VIF0_REG4 + offset,&val); + + + val = ((screen->vsync_len + screen->upper_margin + screen->y_res)<<16) | + (screen->vsync_len + screen->upper_margin); + ret = rk616->write_dev(rk616,VIF0_REG5 + offset,&val); + + return ret; + +} + +static int rk616_vif_bypass(struct mfd_rk616 *rk616,int id) +{ + int ret; + u32 val = 0; + + val &= (~VIF0_EN); + val |= (VIF0_EN << 16); + if(id == 0) + { + ret = rk616->write_dev(rk616,VIF0_REG0,&val); + } + else + { + ret = rk616->write_dev(rk616,VIF1_REG0,&val); + } + + return ret; + +} +static int rk616_scaler_bypass(struct mfd_rk616 *rk616) +{ + u32 val = 0; + int ret; + + val &= (~SCL_EN); //disable scaler + val |= (SCL_EN<<16); + ret = rk616->write_dev(rk616,SCL_REG0,&val); + + return 0; + +} + +int rk610_lcd_scaler_set_param(rk_screen *screen,bool enable )//enable:0 bypass 1: scale +{ + int ret; + struct mfd_rk616 *rk616 = g_rk616; + if(!rk616) + { + printk(KERN_ERR "%s:mfd rk616 is null!\n",__func__); + return -1; + } + rk616_vif_bypass(rk616,0); + rk616_vif_bypass(rk616,1); + rk616_scaler_bypass(rk616); + + return ret; +} + +static int rk616_lvds_probe(struct platform_device *pdev) +{ + + struct mfd_rk616 *rk616 = dev_get_drvdata(pdev->dev.parent); + if(!rk616) + { + dev_err(&pdev->dev,"null mfd device rk616!\n"); + return -ENODEV; + } + else + g_rk616 = rk616; + + dev_info(&pdev->dev,"rk616 lvds probe success!\n"); + + return 0; + +} + +static int rk616_lvds_remove(struct platform_device *pdev) +{ + + return 0; +} + +static void rk616_lvds_shutdown(struct platform_device *pdev) +{ + + return; +} + +static struct platform_driver rk616_lvds_driver = { + .driver = { + .name = "rk616-lvds", + .owner = THIS_MODULE, + }, + .probe = rk616_lvds_probe, + .remove = rk616_lvds_remove, + .shutdown = rk616_lvds_shutdown, +}; + +static int __init rk616_lvds_init(void) +{ + return platform_driver_register(&rk616_lvds_driver); +} +subsys_initcall_sync(rk616_lvds_init); + +static void __exit rk616_lvds_exit(void) +{ + platform_driver_unregister(&rk616_lvds_driver); +} +module_exit(rk616_lvds_exit); + diff --git a/include/linux/mfd/rk616.h b/include/linux/mfd/rk616.h new file mode 100644 index 000000000000..2f160784d087 --- /dev/null +++ b/include/linux/mfd/rk616.h @@ -0,0 +1,85 @@ +#ifndef _RK616_H_ +#define _RK616_H_ + +#include +#include + + +#define VIF0_REG0 0x0000 +#define VIF0_DDR_CLK_EN (1<<3) +#define VIF0_DDR_PHASEN_EN (1<<2) //negative edge first en +#define VIF0_DDR_MODE_EN (1<<1) +#define VIF0_EN (1<<0) + +#define VIF0_REG1 0x0004 +#define VIF0_REG2 0x0008 +#define VIF0_REG3 0x000C +#define VIF0_REG4 0x0010 +#define VIF0_REG5 0x0014 +#define VIF1_REG0 0x0018 +#define VIF1_REG1 0x001C +#define VIF1_REG2 0x0020 +#define VIF1_REG3 0x0024 +#define VIF1_REG4 0x0028 +#define VIF1_REG5 0x002C +#define SCL_REG0 0x0030 +#define SCL_EN (1<<0) + +#define SCL_REG1 0x0034 +#define SCL_REG2 0x0038 +#define SCL_REG3 0x003C +#define SCL_REG4 0x0040 +#define SCL_REG5 0x0044 +#define SCL_REG6 0x0048 +#define SCL_REG7 0x004C +#define SCL_REG8 0x0050 +#define FRC_REG 0x0054 +#define CRU_CLKSEL0_CON 0x0058 +#define CRU_CLKSEL1_CON 0x005C +#define CRU_CODEC_DIV 0x0060 +#define CRU_CLKSE2_CON 0x0064 +#define CRU_PLL0_CON0 0x0068 +#define CRU_PLL0_CON1 0x006C +#define CRU_PLL0_CON2 0x0070 +#define CRU_PLL1_CON0 0x0074 +#define CRU_PLL1_CON1 0x0078 +#define CRU_PLL1_CON2 0x007C +#define CRU_I2C_CON0 0x0080 +#define CRU_LVDS_CON0 0x0084 +#define CRU_IO_CON0 0x0088 +#define CRU_IO_CON1 0x008C +#define CRU_PCM2IS2_CON0 0x0090 +#define CRU_PCM2IS2_CON1 0x0094 +#define CRU_PCM2IS2_CON2 0x0098 +#define CRU_CFGMISC_CON 0x009C + + + + + + + + + + + + + + + +struct rk616_platform_data { + int (*power_init)(void); + int scl_rate; +}; +struct mfd_rk616 { + struct mutex reg_lock; + + struct device *dev; + unsigned int irq_base; + struct rk616_platform_data *pdata; + struct i2c_client *client; + int (*read_dev)(struct mfd_rk616 *rk616, u16 reg,u32 *pval); + int (*write_dev)(struct mfd_rk616 *rk616,u16 reg,u32 *pval); +}; +#endif + -- 2.34.1