summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/adv7481.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/adv7481.c')
-rw-r--r--drivers/media/i2c/adv7481.c1619
1 files changed, 1206 insertions, 413 deletions
diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c
index 359a860fdabb..b382a1d83d92 100644
--- a/drivers/media/i2c/adv7481.c
+++ b/drivers/media/i2c/adv7481.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -27,29 +27,68 @@
#include <media/v4l2-ctrls.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+
#include <media/adv7481.h>
#include <media/msm_ba.h>
#include "adv7481_reg.h"
+#include "msm_cci.h"
+#include "msm_camera_i2c.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
+
#define DRIVER_NAME "adv7481"
-#define I2C_RW_DELAY 100
-#define I2C_SW_RST_DELAY 10000
-#define GPIO_HW_DELAY_LOW 100000
-#define GPIO_HW_DELAY_HI 10000
+#define I2C_RW_DELAY 1
+#define I2C_SW_RST_DELAY 5000
+#define GPIO_HW_RST_DELAY_HI 10000
+#define GPIO_HW_RST_DELAY_LOW 10000
#define SDP_MIN_SLEEP 5000
#define SDP_MAX_SLEEP 6000
#define SDP_NUM_TRIES 30
#define LOCK_MIN_SLEEP 5000
#define LOCK_MAX_SLEEP 6000
-#define LOCK_NUM_TRIES 20
+#define LOCK_NUM_TRIES 200
+
+#define MAX_DEFAULT_WIDTH 1280
+#define MAX_DEFAULT_HEIGHT 720
+#define MAX_DEFAULT_FRAME_RATE 60
+#define MAX_DEFAULT_PIX_CLK_HZ 74240000
#define ONE_MHZ_TO_HZ 1000000
+#define I2C_BLOCK_WRITE_SIZE 1024
+
+enum adv7481_gpio_t {
+
+ CCI_I2C_SDA = 0,
+ CCI_I2C_SCL,
+
+ ADV7481_GPIO_RST,
+
+ ADV7481_GPIO_INT1,
+ ADV7481_GPIO_INT2,
+ ADV7481_GPIO_INT3,
+
+ ADV7481_GPIO_MAX,
+};
struct adv7481_state {
- /* Platform Data */
- struct adv7481_platform_data pdata;
+ struct device *dev;
+
+ /* VREG */
+ struct camera_vreg_t *cci_vreg;
+ struct regulator *cci_reg_ptr[MAX_REGULATOR];
+ int32_t regulator_count;
+
+ /* I2C */
+ struct msm_camera_i2c_client i2c_client;
+ u32 cci_master;
+ u32 i2c_slave_addr;
/* V4L2 Data */
struct v4l2_subdev sd;
@@ -63,19 +102,25 @@ struct adv7481_state {
struct workqueue_struct *work_queues;
struct mutex mutex;
- struct i2c_client *client;
- struct i2c_client *i2c_csi_txa;
- struct i2c_client *i2c_csi_txb;
- struct i2c_client *i2c_hdmi;
- struct i2c_client *i2c_edid;
- struct i2c_client *i2c_cp;
- struct i2c_client *i2c_sdp;
- struct i2c_client *i2c_rep;
+ uint8_t i2c_io_addr;
+ uint8_t i2c_csi_txa_addr;
+ uint8_t i2c_csi_txb_addr;
+ uint8_t i2c_hdmi_addr;
+ uint8_t i2c_edid_addr;
+ uint8_t i2c_cp_addr;
+ uint8_t i2c_sdp_addr;
+ uint8_t i2c_rep_addr;
+ uint8_t i2c_cbus_addr;
/* device status and Flags */
int irq;
int device_num;
int powerup;
+ int cec_detected;
+ int clocks_requested;
+
+ /* GPIOs */
+ struct gpio gpio_array[ADV7481_GPIO_MAX];
/* routing configuration data */
int csia_src;
@@ -196,6 +241,9 @@ const uint8_t adv7481_default_edid_data[] = {
#define ADV7481_EDID_SIZE ARRAY_SIZE(adv7481_default_edid_data)
+static u32 adv7481_inp_to_ba(u32 adv_input);
+static bool adv7481_is_timing_locked(struct adv7481_state *state);
+
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{
return &(container_of(ctrl->handler,
@@ -208,56 +256,151 @@ static inline struct adv7481_state *to_state(struct v4l2_subdev *sd)
}
/* I2C Rd/Rw Functions */
-static int adv7481_wr_byte(struct i2c_client *i2c_client, unsigned int reg,
- unsigned int value)
+static int32_t adv7481_cci_i2c_write(struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, uint16_t *data,
+ enum msm_camera_i2c_data_type data_type)
{
- int ret;
+ return i2c_client->i2c_func_tbl->i2c_write(i2c_client, reg,
+ *data, data_type);
+}
- ret = i2c_smbus_write_byte_data(i2c_client, reg & 0xFF, value);
- usleep_range(I2C_RW_DELAY, 2*I2C_RW_DELAY);
+static int32_t adv7481_cci_i2c_write_seq(
+ struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, const uint8_t *data, uint32_t size)
+{
+ return i2c_client->i2c_func_tbl->i2c_write_seq(i2c_client, reg,
+ (uint8_t *)data, size);
+}
+
+static int32_t adv7481_cci_i2c_read(struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, uint16_t *data,
+ enum msm_camera_i2c_data_type data_type)
+{
+ return i2c_client->i2c_func_tbl->i2c_read(i2c_client, reg,
+ data, data_type);
+}
+
+static int32_t adv7481_wr_byte(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg, uint8_t data)
+{
+ uint16_t write_data = data;
+ int ret = 0;
+
+ c_i2c_client->cci_client->sid = sid;
+
+ ret = adv7481_cci_i2c_write(c_i2c_client, reg, &write_data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ if (ret < 0)
+ pr_err("Error %d writing cci i2c\n", ret);
return ret;
}
-static int adv7481_rd_byte(struct i2c_client *i2c_client, unsigned int reg)
+static int32_t adv7481_wr_block(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg, const uint8_t *data, uint32_t size)
{
- int ret;
+ int ret = 0;
- ret = i2c_smbus_read_byte_data(i2c_client, reg & 0xFF);
- usleep_range(I2C_RW_DELAY, 2*I2C_RW_DELAY);
+ c_i2c_client->cci_client->sid = sid;
+
+ ret = adv7481_cci_i2c_write_seq(c_i2c_client, reg, data, size);
+ if (ret < 0)
+ pr_err("Error %d writing cci i2c block data\n", ret);
return ret;
}
+static uint8_t adv7481_rd_byte(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg)
+{
+ uint16_t data = 0;
+ int ret = 0;
+
+ c_i2c_client->cci_client->sid = sid;
+ ret = adv7481_cci_i2c_read(c_i2c_client, reg, &data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ if (ret < 0) {
+ pr_err("Error %d reading cci i2c\n", ret);
+ return ret;
+ }
+
+ return (uint8_t)(data & 0xFF);
+}
+
+static uint16_t adv7481_rd_word(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg)
+{
+ uint16_t data = 0;
+ int ret;
+
+ c_i2c_client->cci_client->sid = sid;
+ ret = adv7481_cci_i2c_read(c_i2c_client, reg, &data,
+ MSM_CAMERA_I2C_WORD_DATA);
+ if (ret < 0) {
+ pr_err("Error %d reading cci i2c\n", ret);
+ return ret;
+ }
+
+ return data;
+}
+
static int adv7481_set_irq(struct adv7481_state *state)
{
int ret = 0;
- ret = adv7481_wr_byte(state->client, IO_REG_PAD_CTRL_1_ADDR,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PAD_CTRL_1_ADDR,
ADV_REG_SETFIELD(1, IO_PDN_INT2) |
ADV_REG_SETFIELD(1, IO_PDN_INT3) |
ADV_REG_SETFIELD(1, IO_INV_LLC) |
ADV_REG_SETFIELD(AD_MID_DRIVE_STRNGTH, IO_DRV_LLC_PAD));
- ret |= adv7481_wr_byte(state->client, IO_REG_INT1_CONF_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_INT1_CONF_ADDR,
ADV_REG_SETFIELD(AD_ACTIVE_UNTIL_CLR,
IO_INTRQ_DUR_SEL) |
ADV_REG_SETFIELD(AD_OP_DRIVE_LOW, IO_INTRQ_OP_SEL));
- ret |= adv7481_wr_byte(state->client, IO_REG_INT2_CONF_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_INT2_CONF_ADDR,
ADV_REG_SETFIELD(1, IO_CP_LOCK_UNLOCK_EDGE_SEL));
- ret |= adv7481_wr_byte(state->client, IO_REG_DATAPATH_INT_MASKB_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_MASKB_ADDR,
ADV_REG_SETFIELD(1, IO_CP_LOCK_CP_MB1) |
ADV_REG_SETFIELD(1, IO_CP_UNLOCK_CP_MB1) |
ADV_REG_SETFIELD(1, IO_VMUTE_REQUEST_HDMI_MB1) |
ADV_REG_SETFIELD(1, IO_INT_SD_MB1));
- /* Set hpa */
- ret |= adv7481_wr_byte(state->client, IO_HDMI_LVL_INT_MASKB_3_ADDR,
- ADV_REG_SETFIELD(1, IO_CABLE_DET_A_MB1));
+ /* Set cable detect */
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_MASKB_3_ADDR,
+ ADV_REG_SETFIELD(1, IO_CABLE_DET_A_MB1) |
+ ADV_REG_SETFIELD(1, IO_V_LOCKED_MB1) |
+ ADV_REG_SETFIELD(1, IO_DE_REGEN_LCK_MB1));
+
+ /* set CVBS lock/unlock interrupts */
+ /* Select SDP MAP 1 */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x20);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_LOCK_UNLOCK_MASK_ADDR, 0x03);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
if (ret)
pr_err("%s: Failed %d to setup interrupt regs\n",
__func__, ret);
- else
- enable_irq(state->irq);
+
+ return ret;
+}
+
+static int adv7481_reset_irq(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ disable_irq(state->irq);
+
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_MASKB_ADDR, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_MASKB_3_ADDR, 0x00);
return ret;
}
@@ -267,27 +410,42 @@ static int adv7481_set_edid(struct adv7481_state *state)
int i;
int ret = 0;
uint8_t edid_state;
+ uint32_t data_left = 0;
+ uint32_t start_pos;
/* Enable Manual Control of EDID on Port A */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x74, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x74,
+ 0x01);
/* Disable Auto Enable of EDID */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x7A, 0x08);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x7A,
+ 0x08);
/* Set Primary EDID Size to 256 Bytes */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x70, 0x20);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x70,
+ 0x20);
/*
* Readback EDID enable state after a combination of manual
* and automatic functions
*/
- edid_state = adv7481_rd_byte(state->i2c_rep,
+ edid_state = adv7481_rd_byte(&state->i2c_client, state->i2c_rep_addr,
HDMI_REG_RO_EDID_DEBUG_2_ADDR);
pr_debug("%s: Readback EDID enable state: 0x%x\n", __func__,
edid_state);
- for (i = 0; i < ADV7481_EDID_SIZE; i++) {
- ret |= adv7481_wr_byte(state->i2c_edid, i,
- adv7481_default_edid_data[i]);
- }
+ for (i = 0; i < ADV7481_EDID_SIZE && !ret; i += I2C_BLOCK_WRITE_SIZE)
+ ret |= adv7481_wr_block(&state->i2c_client,
+ state->i2c_edid_addr,
+ i, &adv7481_default_edid_data[i],
+ I2C_BLOCK_WRITE_SIZE);
+
+ data_left = ADV7481_EDID_SIZE % I2C_BLOCK_WRITE_SIZE;
+ start_pos = ADV7481_EDID_SIZE - data_left;
+ if (data_left && !ret)
+ ret |= adv7481_wr_block(&state->i2c_client,
+ state->i2c_edid_addr,
+ start_pos,
+ &adv7481_default_edid_data[start_pos],
+ data_left);
return ret;
}
@@ -301,47 +459,232 @@ static irqreturn_t adv7481_irq(int irq, void *dev)
return IRQ_HANDLED;
}
+/* Request CCI clocks for adv7481 register access */
+static int adv7481_request_cci_clks(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ if (state->clocks_requested == TRUE)
+ return ret;
+
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_INIT);
+ if (ret < 0)
+ pr_err("%s - cci_init failed\n", __func__);
+ else
+ state->clocks_requested = TRUE;
+
+ /* enable camera voltage regulator */
+ ret = msm_camera_enable_vreg(state->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0)
+ pr_err("%s:cci enable_vreg failed\n", __func__);
+ else
+ pr_debug("%s - VREG Initialized...\n", __func__);
+
+ return ret;
+}
+
+static int adv7481_release_cci_clks(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ if (state->clocks_requested == FALSE)
+ return ret;
+
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_RELEASE);
+ if (ret < 0)
+ pr_err("%s - cci_release failed\n", __func__);
+ else
+ state->clocks_requested = FALSE;
+
+ /* disable camera voltage regulator */
+ ret = msm_camera_enable_vreg(state->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 0);
+ if (ret < 0)
+ pr_err("%s:cci disable vreg failed\n", __func__);
+ else
+ pr_debug("%s - VREG Initialized...\n", __func__);
+
+ return ret;
+}
+
static void adv7481_irq_delay_work(struct work_struct *work)
{
struct adv7481_state *state;
- uint8_t status;
+ uint8_t int_raw_status;
+ uint8_t int_status;
+ uint8_t raw_status;
state = container_of(work, struct adv7481_state,
irq_delayed_work.work);
mutex_lock(&state->mutex);
- /* workaround for irq trigger */
- status = adv7481_rd_byte(state->client,
+ /* Read raw irq status register */
+ int_raw_status = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_INT_RAW_STATUS_ADDR);
pr_debug("%s: dev: %d got int raw status: 0x%x\n", __func__,
- state->device_num, status);
+ state->device_num, int_raw_status);
+ state->cec_detected = ADV_REG_GETFIELD(int_raw_status, IO_INT_CEC_ST);
+
+ while (int_raw_status) {
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INTRQ1_RAW)) {
+ int lock_status = -1;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
+
+ pr_debug("%s: dev: %d got intrq1_raw\n", __func__,
+ state->device_num);
+ int_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_STATUS_ADDR);
+
+ raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_RAW_STATUS_ADDR);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_CLEAR_ADDR, int_status);
+
+ pr_debug("%s: dev: %d got datapath int status: 0x%x\n",
+ __func__, state->device_num, int_status);
+
+ pr_debug("%s: dev: %d got datapath raw status: 0x%x\n",
+ __func__, state->device_num, raw_status);
+
+ if (ADV_REG_GETFIELD(int_status, IO_INT_SD_ST) &&
+ ADV_REG_GETFIELD(raw_status, IO_INT_SD_RAW)) {
+ uint8_t sdp_sts = 0;
+
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x01);
+ sdp_sts = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr,
+ SDP_RO_MAIN_STATUS1_ADDR);
+ pr_debug("%s: dev: %d got sdp status: 0x%x\n",
+ __func__, state->device_num, sdp_sts);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x00);
+ if (ADV_REG_GETFIELD(sdp_sts,
+ SDP_RO_MAIN_IN_LOCK)) {
+ lock_status = 0;
+ pr_debug(
+ "%s: set lock_status SDP_IN_LOCK:0x%x\n",
+ __func__, lock_status);
+ } else {
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status SDP_UNLOCK:0x%x\n",
+ __func__, lock_status);
+ }
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x20);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr,
+ SDP_RW_LOCK_UNLOCK_CLR_ADDR, sdp_sts);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x00);
+ } else {
+ if (ADV_REG_GETFIELD(int_status,
+ IO_CP_LOCK_CP_ST) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_CP_LOCK_CP_RAW)) {
+ lock_status = 0;
+ pr_debug(
+ "%s: set lock_status IO_CP_LOCK_CP_RAW:0x%x\n",
+ __func__, lock_status);
+ }
+ if (ADV_REG_GETFIELD(int_status,
+ IO_CP_UNLOCK_CP_ST) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_CP_UNLOCK_CP_RAW)) {
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status IO_CP_UNLOCK_CP_RAW:0x%x\n",
+ __func__, lock_status);
+ }
+ }
+
+ if (lock_status >= 0) {
+ ptr[0] = adv7481_inp_to_ba(state->mode);
+ ptr[1] = lock_status;
+ event.type = lock_status ?
+ V4L2_EVENT_MSM_BA_SIGNAL_LOST_LOCK :
+ V4L2_EVENT_MSM_BA_SIGNAL_IN_LOCK;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ }
- status = adv7481_rd_byte(state->client,
- IO_REG_DATAPATH_INT_STATUS_ADDR);
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INT_HDMI_ST)) {
+ int cable_detected = 0;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
- pr_debug("%s: dev: %d got datapath int status: 0x%x\n", __func__,
- state->device_num, status);
+ ptr[0] = adv7481_inp_to_ba(state->mode);
- adv7481_wr_byte(state->client,
- IO_REG_DATAPATH_INT_CLEAR_ADDR, status);
+ pr_debug("%s: dev: %d got int_hdmi_st\n", __func__,
+ state->device_num);
- status = adv7481_rd_byte(state->client,
- IO_REG_DATAPATH_RAW_STATUS_ADDR);
+ int_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_HDMI_LVL_INT_STATUS_3_ADDR);
- pr_debug("%s: dev: %d got datapath rawstatus: 0x%x\n", __func__,
- state->device_num, status);
+ raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- status = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_INT_STATUS_3_ADDR);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_CLEAR_3_ADDR, int_status);
- pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n", __func__,
- state->device_num, status);
+ pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n",
+ __func__, state->device_num, int_status);
+ pr_debug("%s: dev: %d got hdmi lvl raw status 3: 0x%x\n",
+ __func__, state->device_num, raw_status);
- adv7481_wr_byte(state->client,
- IO_HDMI_LVL_INT_CLEAR_3_ADDR, status);
+ if (ADV_REG_GETFIELD(int_status, IO_CABLE_DET_A_ST)) {
+ cable_detected = ADV_REG_GETFIELD(raw_status,
+ IO_CABLE_DET_A_RAW);
+ pr_debug("%s: set cable_detected: 0x%x\n",
+ __func__, cable_detected);
+ ptr[1] = cable_detected;
+ event.type = V4L2_EVENT_MSM_BA_CABLE_DETECT;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ /* Assumption is that vertical sync int
+ * is the last one to come
+ */
+ if (ADV_REG_GETFIELD(int_status, IO_V_LOCKED_ST)) {
+ if (ADV_REG_GETFIELD(raw_status,
+ IO_TMDSPLL_LCK_A_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_V_LOCKED_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_DE_REGEN_LCK_RAW)) {
+ pr_debug("%s: port settings changed\n",
+ __func__);
+ event.type =
+ V4L2_EVENT_MSM_BA_PORT_SETTINGS_CHANGED;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ }
+ }
+ int_raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_INT_RAW_STATUS_ADDR);
+ }
mutex_unlock(&state->mutex);
}
@@ -350,110 +693,100 @@ static int adv7481_cec_wakeup(struct adv7481_state *state, bool enable)
uint8_t val;
int ret = 0;
- val = adv7481_rd_byte(state->client,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR);
val = ADV_REG_GETFIELD(val, IO_PROG_XTAL_FREQ_HIGH);
if (enable) {
/* CEC wake up enabled in power-down mode */
val |= ADV_REG_SETFIELD(1, IO_CTRL_CEC_WAKE_UP_PWRDN2B) |
ADV_REG_SETFIELD(0, IO_CTRL_CEC_WAKE_UP_PWRDNB);
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR, val);
} else {
/* CEC wake up disabled in power-down mode */
val |= ADV_REG_SETFIELD(0, IO_CTRL_CEC_WAKE_UP_PWRDN2B) |
ADV_REG_SETFIELD(1, IO_CTRL_CEC_WAKE_UP_PWRDNB);
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR, val);
}
return ret;
}
/* Initialize adv7481 I2C Settings */
-static int adv7481_dev_init(struct adv7481_state *state,
- struct i2c_client *client)
+static int adv7481_dev_init(struct adv7481_state *state)
{
+ uint16_t chip_rev_id;
int ret;
mutex_lock(&state->mutex);
/* Soft reset */
- ret = adv7481_wr_byte(state->client,
- IO_REG_MAIN_RST_ADDR, IO_REG_MAIN_RST_VALUE);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_MAIN_RST_ADDR, IO_REG_MAIN_RST_VALUE);
/* Delay required following I2C reset and I2C transactions */
- usleep_range(I2C_SW_RST_DELAY, I2C_SW_RST_DELAY+1000);
+ udelay(I2C_SW_RST_DELAY);
+
+ chip_rev_id = adv7481_rd_word(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CHIP_REV_ID_1_ADDR);
+ pr_debug("%s: ADV7481 chip rev id: 0x%x", __func__, chip_rev_id);
/* Disable CEC wake up in power-down mode */
ret |= adv7481_cec_wakeup(state, 0);
/* Setting Vid_Std to 720x480p60 */
- ret |= adv7481_wr_byte(state->client,
- IO_REG_CP_VID_STD_ADDR, 0x4A);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CP_VID_STD_ADDR, 0x4A);
/* Configure I2C Maps and I2C Communication Settings */
/* io_reg_f2 I2C Auto Increment */
- ret |= adv7481_wr_byte(state->client, IO_REG_I2C_CFG_ADDR,
- IO_REG_I2C_AUTOINC_EN_REG_VALUE);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_I2C_CFG_ADDR, IO_REG_I2C_AUTOINC_EN_REG_VALUE);
/* DPLL Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_DPLL_ADDR,
- IO_REG_DPLL_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DPLL_ADDR, IO_REG_DPLL_SADDR);
/* CP Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CP_ADDR,
- IO_REG_CP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CP_ADDR, IO_REG_CP_SADDR);
/* HDMI RX Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_ADDR,
- IO_REG_HDMI_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_ADDR, IO_REG_HDMI_SADDR);
/* EDID Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_EDID_ADDR,
- IO_REG_EDID_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_EDID_ADDR, IO_REG_EDID_SADDR);
/* HDMI RX Repeater Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_REP_ADDR,
- IO_REG_HDMI_REP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_REP_ADDR, IO_REG_HDMI_REP_SADDR);
/* HDMI RX Info-frame Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_INF_ADDR,
- IO_REG_HDMI_INF_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_INF_ADDR, IO_REG_HDMI_INF_SADDR);
/* CBUS Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CBUS_ADDR,
- IO_REG_CBUS_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CBUS_ADDR, IO_REG_CBUS_SADDR);
/* CEC Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CEC_ADDR,
- IO_REG_CEC_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CEC_ADDR, IO_REG_CEC_SADDR);
/* SDP Main Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_SDP_ADDR,
- IO_REG_SDP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_SDP_ADDR, IO_REG_SDP_SADDR);
/* CSI-TXB Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_TXB_ADDR,
- IO_REG_CSI_TXB_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_TXB_ADDR, IO_REG_CSI_TXB_SADDR);
/* CSI-TXA Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_TXA_ADDR,
- IO_REG_CSI_TXA_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_TXA_ADDR, IO_REG_CSI_TXA_SADDR);
if (ret) {
pr_err("%s: Failed dev init %d\n", __func__, ret);
goto err_exit;
}
/* Configure i2c clients */
- state->i2c_csi_txa = i2c_new_dummy(client->adapter,
- IO_REG_CSI_TXA_SADDR >> 1);
- state->i2c_csi_txb = i2c_new_dummy(client->adapter,
- IO_REG_CSI_TXB_SADDR >> 1);
- state->i2c_cp = i2c_new_dummy(client->adapter,
- IO_REG_CP_SADDR >> 1);
- state->i2c_hdmi = i2c_new_dummy(client->adapter,
- IO_REG_HDMI_SADDR >> 1);
- state->i2c_edid = i2c_new_dummy(client->adapter,
- IO_REG_EDID_SADDR >> 1);
- state->i2c_sdp = i2c_new_dummy(client->adapter,
- IO_REG_SDP_SADDR >> 1);
- state->i2c_rep = i2c_new_dummy(client->adapter,
- IO_REG_HDMI_REP_SADDR >> 1);
-
- if (!state->i2c_csi_txa || !state->i2c_csi_txb || !state->i2c_cp ||
- !state->i2c_sdp || !state->i2c_hdmi || !state->i2c_edid ||
- !state->i2c_rep) {
- pr_err("%s: Additional I2C Client Fail\n", __func__);
- ret = -EFAULT;
- goto err_exit;
- }
+ state->i2c_csi_txa_addr = IO_REG_CSI_TXA_SADDR >> 1;
+ state->i2c_csi_txb_addr = IO_REG_CSI_TXB_SADDR >> 1;
+ state->i2c_cp_addr = IO_REG_CP_SADDR >> 1;
+ state->i2c_hdmi_addr = IO_REG_HDMI_SADDR >> 1;
+ state->i2c_edid_addr = IO_REG_EDID_SADDR >> 1;
+ state->i2c_sdp_addr = IO_REG_SDP_SADDR >> 1;
+ state->i2c_rep_addr = IO_REG_HDMI_REP_SADDR >> 1;
+ state->i2c_cbus_addr = IO_REG_CBUS_SADDR >> 1;
ret = adv7481_set_edid(state);
ret |= adv7481_set_irq(state);
@@ -465,28 +798,25 @@ err_exit:
}
/* Initialize adv7481 hardware */
-static int adv7481_hw_init(struct adv7481_platform_data *pdata,
- struct adv7481_state *state)
+static int adv7481_hw_init(struct adv7481_state *state)
{
int ret = 0;
- if (!pdata) {
- pr_err("%s: PDATA is NULL\n", __func__);
- return -EFAULT;
- }
-
mutex_lock(&state->mutex);
- if (gpio_is_valid(pdata->rstb_gpio)) {
- ret = gpio_request(pdata->rstb_gpio, "rstb_gpio");
- if (ret) {
- pr_err("%s: Request GPIO Fail %d\n", __func__, ret);
- goto err_exit;
- }
- ret = gpio_direction_output(pdata->rstb_gpio, 0);
- usleep_range(GPIO_HW_DELAY_LOW, GPIO_HW_DELAY_LOW+1000);
- ret = gpio_direction_output(pdata->rstb_gpio, 1);
- usleep_range(GPIO_HW_DELAY_HI, GPIO_HW_DELAY_HI+1000);
+ /* Bring ADV7481 out of reset */
+ ret = gpio_request_array(&state->gpio_array[ADV7481_GPIO_RST], 1);
+ if (ret < 0) {
+ pr_err("%s: Failed to request reset GPIO %d\n", __func__, ret);
+ goto err_exit;
+ }
+ if (gpio_is_valid(state->gpio_array[ADV7481_GPIO_RST].gpio)) {
+ ret |= gpio_direction_output(
+ state->gpio_array[ADV7481_GPIO_RST].gpio, 0);
+ udelay(GPIO_HW_RST_DELAY_LOW);
+ ret |= gpio_direction_output(
+ state->gpio_array[ADV7481_GPIO_RST].gpio, 1);
+ udelay(GPIO_HW_RST_DELAY_HI);
if (ret) {
pr_err("%s: Set GPIO Fail %d\n", __func__, ret);
goto err_exit;
@@ -494,22 +824,21 @@ static int adv7481_hw_init(struct adv7481_platform_data *pdata,
}
/* Only setup IRQ1 for now... */
- if (gpio_is_valid(pdata->irq1_gpio)) {
- ret = gpio_request(pdata->irq1_gpio, "irq_gpio");
- if (ret) {
- pr_err("%s: Failed to request irq_gpio %d\n",
- __func__, ret);
- goto err_exit;
- }
-
- ret = gpio_direction_input(pdata->irq1_gpio);
+ ret = gpio_request_array(&state->gpio_array[ADV7481_GPIO_INT1], 1);
+ if (ret < 0) {
+ pr_err("%s: Failed to request irq_gpio %d\n", __func__, ret);
+ goto err_exit;
+ }
+ if (gpio_is_valid(state->gpio_array[ADV7481_GPIO_INT1].gpio)) {
+ ret |= gpio_direction_input(
+ state->gpio_array[ADV7481_GPIO_INT1].gpio);
if (ret) {
pr_err("%s: Failed gpio_direction irq %d\n",
__func__, ret);
goto err_exit;
}
-
- state->irq = gpio_to_irq(pdata->irq1_gpio);
+ state->irq = gpio_to_irq(
+ state->gpio_array[ADV7481_GPIO_INT1].gpio);
if (state->irq) {
ret = request_irq(state->irq, adv7481_irq,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
@@ -519,18 +848,16 @@ static int adv7481_hw_init(struct adv7481_platform_data *pdata,
__func__, ret);
goto err_exit;
}
+ /* disable irq until chip interrupts are programmed */
+ disable_irq(state->irq);
} else {
pr_err("%s: Failed gpio_to_irq %d\n", __func__, ret);
ret = -EINVAL;
goto err_exit;
}
-
- /* disable irq until chip interrupts are programmed */
- disable_irq(state->irq);
-
- INIT_DELAYED_WORK(&state->irq_delayed_work,
- adv7481_irq_delay_work);
}
+ INIT_DELAYED_WORK(&state->irq_delayed_work,
+ adv7481_irq_delay_work);
err_exit:
mutex_unlock(&state->mutex);
@@ -548,31 +875,40 @@ static int adv7481_s_ctrl(struct v4l2_ctrl *ctrl)
pr_debug("Enter %s: id = 0x%x\n", __func__, ctrl->id);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_BRIGHTNESS, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_BRIGHTNESS, ctrl->val);
break;
case V4L2_CID_CONTRAST:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_CONTRAST, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_CONTRAST, ctrl->val);
break;
case V4L2_CID_SATURATION:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_SATURATION, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_SATURATION, ctrl->val);
break;
case V4L2_CID_HUE:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client, CP_REG_HUE, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_HUE, ctrl->val);
break;
default:
break;
@@ -611,6 +947,108 @@ static int adv7481_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
+static int adv7481_set_cec_logical_addr(struct adv7481_state *state, int *la)
+{
+ int rc = 0;
+ uint8_t val;
+
+ if (!la) {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ return -EINVAL;
+ }
+
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOG_ADDR_MASK_ADDR);
+ if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK0)) {
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR);
+ val = ADV_REG_RSTFIELD(val, CEC_REG_LOGICAL_ADDRESS0);
+ val |= ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS0);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR, val);
+ } else if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK1)) {
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR);
+ val = ADV_REG_RSTFIELD(val, CEC_REG_LOGICAL_ADDRESS1);
+ val |= ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS1);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR, val);
+ } else if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK2)) {
+ val = ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS2);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS2_ADDR, val);
+ } else {
+ pr_err("No cec logical address mask set\n");
+ }
+
+ return rc;
+}
+
+static int adv7481_cec_powerup(struct adv7481_state *state, int *powerup)
+{
+ int rc = 0;
+ uint8_t val = 0;
+
+ if (!powerup) {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: set power %d\n", __func__, *powerup);
+
+ val = ADV_REG_SETFIELD(*powerup, CEC_REG_CEC_POWER_UP);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_CEC_POWER_UP_ADDR, val);
+
+ return rc;
+}
+
+static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct adv7481_state *state = to_state(sd);
+ int *ret_val = arg;
+ long ret = 0;
+ int param = 0;
+
+ pr_debug("Enter %s with command: 0x%x", __func__, cmd);
+
+ if (!sd)
+ return -EINVAL;
+
+ switch (cmd) {
+ case VIDIOC_HDMI_RX_CEC_S_LOGICAL:
+ ret = adv7481_set_cec_logical_addr(state, arg);
+ break;
+ case VIDIOC_HDMI_RX_CEC_CLEAR_LOGICAL:
+ ret = adv7481_set_cec_logical_addr(state, &param);
+ break;
+ case VIDIOC_HDMI_RX_CEC_G_PHYSICAL:
+ if (ret_val) {
+ *ret_val = 0;
+ } else {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ ret = -EINVAL;
+ }
+ break;
+ case VIDIOC_HDMI_RX_CEC_G_CONNECTED:
+ if (ret_val) {
+ *ret_val = state->cec_detected;
+ } else {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ ret = -EINVAL;
+ }
+ break;
+ case VIDIOC_HDMI_RX_CEC_S_ENABLE:
+ ret = adv7481_cec_powerup(state, arg);
+ break;
+ default:
+ pr_err("Not a typewriter! Command: 0x%x", cmd);
+ ret = -ENOTTY;
+ break;
+ }
+ return ret;
+}
+
static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
{
int ret = 0;
@@ -620,18 +1058,22 @@ static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
if (sd_standard == NULL)
return -EINVAL;
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
do {
- sdp_stat = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
+ sdp_stat = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
usleep_range(SDP_MIN_SLEEP, SDP_MAX_SLEEP);
timeout++;
- sdp_stat2 = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
+ sdp_stat2 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
} while ((sdp_stat != sdp_stat2) && (timeout < SDP_NUM_TRIES));
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
if (sdp_stat != sdp_stat2) {
- pr_err("%s(%d), adv7481 SDP status unstable: 1\n",
- __func__, __LINE__);
+ pr_err("%s, adv7481 SDP status unstable: 1\n", __func__);
return -ETIMEDOUT;
}
@@ -681,22 +1123,50 @@ static int adv7481_set_cvbs_mode(struct adv7481_state *state)
pr_debug("Enter %s\n", __func__);
state->mode = ADV7481_IP_CVBS_1;
/* cvbs video settings ntsc etc */
- ret = adv7481_wr_byte(state->client, 0x00, 0x30);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0f, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x00, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x03, 0x42);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x04, 0x07);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x13, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x17, 0x41);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x31, 0x12);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x52, 0xcd);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0e, 0xff);
- val = adv7481_rd_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x00, 0x30);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x0e, 0xff);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x0f, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x52, 0xcd);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x00, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x9c, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x9c, 0xff);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x80, 0x51);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x81, 0x51);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x82, 0x68);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x03, 0x42);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x04, 0x07);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x13, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x17, 0x41);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x31, 0x12);
+
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR);
/* Output of SD core routed to MIPI CSI 4-lane Tx */
- val |= ADV_REG_SETFIELD(0x10, IO_CTRL_CSI4_IN_SEL);
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR, val);
- /* Enable autodetect */
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0e, 0x81);
+ val = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0x2, IO_CTRL_CSI4_IN_SEL);
+
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR, val);
return ret;
}
@@ -713,69 +1183,101 @@ static int adv7481_set_hdmi_mode(struct adv7481_state *state)
* YUV 422 out via TxA CSI: 4-Lane
*/
/* Disable chip powerdown & Enable HDMI Rx block */
- temp = adv7481_rd_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR);
val = ADV_REG_SETFIELD(1, IO_CTRL_RX_EN) |
ADV_REG_SETFIELD(0, IO_CTRL_RX_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_XTAL_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_CORE_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_MASTER_PWDN);
- ret = adv7481_wr_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR, val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR, val);
/* SDR mode */
- ret |= adv7481_wr_byte(state->client, 0x11, 0x48);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x11, 0x48);
/* Set CP core to YUV out */
- ret |= adv7481_wr_byte(state->client, 0x04, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x04, 0x00);
/* Set CP core to SDR 422 */
- ret |= adv7481_wr_byte(state->client, 0x12, 0xF2);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x12, 0xF2);
/* Saturate both Luma and Chroma values to 254 */
- ret |= adv7481_wr_byte(state->client, 0x17, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x17, 0x80);
/* Set CP core to enable AV codes */
- ret |= adv7481_wr_byte(state->client, 0x03, 0x86);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x03, 0x86);
/* ADI RS CP Core: */
- ret |= adv7481_wr_byte(state->i2c_cp, 0x7C, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_cp_addr,
+ 0x7C, 0x00);
/* Set CP core Phase Adjustment */
- ret |= adv7481_wr_byte(state->client, 0x0C, 0xE0);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x0C, 0xE0);
/* LLC/PIX/SPI PINS TRISTATED AUD Outputs Enabled */
- ret |= adv7481_wr_byte(state->client, IO_PAD_CTRLS_ADDR, 0xDD);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_PAD_CTRLS_ADDR, 0xDD);
/* Enable Tx A CSI 4-Lane & data from CP core */
val = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR,
- val);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR, val);
/* start to configure HDMI Rx once io-map is configured */
/* Enable HDCP 1.1 */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x40, 0x83);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr,
+ 0x40, 0x83);
/* Foreground Channel = A */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x00, 0x08);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x00, 0x08);
/* ADI Required Write */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x98, 0xFF);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x99, 0xA3);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9A, 0x00);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9B, 0x0A);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9D, 0x40);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xCB, 0x09);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x98, 0xFF);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x99, 0xA3);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9A, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9B, 0x0A);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9D, 0x40);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xCB, 0x09);
/* ADI RS */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3D, 0x10);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3E, 0x7B);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3F, 0x5E);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x4E, 0xFE);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x4F, 0x18);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x57, 0xA3);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x58, 0x04);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x85, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3D, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3E, 0x7B);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3F, 0x5E);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x4E, 0xFE);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x4F, 0x18);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x57, 0xA3);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x58, 0x04);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x85, 0x10);
/* Enable All Terminations */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x83, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x83, 0x00);
/* ADI RS */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xA3, 0x01);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xBE, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xA3, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xBE, 0x00);
/* HPA Manual Enable */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x6C, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x6C, 0x01);
/* HPA Asserted */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xF8, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xF8, 0x01);
/* Audio Mute Speed Set to Fastest (Smallest Step Size) */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x0F, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x0F, 0x00);
return ret;
}
@@ -860,7 +1362,7 @@ static int adv7481_set_ip_mode(struct adv7481_state *state, int input)
}
static int adv7481_set_op_src(struct adv7481_state *state,
- int output, int input)
+ int output, int input)
{
int ret = 0;
int temp = 0;
@@ -897,10 +1399,11 @@ static int adv7481_set_op_src(struct adv7481_state *state,
default:
ret = -EINVAL;
}
- temp = adv7481_rd_byte(state->client,
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DOWN_CTRL_ADDR);
temp |= val;
- adv7481_wr_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR, temp);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR, temp);
state->csia_src = input;
break;
case ADV7481_OP_CSIB:
@@ -915,11 +1418,11 @@ static int adv7481_set_op_src(struct adv7481_state *state,
return ret;
}
-static u32 ba_inp_to_adv7481(u32 input)
+static u32 ba_inp_to_adv7481(u32 ba_input)
{
u32 adv_input = ADV7481_IP_HDMI;
- switch (input) {
+ switch (ba_input) {
case BA_IP_CVBS_0:
adv_input = ADV7481_IP_CVBS_1;
break;
@@ -954,6 +1457,42 @@ static u32 ba_inp_to_adv7481(u32 input)
return adv_input;
}
+static u32 adv7481_inp_to_ba(u32 adv_input)
+{
+ u32 ba_input = BA_IP_HDMI_1;
+
+ switch (adv_input) {
+ case ADV7481_IP_CVBS_1:
+ ba_input = BA_IP_CVBS_0;
+ break;
+ case ADV7481_IP_CVBS_2:
+ ba_input = BA_IP_CVBS_1;
+ break;
+ case ADV7481_IP_CVBS_3:
+ ba_input = BA_IP_CVBS_2;
+ break;
+ case ADV7481_IP_CVBS_4:
+ ba_input = BA_IP_CVBS_3;
+ break;
+ case ADV7481_IP_CVBS_5:
+ ba_input = BA_IP_CVBS_4;
+ break;
+ case ADV7481_IP_CVBS_6:
+ ba_input = BA_IP_CVBS_5;
+ break;
+ case ADV7481_IP_HDMI:
+ ba_input = BA_IP_HDMI_1;
+ break;
+ case ADV7481_IP_TTL:
+ ba_input = BA_IP_TTL;
+ break;
+ default:
+ ba_input = BA_IP_HDMI_1;
+ break;
+ }
+ return ba_input;
+}
+
static int adv7481_s_routing(struct v4l2_subdev *sd, u32 input,
u32 output, u32 config)
{
@@ -971,14 +1510,11 @@ static int adv7481_s_routing(struct v4l2_subdev *sd, u32 input,
goto unlock_exit;
}
- if (state->mode != adv_input) {
- ret = adv7481_set_ip_mode(state, adv_input);
- if (ret)
- pr_err("%s: Set input mode failed: %d\n",
- __func__, ret);
- else
- state->mode = adv_input;
- }
+ ret = adv7481_set_ip_mode(state, adv_input);
+ if (ret)
+ pr_err("%s: Set input mode failed: %d\n", __func__, ret);
+ else
+ state->mode = adv_input;
unlock_exit:
mutex_unlock(&state->mutex);
@@ -986,6 +1522,27 @@ unlock_exit:
return ret;
}
+static bool adv7481_is_timing_locked(struct adv7481_state *state)
+{
+ bool ret = false;
+ int val1 = 0;
+ int val2 = 0;
+
+ /* Check Timing Lock IO Map Status3:0x71[0] && 0x71[1] && 0x71[7] */
+ val1 = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_RAW_STATUS_3_ADDR);
+ val2 = adv7481_rd_byte(&state->i2c_client, state->i2c_cp_addr,
+ CP_REG_STDI_CH_ADDR);
+
+ if (ADV_REG_GETFIELD(val1, IO_DE_REGEN_LCK_RAW) &&
+ ADV_REG_GETFIELD(val1, IO_V_LOCKED_RAW) &&
+ ADV_REG_GETFIELD(val1, IO_TMDSPLL_LCK_A_RAW) &&
+ ADV_REG_GETFIELD(val2, CP_STDI_DVALID_CH1))
+ ret = true;
+
+ return ret;
+}
+
static int adv7481_get_hdmi_timings(struct adv7481_state *state,
struct adv7481_vid_params *vid_params,
struct adv7481_hdmi_params *hdmi_params)
@@ -998,13 +1555,15 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
pr_debug("Enter %s\n", __func__);
/* Check TMDS PLL Lock and Frequency */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_HDMI_PARAM4_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_HDMI_PARAM4_ADDR);
hdmi_params->pll_lock = ADV_REG_GETFIELD(temp1,
HDMI_REG_TMDS_PLL_LOCKED);
if (hdmi_params->pll_lock) {
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
- HDMI_REG_TMDS_FREQ_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr, HDMI_REG_TMDS_FREQ_ADDR);
+ temp2 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr,
HDMI_REG_TMDS_FREQ_FRAC_ADDR);
hdmi_params->tmds_freq = ADV_REG_GETFIELD(temp1,
HDMI_REG_TMDS_FREQ);
@@ -1015,34 +1574,29 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
hdmi_params->tmds_freq += ADV_REG_GETFIELD(temp2,
HDMI_REG_TMDS_FREQ_FRAC)*ONE_MHZ_TO_HZ/128;
} else {
- pr_err("%s: PLL not locked return EBUSY\n", __func__);
- return -EBUSY;
+ pr_err("%s(%d): PLL not locked return EBUSY\n",
+ __func__, __LINE__);
+ ret = -EBUSY;
+ goto set_default;
}
- /* Check Timing Lock IO Map Status3:0x71[0] && 0x71[1] && 0x71[7] */
+ /* Check Timing Lock */
do {
- temp1 = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_cp,
- CP_REG_STDI_CH_ADDR);
-
- if (ADV_REG_GETFIELD(temp1, IO_DE_REGEN_LCK_RAW) &&
- ADV_REG_GETFIELD(temp1, IO_V_LOCKED_RAW) &&
- ADV_REG_GETFIELD(temp1, IO_TMDSPLL_LCK_A_RAW) &&
- ADV_REG_GETFIELD(temp2, CP_STDI_DVALID_CH1))
+ if (adv7481_is_timing_locked(state))
break;
count++;
usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
} while (count < LOCK_NUM_TRIES);
if (count >= LOCK_NUM_TRIES) {
- pr_err("%s(%d), adv7481 HDMI DE regeneration block NOT Locked: 0x%x",
- __func__, __LINE__, temp1);
+ pr_err("%s(%d), HDMI DE regeneration block NOT Locked\n",
+ __func__, __LINE__);
}
/* Check Timing Lock HDMI Map V:0x07[7], H:0x7[5] */
do {
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr,
HDMI_REG_LINE_WIDTH_1_ADDR);
if (ADV_REG_GETFIELD(temp1, HDMI_VERT_FILTER_LOCKED) &&
@@ -1059,7 +1613,8 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
}
/* Check HDMI Parameters */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_FIELD1_HEIGHT1_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_FIELD1_HEIGHT1_ADDR);
hdmi_params->color_depth = ADV_REG_GETFIELD(temp1,
HDMI_REG_DEEP_COLOR_MODE);
@@ -1068,22 +1623,25 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_HDMI_INTERLACED);
fieldfactor = (vid_params->intrlcd == 1) ? 2 : 1;
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_HDMI_PARAM5_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_HDMI_PARAM5_ADDR);
hdmi_params->pix_rep = ADV_REG_GETFIELD(temp1,
HDMI_REG_PIXEL_REPETITION);
/* Get Active Timing Data HDMI Map H:0x07[4:0] + 0x08[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_LINE_WIDTH_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_LINE_WIDTH_2_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_LINE_WIDTH_1_ADDR);
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_LINE_WIDTH_2_ADDR);
vid_params->act_pix = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_LINE_WIDTH_1) << 8) & 0x1F00) |
ADV_REG_GETFIELD(temp2,
HDMI_REG_LINE_WIDTH_2));
/* Get Total Timing Data HDMI Map H:0x1E[5:0] + 0x1F[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_TOTAL_LINE_WIDTH_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_TOTAL_LINE_WIDTH_2_ADDR);
vid_params->tot_pix = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_TOTAL_LINE_WIDTH_1) << 8) & 0x3F00) |
@@ -1091,9 +1649,9 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_TOTAL_LINE_WIDTH_2));
/* Get Active Timing Data HDMI Map V:0x09[4:0] + 0x0A[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_HEIGHT_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_HEIGHT_2_ADDR);
vid_params->act_lines = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_FIELD0_HEIGHT_1) << 8) & 0x1F00) |
@@ -1101,9 +1659,9 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_FIELD0_HEIGHT_2));
/* Get Total Timing Data HDMI Map V:0x26[5:0] + 0x27[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_TOTAL_HEIGHT_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_TOTAL_HEIGHT_2_ADDR);
vid_params->tot_lines = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_FIELD0_TOT_HEIGHT_1) << 8) & 0x3F00) |
@@ -1139,6 +1697,18 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
(hdmi_params->pix_rep + 1));
}
+set_default:
+ if (ret) {
+ pr_debug("%s(%d), error %d resort to default fmt\n",
+ __func__, __LINE__, ret);
+ vid_params->act_pix = MAX_DEFAULT_WIDTH;
+ vid_params->act_lines = MAX_DEFAULT_HEIGHT;
+ vid_params->fr_rate = MAX_DEFAULT_FRAME_RATE;
+ vid_params->pix_clk = MAX_DEFAULT_PIX_CLK_HZ;
+ vid_params->intrlcd = 0;
+ ret = 0;
+ }
+
pr_debug("%s(%d), adv7481 TMDS Resolution: %d x %d @ %d fps\n",
__func__, __LINE__,
vid_params->act_pix, vid_params->act_lines,
@@ -1170,15 +1740,22 @@ static int adv7481_query_dv_timings(struct v4l2_subdev *sd,
switch (state->mode) {
case ADV7481_IP_HDMI:
case ADV7481_IP_CVBS_1_HDMI_SIM:
- adv7481_get_hdmi_timings(state, &vid_params, &hdmi_params);
- timings->type = V4L2_DV_BT_656_1120;
- bt_timings->width = vid_params.act_pix;
- bt_timings->height = vid_params.act_lines;
- bt_timings->pixelclock = vid_params.pix_clk;
- bt_timings->interlaced = vid_params.intrlcd ?
+ ret = adv7481_get_hdmi_timings(state, &vid_params,
+ &hdmi_params);
+ if (!ret) {
+ timings->type = V4L2_DV_BT_656_1120;
+ bt_timings->width = vid_params.act_pix;
+ bt_timings->height = vid_params.act_lines;
+ bt_timings->pixelclock = vid_params.pix_clk;
+ bt_timings->interlaced = vid_params.intrlcd ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
- if (bt_timings->interlaced == V4L2_DV_INTERLACED)
- bt_timings->height /= 2;
+ if (bt_timings->interlaced == V4L2_DV_INTERLACED)
+ bt_timings->height /= 2;
+ } else {
+ pr_err(
+ "%s: Error in adv7481_get_hdmi_timings. ret %d\n",
+ __func__, ret);
+ }
break;
default:
return -EINVAL;
@@ -1193,10 +1770,24 @@ static int adv7481_query_sd_std(struct v4l2_subdev *sd, v4l2_std_id *std)
int temp = 0;
struct adv7481_state *state = to_state(sd);
uint8_t tStatus = 0x0;
+ uint32_t count = 0;
pr_debug("Enter %s\n", __func__);
- tStatus = adv7481_rd_byte(state->i2c_sdp, SDP_RO_MAIN_STATUS1_ADDR);
- if (!ADV_REG_GETFIELD(tStatus, SDP_RO_MAIN_IN_LOCK))
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
+ do {
+ tStatus = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
+ if (ADV_REG_GETFIELD(tStatus, SDP_RO_MAIN_IN_LOCK))
+ break;
+ count++;
+ usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
+ } while (count < LOCK_NUM_TRIES);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ if (count >= LOCK_NUM_TRIES)
pr_err("%s(%d), adv7481 SD Input NOT Locked: 0x%x\n",
__func__, __LINE__, tStatus);
@@ -1245,13 +1836,15 @@ static int adv7481_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int adv7481_g_mbus_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *fmt)
+static int adv7481_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
int ret;
struct adv7481_vid_params vid_params;
struct adv7481_hdmi_params hdmi_params;
struct adv7481_state *state = to_state(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
if (!fmt)
return -EINVAL;
@@ -1267,17 +1860,29 @@ static int adv7481_g_mbus_fmt(struct v4l2_subdev *sd,
switch (state->mode) {
case ADV7481_IP_HDMI:
case ADV7481_IP_CVBS_1_HDMI_SIM:
- adv7481_get_hdmi_timings(state, &vid_params, &hdmi_params);
- fmt->width = vid_params.act_pix;
- fmt->height = vid_params.act_lines;
- if (vid_params.intrlcd)
- fmt->height /= 2;
+ ret = adv7481_get_hdmi_timings(state, &vid_params,
+ &hdmi_params);
+ if (!ret) {
+ fmt->width = vid_params.act_pix;
+ fmt->height = vid_params.act_lines;
+ if (vid_params.intrlcd)
+ fmt->height /= 2;
+ } else {
+ pr_err("%s: Error %d in adv7481_get_hdmi_timings\n",
+ __func__, ret);
+ }
+ break;
+ case ADV7481_IP_CVBS_1:
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->width = 720;
+ fmt->height = 576;
break;
default:
return -EINVAL;
}
mutex_unlock(&state->mutex);
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
return ret;
}
@@ -1290,17 +1895,17 @@ static int adv7481_set_audio_spdif(struct adv7481_state *state,
if (on) {
/* Configure I2S_SDATA output pin as an SPDIF output 0x6E[3] */
- val = adv7481_rd_byte(state->i2c_hdmi,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR);
val |= ADV_REG_SETFIELD(1, HDMI_MUX_SPDIF_TO_I2S_EN);
- ret = adv7481_wr_byte(state->i2c_hdmi,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR, val);
} else {
/* Configure I2S_SDATA output pin as an I2S output 0x6E[3] */
- val = adv7481_rd_byte(state->i2c_hdmi,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR);
val &= ~ADV_REG_SETFIELD(1, HDMI_MUX_SPDIF_TO_I2S_EN);
- ret = adv7481_wr_byte(state->i2c_hdmi,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR, val);
}
return ret;
@@ -1310,40 +1915,42 @@ static int adv7481_csi_powerdown(struct adv7481_state *state,
enum adv7481_output output)
{
int ret;
- struct i2c_client *csi_map;
+ uint8_t csi_map;
uint8_t val = 0;
pr_debug("Enter %s for output: %d\n", __func__, output);
/* Select CSI TX to configure data */
if (output == ADV7481_OP_CSIA) {
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else if (output == ADV7481_OP_CSIB) {
- csi_map = state->i2c_csi_txb;
+ csi_map = state->i2c_csi_txb_addr;
} else if (output == ADV7481_OP_TTL) {
/* For now use TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else {
/* Default to TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
}
/* CSI Tx: power down DPHY */
- ret = adv7481_wr_byte(csi_map, CSI_REG_TX_DPHY_PWDN_ADDR,
+ ret = adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_DPHY_PWDN_ADDR,
ADV_REG_SETFIELD(1, CSI_CTRL_DPHY_PWDN));
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x82);
- ret |= adv7481_wr_byte(csi_map, 0x1e, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x82);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x1e, 0x00);
/* CSI TxA: # Lane : Power Off */
val = ADV_REG_SETFIELD(1, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/*
* ADI Recommended power down sequence
* DPHY and CSI Tx A Power down Sequence
* CSI TxA: MIPI PLL DIS
*/
- ret |= adv7481_wr_byte(csi_map, 0xda, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xda, 0x00);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0xc1, 0x3b);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc1, 0x3b);
pr_debug("Exit %s, ret: %d\n", __func__, ret);
@@ -1354,17 +1961,23 @@ static int adv7481_csi_powerup(struct adv7481_state *state,
enum adv7481_output output)
{
int ret;
- struct i2c_client *csi_map;
+ uint8_t csi_map;
uint8_t val = 0;
uint8_t csi_sel = 0;
pr_debug("Enter %s for output: %d\n", __func__, output);
/* Select CSI TX to configure data */
if (output == ADV7481_OP_CSIA) {
- csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
- ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
- ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- csi_map = state->i2c_csi_txa;
+ if (state->csia_src == ADV7481_IP_HDMI) {
+ csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
+ } else {
+ csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0x2, IO_CTRL_CSI4_IN_SEL);
+ }
+ csi_map = state->i2c_csi_txa_addr;
} else if (output == ADV7481_OP_CSIB) {
/* Enable 1-Lane MIPI Tx, enable pixel output and
* route SD through Pixel port
@@ -1373,54 +1986,57 @@ static int adv7481_csi_powerup(struct adv7481_state *state,
ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
ADV_REG_SETFIELD(1, IO_CTRL_SD_THRU_PIX_OUT) |
ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- csi_map = state->i2c_csi_txb;
+ csi_map = state->i2c_csi_txb_addr;
} else if (output == ADV7481_OP_TTL) {
/* For now use TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else {
/* Default to TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
}
/* Enable Tx A/B CSI #-lane */
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_CSI_PIX_EN_SEL_ADDR, csi_sel);
/* TXA MIPI lane settings for CSI */
/* CSI TxA: # Lane : Power Off */
val = ADV_REG_SETFIELD(1, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/* CSI TxA: Auto D-PHY Timing */
val |= ADV_REG_SETFIELD(1, CSI_CTRL_AUTO_PARAMS);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/* DPHY and CSI Tx A */
- ret |= adv7481_wr_byte(csi_map, 0xdb, 0x10);
- ret |= adv7481_wr_byte(csi_map, 0xd6, 0x07);
- ret |= adv7481_wr_byte(csi_map, 0xc4, 0x0a);
- ret |= adv7481_wr_byte(csi_map, 0x71, 0x33);
- ret |= adv7481_wr_byte(csi_map, 0x72, 0x11);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xdb, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xd6, 0x07);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc4, 0x0a);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x71, 0x33);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x72, 0x11);
/* CSI TxA: power up DPHY */
- ret |= adv7481_wr_byte(csi_map, 0xf0, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xf0, 0x00);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x82);
- ret |= adv7481_wr_byte(csi_map, 0x1e, 0x40);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x82);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x1e, 0x40);
/* adi Recommended power up sequence */
/* DPHY and CSI Tx A Power up Sequence */
/* CSI TxA: MIPI PLL EN */
- ret |= adv7481_wr_byte(csi_map, 0xda, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xda, 0x01);
msleep(200);
/* CSI TxA: # MIPI Lane : Power ON */
val = ADV_REG_SETFIELD(0, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(1, CSI_CTRL_AUTO_PARAMS) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
msleep(100);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0xc1, 0x2b);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc1, 0x2b);
msleep(100);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x80);
pr_debug("Exit %s, ret: %d\n", __func__, ret);
@@ -1476,42 +2092,43 @@ static int adv7481_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
int ret = 0;
struct adv7481_state *state = to_state(sd);
- uint8_t val1 = 0;
- uint8_t val2 = 0;
+ uint8_t val = 0;
uint32_t count = 0;
+ *status = 0;
pr_debug("Enter %s\n", __func__);
if (ADV7481_IP_HDMI == state->mode) {
- /*
- * Check Timing Lock IO Map Status3:0x71[0] &&
- * 0x71[1] && 0x71[7]
- */
+ /* Check Timing Lock */
do {
- val1 = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- val2 = adv7481_rd_byte(state->i2c_cp,
- CP_REG_STDI_CH_ADDR);
-
- if (ADV_REG_GETFIELD(val1, IO_DE_REGEN_LCK_RAW) &&
- ADV_REG_GETFIELD(val1, IO_V_LOCKED_RAW) &&
- ADV_REG_GETFIELD(val1, IO_TMDSPLL_LCK_A_RAW) &&
- ADV_REG_GETFIELD(val2, CP_STDI_DVALID_CH1))
+ if (adv7481_is_timing_locked(state))
break;
count++;
usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
} while (count < LOCK_NUM_TRIES);
if (count >= LOCK_NUM_TRIES) {
- pr_err("%s(%d), HDMI DE regeneration block NOT Locked: 0x%x, 0x%x",
- __func__, __LINE__, val1, val2);
+ pr_err("%s(%d), HDMI DE regeneration block NOT Locked\n",
+ __func__, __LINE__);
*status |= V4L2_IN_ST_NO_SIGNAL;
}
} else {
- val1 = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
- if (!ADV_REG_GETFIELD(val1, SDP_RO_MAIN_IN_LOCK)) {
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
+ do {
+ val = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
+ if (ADV_REG_GETFIELD(val, SDP_RO_MAIN_IN_LOCK))
+ break;
+ count++;
+ usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
+ } while (count < LOCK_NUM_TRIES);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ if (count >= LOCK_NUM_TRIES) {
pr_err("%s(%d), SD Input NOT Locked: 0x%x\n",
- __func__, __LINE__, val1);
+ __func__, __LINE__, val);
*status |= V4L2_IN_ST_NO_SIGNAL;
}
}
@@ -1530,7 +2147,6 @@ static int adv7481_s_stream(struct v4l2_subdev *sd, int on)
static const struct v4l2_subdev_video_ops adv7481_video_ops = {
.s_routing = adv7481_s_routing,
.g_frame_interval = adv7481_g_frame_interval,
- .g_mbus_fmt = adv7481_g_mbus_fmt,
.querystd = adv7481_query_sd_std,
.g_dv_timings = adv7481_query_dv_timings,
.g_input_status = adv7481_g_input_status,
@@ -1539,6 +2155,11 @@ static const struct v4l2_subdev_video_ops adv7481_video_ops = {
static const struct v4l2_subdev_core_ops adv7481_core_ops = {
.s_power = adv7481_s_power,
+ .ioctl = adv7481_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops adv7481_pad_ops = {
+ .get_fmt = adv7481_get_fmt,
};
static const struct v4l2_ctrl_ops adv7481_ctrl_ops = {
@@ -1548,10 +2169,13 @@ static const struct v4l2_ctrl_ops adv7481_ctrl_ops = {
static const struct v4l2_subdev_ops adv7481_ops = {
.core = &adv7481_core_ops,
.video = &adv7481_video_ops,
+ .pad = &adv7481_pad_ops,
};
static int adv7481_init_v4l2_controls(struct adv7481_state *state)
{
+ int ret = 0;
+
v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7481_ctrl_ops,
@@ -1565,59 +2189,195 @@ static int adv7481_init_v4l2_controls(struct adv7481_state *state)
state->sd.ctrl_handler = &state->ctrl_hdl;
if (state->ctrl_hdl.error) {
- int err = state->ctrl_hdl.error;
+ ret = state->ctrl_hdl.error;
v4l2_ctrl_handler_free(&state->ctrl_hdl);
- return err;
+ } else {
+ v4l2_ctrl_handler_setup(&state->ctrl_hdl);
}
- v4l2_ctrl_handler_setup(&state->ctrl_hdl);
- return 0;
+ pr_err("%s: Exit with ret: %d\n", __func__, ret);
+ return ret;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+ .i2c_read = msm_camera_cci_i2c_read,
+ .i2c_read_seq = msm_camera_cci_i2c_read_seq,
+ .i2c_write = msm_camera_cci_i2c_write,
+ .i2c_write_seq = msm_camera_cci_i2c_write_seq,
+ .i2c_write_table = msm_camera_cci_i2c_write_table,
+ .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+ .i2c_write_table_w_microdelay =
+ msm_camera_cci_i2c_write_table_w_microdelay,
+ .i2c_util = msm_sensor_cci_i2c_util,
+ .i2c_poll = msm_camera_cci_i2c_poll,
+};
+
+static int adv7481_cci_init(struct adv7481_state *state)
+{
+ struct msm_camera_cci_client *cci_client = NULL;
+ int ret = 0;
+
+ pr_err("%s: Enter\n", __func__);
+
+ state->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
+ state->i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ state->i2c_client.cci_client = kzalloc(sizeof(
+ struct msm_camera_cci_client), GFP_KERNEL);
+ cci_client = state->i2c_client.cci_client;
+ if (!cci_client) {
+ ret = -ENOMEM;
+ goto err_cci_init;
+ }
+ cci_client->cci_subdev = msm_cci_get_subdev();
+ pr_debug("%s cci_subdev: %p\n", __func__, cci_client->cci_subdev);
+ if (!cci_client->cci_subdev) {
+ ret = -EPROBE_DEFER;
+ goto err_cci_init;
+ }
+ cci_client->cci_i2c_master = state->cci_master;
+ cci_client->sid = state->i2c_slave_addr;
+ cci_client->retries = 3;
+ cci_client->id_map = 0;
+ cci_client->i2c_freq_mode = I2C_CUSTOM_MODE;
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_INIT);
+ if (ret < 0)
+ pr_err("%s - cci_init failed\n", __func__);
+ else
+ state->clocks_requested = TRUE;
+
+ pr_debug("%s i2c_client.client: %p\n", __func__,
+ state->i2c_client.client);
+
+err_cci_init:
+ return ret;
}
-static int adv7481_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7481_parse_dt(struct platform_device *pdev,
+ struct adv7481_state *state)
+{
+ struct device_node *np = state->dev->of_node;
+ uint32_t i = 0;
+ int gpio_count = 0;
+ struct resource *adv_addr_res = NULL;
+ int ret = 0;
+
+ /* config CCI */
+ ret = of_property_read_u32(np, "qcom,cci-master",
+ &state->cci_master);
+ if (ret < 0 || state->cci_master >= MASTER_MAX) {
+ pr_err("%s: failed to read cci master . ret %d\n",
+ __func__, ret);
+ goto exit;
+ }
+ pr_debug("%s: cci_master: 0x%x\n", __func__, state->cci_master);
+ adv_addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!adv_addr_res) {
+ pr_err("%s: failed to read adv7481 resource.\n", __func__);
+ goto exit;
+ }
+ state->i2c_slave_addr = adv_addr_res->start;
+ pr_debug("%s: i2c_slave_addr: 0x%x\n", __func__, state->i2c_slave_addr);
+ state->i2c_io_addr = (uint8_t)state->i2c_slave_addr;
+
+ gpio_count = of_gpio_count(np);
+ if (gpio_count != ADV7481_GPIO_MAX) {
+ ret = -EFAULT;
+ pr_err("%s: dt gpio count %d doesn't match required. ret %d\n",
+ __func__, gpio_count, ret);
+ goto exit;
+ }
+ for (i = 0; i < ADV7481_GPIO_MAX; i++) {
+ state->gpio_array[i].gpio = of_get_gpio_flags(np, i,
+ (enum of_gpio_flags *)&state->gpio_array[i].flags);
+ if (!gpio_is_valid(state->gpio_array[i].gpio)) {
+ pr_err("invalid gpio setting for index %d\n", i);
+ ret = -EFAULT;
+ goto exit;
+ }
+ pr_debug("%s: gpio_array[%d] = %d flag = %ld\n", __func__, i,
+ state->gpio_array[i].gpio, state->gpio_array[i].flags);
+ }
+
+exit:
+ return ret;
+}
+
+static const struct of_device_id adv7481_id[] = {
+ { .compatible = "qcom,adv7481", },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, adv7481_id);
+
+static int adv7481_probe(struct platform_device *pdev)
{
struct adv7481_state *state;
- struct adv7481_platform_data *pdata = NULL;
+ const struct of_device_id *device_id;
struct v4l2_subdev *sd;
- struct v4l2_ctrl_handler *hdl;
int ret;
- pr_debug("Attempting to probe...\n");
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- pr_err("%s %s Check i2c Functionality Fail\n",
- __func__, client->name);
- ret = -EIO;
+ device_id = of_match_device(adv7481_id, &pdev->dev);
+ if (!device_id) {
+ pr_err("%s: device_id is NULL\n", __func__);
+ ret = -ENODEV;
goto err;
}
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr, client->adapter->name);
/* Create 7481 State */
- state = devm_kzalloc(&client->dev,
- sizeof(struct adv7481_state), GFP_KERNEL);
+ state = devm_kzalloc(&pdev->dev,
+ sizeof(struct adv7481_state), GFP_KERNEL);
if (state == NULL) {
ret = -ENOMEM;
- pr_err("Check Kzalloc Fail\n");
- goto err_mem;
+ goto err;
}
- state->client = client;
+ platform_set_drvdata(pdev, state);
+ state->dev = &pdev->dev;
+
mutex_init(&state->mutex);
+ ret = adv7481_parse_dt(pdev, state);
+ if (ret < 0) {
+ pr_err("Error parsing dt tree\n");
+ goto err_mem_free;
+ }
- /* Get and Check Platform Data */
- pdata = (struct adv7481_platform_data *) client->dev.platform_data;
- if (!pdata) {
- ret = -ENOMEM;
- pr_err("Getting Platform data failed\n");
- goto err_mem;
+ ret = adv7481_cci_init(state);
+ if (ret < 0) {
+ pr_err("%s: failed adv7481_cci_init ret %d\n", __func__, ret);
+ goto err_mem_free;
+ }
+
+ /* config VREG */
+ ret = msm_camera_get_dt_vreg_data(pdev->dev.of_node,
+ &(state->cci_vreg), &(state->regulator_count));
+ if (ret < 0) {
+ pr_err("%s:cci get_dt_vreg failed\n", __func__);
+ goto err_mem_free;
+ }
+
+ ret = msm_camera_config_vreg(&pdev->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0) {
+ pr_err("%s:cci config_vreg failed\n", __func__);
+ goto err_mem_free;
+ }
+
+ ret = msm_camera_enable_vreg(&pdev->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0) {
+ pr_err("%s:cci enable_vreg failed\n", __func__);
+ goto err_mem_free;
}
+ pr_debug("%s - VREG Initialized...\n", __func__);
- /* Configure and Register V4L2 I2C Sub-device */
+ /* Configure and Register V4L2 Sub-device */
sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &adv7481_ops);
+ v4l2_subdev_init(sd, &adv7481_ops);
+ sd->owner = pdev->dev.driver->owner;
+ v4l2_set_subdevdata(sd, state);
+ strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
state->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
@@ -1627,103 +2387,136 @@ static int adv7481_probe(struct i2c_client *client,
ret = media_entity_init(&state->sd.entity, 1, &state->pad, 0);
if (ret) {
ret = -EIO;
- pr_err("Media entity init failed\n");
+ pr_err("%s(%d): Media entity init failed\n",
+ __func__, __LINE__);
goto err_media_entity;
}
/* Initialize HW Config */
- ret = adv7481_hw_init(pdata, state);
+ ret = adv7481_hw_init(state);
if (ret) {
ret = -EIO;
- pr_err("HW Initialisation Failed\n");
+ pr_err("%s: HW Initialisation Failed\n", __func__);
goto err_media_entity;
}
/* Register V4l2 Control Functions */
- hdl = &state->ctrl_hdl;
- v4l2_ctrl_handler_init(hdl, 4);
- adv7481_init_v4l2_controls(state);
+ ret = adv7481_init_v4l2_controls(state);
+ if (ret) {
+ pr_err("%s: V4L2 Controls Initialisation Failed %d\n",
+ __func__, ret);
+ }
- /* Initials ADV7481 State Settings */
+ /* Initial ADV7481 State Settings */
state->tx_auto_params = ADV7481_AUTO_PARAMS;
- state->tx_lanes = ADV7481_MIPI_2LANE;
/* Initialize SW Init Settings and I2C sub maps 7481 */
- ret = adv7481_dev_init(state, client);
+ ret = adv7481_dev_init(state);
if (ret) {
ret = -EIO;
- pr_err("SW Initialisation Failed\n");
+ pr_err("%s(%d): SW Initialisation Failed\n",
+ __func__, __LINE__);
goto err_media_entity;
}
- /* Set hdmi settings */
- ret = adv7481_set_hdmi_mode(state);
-
/* BA registration */
- ret |= msm_ba_register_subdev_node(sd);
+ ret = msm_ba_register_subdev_node(sd);
if (ret) {
ret = -EIO;
- pr_err("BA INIT FAILED\n");
+ pr_err("%s: BA init failed\n", __func__);
goto err_media_entity;
}
+ enable_irq(state->irq);
pr_debug("Probe successful!\n");
return ret;
err_media_entity:
media_entity_cleanup(&sd->entity);
-err_mem:
- kfree(state);
+
+err_mem_free:
+ adv7481_release_cci_clks(state);
+ devm_kfree(&pdev->dev, state);
+
err:
- if (!ret)
- ret = 1;
return ret;
}
-static int adv7481_remove(struct i2c_client *client)
+static int adv7481_remove(struct platform_device *pdev)
{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct adv7481_state *state = to_state(sd);
+ struct adv7481_state *state = platform_get_drvdata(pdev);
- msm_ba_unregister_subdev_node(sd);
- v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
+ msm_ba_unregister_subdev_node(&state->sd);
+ v4l2_device_unregister_subdev(&state->sd);
+ media_entity_cleanup(&state->sd.entity);
v4l2_ctrl_handler_free(&state->ctrl_hdl);
+ adv7481_reset_irq(state);
if (state->irq > 0)
free_irq(state->irq, state);
- i2c_unregister_device(state->i2c_csi_txa);
- i2c_unregister_device(state->i2c_csi_txb);
- i2c_unregister_device(state->i2c_hdmi);
- i2c_unregister_device(state->i2c_edid);
- i2c_unregister_device(state->i2c_cp);
- i2c_unregister_device(state->i2c_sdp);
- i2c_unregister_device(state->i2c_rep);
+ cancel_delayed_work(&state->irq_delayed_work);
mutex_destroy(&state->mutex);
- kfree(state);
+ devm_kfree(&pdev->dev, state);
return 0;
}
-static const struct i2c_device_id adv7481_id[] = {
- { DRIVER_NAME, 0 },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, adv7481_id);
+#ifdef CONFIG_PM_SLEEP
+static int adv7481_suspend(struct device *dev)
+{
+ struct adv7481_state *state;
+ int ret;
+
+ state = (struct adv7481_state *)dev_get_drvdata(dev);
+
+ /* release CCI clocks */
+ ret = adv7481_release_cci_clks(state);
+ if (ret)
+ pr_err("%s: adv7481 release cci clocks failed\n", __func__);
+ else
+ pr_debug("released cci clocks in suspend");
+
+ return 0;
+}
+
+static int adv7481_resume(struct device *dev)
+{
+ struct adv7481_state *state;
+ int ret;
+
+ state = (struct adv7481_state *)dev_get_drvdata(dev);
+
+ /* Request CCI clocks */
+ ret = adv7481_request_cci_clks(state);
+ if (ret)
+ pr_err("%s: adv7481 request cci clocks failed\n", __func__);
+ else
+ pr_debug("requested cci clocks in resume");
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(adv7481_pm_ops, adv7481_suspend, adv7481_resume);
+#define ADV7481_PM_OPS (&adv7481_pm_ops)
+#else
+#define ADV7481_PM_OPS NULL
+#endif
-static struct i2c_driver adv7481_driver = {
+static struct platform_driver adv7481_driver = {
.driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
+ .of_match_table = adv7481_id,
+ .pm = ADV7481_PM_OPS,
},
.probe = adv7481_probe,
.remove = adv7481_remove,
- .id_table = adv7481_id,
};
-module_i2c_driver(adv7481_driver);
+module_driver(adv7481_driver, platform_driver_register,
+ platform_driver_unregister);
MODULE_DESCRIPTION("ADI ADV7481 HDMI/MHL/SD video receiver");