From 09fe4f7ce6c8c69de3abd3c986d1fab44cf6f6b9 Mon Sep 17 00:00:00 2001 From: Adrian Alonso Date: Wed, 24 Oct 2012 11:37:11 -0500 Subject: [PATCH] ENGR00231266-2: adv7280_mipi_tvin add i2c dummy client for csi config * Add i2c dummy client for csi-tx register map config * adv7280 csi-tx reg banks are mapped in a different memory map and respond to a different i2c slave address that user can configure * Add default config helper function * Override slave csi-tx address if user provides a different value. Signed-off-by: Adrian Alonso --- .../video/mxc/capture/adv7280_mipi_tvin.c | 150 +++++++++++++----- 1 file changed, 108 insertions(+), 42 deletions(-) diff --git a/drivers/media/video/mxc/capture/adv7280_mipi_tvin.c b/drivers/media/video/mxc/capture/adv7280_mipi_tvin.c index d4e1d2ddc16b..4310cb09bd93 100644 --- a/drivers/media/video/mxc/capture/adv7280_mipi_tvin.c +++ b/drivers/media/video/mxc/capture/adv7280_mipi_tvin.c @@ -31,6 +31,7 @@ #define ADV7280_SAMPLE_SILICON 0x40 #define ADV7280_PROD_SILICON 0x41 +#define ADV7280_CSI_TX_ADDR 0x50 /** ADV7280 register definitions */ #define ADV7280_INPUT_CTL 0x00 /* Input Control */ #define ADV7280_STATUS_1 0x10 /* Status #1 */ @@ -42,6 +43,7 @@ #define ADV7280_SD_SATURATION_CR 0xe4 /* SD Saturation Cr */ #define ADV7280_PM_REG 0x0f /* Power Management */ #define ADV7280_ADI_CONTROL1 0x0E /* ADI Control 1 */ +#define ADV7280_CSI_TX_SLAVE_ADDR 0xFE /* csi-tx slave address register */ /* adv7280 power management reset bit */ #define ADV7280_PM_RESET_BIT 0x80 /** adv7280 input video masks */ @@ -62,9 +64,11 @@ struct reg_value { u32 delay_ms; }; -struct adv7280_priv { - struct fsl_mxc_tvin_platform_data *pdata; +struct adv7280_chipset { + struct device *dev; struct i2c_client *client; + struct i2c_client *client_csi_tx; + struct fsl_mxc_tvin_platform_data *pdata; }; /*! @@ -86,22 +90,29 @@ static struct reg_value adv7280_init_params[] = { {0x17, 0x41, 0x00, 0}, /* select SH1 */ {0x1D, 0x40, 0x00, 0}, /* enable LCC output driver */ {0x52, 0xC0, 0x00, 0}, /* ADI recommended*/ - {0xFE, 0xA0, 0x00, 0}, /* set CSI-Tx slave address to 0xA0 */ + {0xFE, 0xA2, 0x00, 0}, /* set CSI-Tx slave address to 0x51 */ {0x59, 0x15, 0x00, 0}, /* GPO control */ }; +static struct reg_value adv7280_init_mipi_csi_top[] = { + {0xDE, 0x03, 0x00, 0x00}, /* dphy pwrdwn, Pwrdwn control DPHY_PWDN */ + {0xDC, 0x30, 0x00, 0x00}, /* enable mipi data/clk lanes */ + {0xD2, 0x00, 0x00, 0x00}, /* mipi data lane */ + {0xD1, 0x00, 0x00, 0x00}, /* mipi clk lane */ + {0x00, 0x00, 0x00, 0x00}, /* csi_tx_pwrdwn */ +}; + /*! Read one register from a ADV7280 i2c slave device. * @param *reg register in the device we wish to access. * @return 0 if success, an error code otherwise. */ -static inline int adv7280_read_reg(struct adv7280_priv *adv7280, u8 reg) +static inline int adv7280_read_reg(struct i2c_client *client, u8 reg) { int ret; - ret = i2c_smbus_read_byte_data(adv7280->client, reg); + ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) { - dev_dbg(&adv7280->client->dev, "%s:read reg error: reg=%2x\n", - __func__, reg); + dev_dbg(&client->dev, "read reg error: ret = %d\n", ret); } return ret; @@ -111,15 +122,14 @@ static inline int adv7280_read_reg(struct adv7280_priv *adv7280, u8 reg) * @param *reg register in the device we wish to access. * @return 0 if success, an error code otherwise. */ -static inline int adv7280_write_reg(struct adv7280_priv *adv7280, +static inline int adv7280_write_reg(struct i2c_client *client, u8 reg, u8 val) { int ret; - ret = i2c_smbus_write_byte_data(adv7280->client, reg, val); + ret = i2c_smbus_write_byte_data(client, reg, val); if (ret < 0) { - dev_dbg(&adv7280->client->dev, "%s:write reg error: reg=%2x\n", - __func__, reg); + dev_dbg(&client->dev, "write reg error: ret = %d", ret); } return ret; @@ -127,14 +137,14 @@ static inline int adv7280_write_reg(struct adv7280_priv *adv7280, /*! Write ADV7280 config paramater array */ -static int adv7280_config(struct adv7280_priv *adv7280, +static int adv7280_config(struct i2c_client *client, struct reg_value *config, int size) { int i, ret; for (i = 0; i < size; i++) { pr_debug("%s[%d]: reg = 0x%02x, value = 0x%02x\n", __func__, i, config[i].reg, config[i].value); - ret = adv7280_write_reg(adv7280, config[i].reg, + ret = adv7280_write_reg(client, config[i].reg, config[i].value | config[i].mask); if (ret < 0) { pr_err("%s: write error %x\n", __func__, ret); @@ -148,6 +158,64 @@ static int adv7280_config(struct adv7280_priv *adv7280, return 0; } +/*! Initial ADV7280 chipset configuration load recommended settings + */ +static int adv7280_default_config(struct adv7280_chipset *adv7280) +{ + int ret; + /* select main register map */ + ret = adv7280_write_reg(adv7280->client, ADV7280_ADI_CONTROL1, 0x00); + if (ret < 0) { + pr_err("%s: write error, select memory map %x\n", + __func__, ret); + goto err; + } + + /* perform a device reset */ + ret = adv7280_write_reg(adv7280->client, ADV7280_PM_REG, + ADV7280_PM_RESET_BIT); + if (ret < 0) { + pr_err("%s: write error, reset %x\n", __func__, ret); + goto err; + } + /* Wait 5ms reset time spec */ + msleep(5); + + /* Initial device configuration */ + ret = adv7280_config(adv7280->client, adv7280_init_params, + ARRAY_SIZE(adv7280_init_params)); + if (ret < 0) { + pr_err("%s: config device error %x\n", __func__, ret); + goto err; + } + + /* configure csi-tx slave address */ + if (adv7280->pdata->csi_tx_addr) { + /* shit left to pass 8bit address instead of 7bit address*/ + ret = adv7280_write_reg(adv7280->client, + ADV7280_CSI_TX_SLAVE_ADDR, + adv7280->pdata->csi_tx_addr << 1); + if (ret < 0) + goto err; + } + + /* select csi top reg address space*/ + ret = adv7280_write_reg(adv7280->client, ADV7280_ADI_CONTROL1, 0x40); + if (ret < 0) + goto err; + + ret = adv7280_config(adv7280->client_csi_tx, adv7280_init_mipi_csi_top, + ARRAY_SIZE(adv7280_init_mipi_csi_top)); + if (ret < 0) { + pr_err("%s: config device error csi_top %x\n", __func__, ret); + goto err; + } + + return 0; +err: + return ret; +} + /*! * ADV7280 I2C probe function. * Function set in i2c_driver struct. @@ -160,17 +228,33 @@ static int adv7280_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; - struct adv7280_priv *adv7280; + u8 csi_addr; + struct adv7280_chipset *adv7280; - adv7280 = kzalloc(sizeof(struct adv7280_priv), GFP_KERNEL); + adv7280 = kzalloc(sizeof(struct adv7280_chipset), GFP_KERNEL); if (!adv7280) return -ENOMEM; + i2c_set_clientdata(client, adv7280); + + adv7280->dev = &client->dev; adv7280->client = client; adv7280->pdata = client->dev.platform_data; - i2c_set_clientdata(client, adv7280); - ret = adv7280_read_reg(adv7280, ADV7280_IDENT); + if (adv7280->pdata->csi_tx_addr) { + csi_addr = adv7280->pdata->csi_tx_addr; + pr_debug("%s: csi_tx_addr = 0x%02x\n", __func__, csi_addr); + } else + csi_addr = ADV7280_CSI_TX_ADDR; + /* Attach a second dummy i2c_client for csi-top register access */ + adv7280->client_csi_tx = i2c_new_dummy(client->adapter, + csi_addr); + if (!adv7280->client_csi_tx) { + ret = -ENOMEM; + goto client_csi_tx_err; + } + + ret = adv7280_read_reg(adv7280->client, ADV7280_IDENT); if (ret < 0) { pr_err("%s: read id error %x\n", __func__, ret); goto err; @@ -183,42 +267,24 @@ static int adv7280_i2c_probe(struct i2c_client *client, } pr_info("%s: device found, rev_id 0x%02x\n", __func__, ret); - /* select main register map */ - ret = adv7280_write_reg(adv7280, ADV7280_ADI_CONTROL1, 0x00); - if (ret < 0) { - pr_err("%s: write error, select memory map %x\n", - __func__, ret); + /* default configuration */ + ret = adv7280_default_config(adv7280); + if (ret < 0) goto err; - } - - /* perform a device reset */ - ret = adv7280_write_reg(adv7280, ADV7280_PM_REG, - ADV7280_PM_RESET_BIT); - if (ret < 0) { - pr_err("%s: write error, reset %x\n", __func__, ret); - goto err; - } - /* Wait 5ms reset time spec */ - msleep(5); - - /* Initial device configuration */ - ret = adv7280_config(adv7280, adv7280_init_params, - ARRAY_SIZE(adv7280_init_params)); - if (ret < 0) { - pr_err("%s: config device error %x\n", __func__, ret); - goto err; - } return 0; err: + i2c_unregister_device(adv7280->client_csi_tx); +client_csi_tx_err: kfree(adv7280); return ret; } static int adv7280_i2c_remove(struct i2c_client *i2c_client) { - struct adv7280_priv *adv7280 = i2c_get_clientdata(i2c_client); + struct adv7280_chipset *adv7280 = i2c_get_clientdata(i2c_client); + i2c_unregister_device(adv7280->client_csi_tx); kfree(adv7280); return 0; } -- 2.39.5