OSDN Git Service

adv7481: Add support for AVI Infoframe
authorSuprith Malligere Shankaregowda <supgow@codeaurora.org>
Tue, 22 May 2018 19:41:23 +0000 (01:11 +0530)
committerGerrit - the friendly Code Review server <code-review@localhost>
Thu, 31 May 2018 04:21:40 +0000 (21:21 -0700)
AVI Infoframe provides the aspect ratio and video
identification code information. Add support to read
this from ADV7481 registers and to return it to user space
through an ioctl call.

Change-Id: Ia64fbc736b548633b34a9bd96f7a78700afb3db5
Signed-off-by: Suprith Malligere Shankaregowda <supgow@codeaurora.org>
drivers/media/i2c/adv7481.c
drivers/media/i2c/adv7481_reg.h
drivers/video/msm/ba/msm_ba.c
include/uapi/media/msm_ba.h

index 43a5f3d..19ec111 100644 (file)
 #include "msm_camera_i2c.h"
 #include "msm_camera_io_util.h"
 #include "msm_camera_dt_util.h"
+#include "linux/hdmi.h"
 
 #define DRIVER_NAME "adv7481"
 
-#define I2C_RW_DELAY           1
-#define I2C_SW_RST_DELAY       5000
+#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         200
+#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                 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
-#define ADV_REG_STABLE_DELAY    70      /* ms*/
+#define ONE_MHZ_TO_HZ                  1000000
+#define I2C_BLOCK_WRITE_SIZE   1024
+#define ADV_REG_STABLE_DELAY   70              /* ms*/
+
+#define AVI_INFOFRAME_SIZE             31
+#define INFOFRAME_DATA_SIZE            28
 
 enum adv7481_gpio_t {
 
@@ -120,6 +124,7 @@ struct adv7481_state {
        uint8_t i2c_csi_txa_addr;
        uint8_t i2c_csi_txb_addr;
        uint8_t i2c_hdmi_addr;
+       uint8_t i2c_hdmi_inf_addr;
        uint8_t i2c_edid_addr;
        uint8_t i2c_cp_addr;
        uint8_t i2c_sdp_addr;
@@ -141,6 +146,9 @@ struct adv7481_state {
        int csib_src;
        int mode;
 
+       /* AVI Infoframe Params */
+       struct avi_infoframe_params hdmi_avi_infoframe;
+
        /* resolution configuration */
        struct resolution_config res_configs[RES_MAX];
 
@@ -304,6 +312,14 @@ static int32_t adv7481_cci_i2c_read(struct msm_camera_i2c_client *i2c_client,
                                data, data_type);
 }
 
+static int32_t adv7481_cci_i2c_read_seq(
+       struct msm_camera_i2c_client *i2c_client,
+       uint8_t reg, uint8_t *data, uint32_t size)
+{
+       return i2c_client->i2c_func_tbl->i2c_read_seq(i2c_client, reg,
+                               data, size);
+}
+
 static int32_t adv7481_wr_byte(struct msm_camera_i2c_client *c_i2c_client,
        uint8_t sid, uint8_t reg, uint8_t data)
 {
@@ -334,6 +350,20 @@ static int32_t adv7481_wr_block(struct msm_camera_i2c_client *c_i2c_client,
        return ret;
 }
 
+static int32_t adv7481_rd_block(struct msm_camera_i2c_client *c_i2c_client,
+       uint8_t sid, uint8_t reg, uint8_t *data, uint32_t size)
+{
+       int ret = 0;
+
+       c_i2c_client->cci_client->sid = sid;
+
+       ret = adv7481_cci_i2c_read_seq(c_i2c_client, reg, data, size);
+       if (ret < 0)
+               pr_err("Error %d reading 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)
 {
@@ -392,6 +422,7 @@ static int adv7481_set_irq(struct adv7481_state *state)
                        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 cable detect */
        ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
                        IO_HDMI_LVL_INT_MASKB_3_ADDR,
@@ -801,6 +832,7 @@ static int adv7481_dev_init(struct adv7481_state *state)
        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_hdmi_inf_addr = IO_REG_HDMI_INF_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;
@@ -1035,10 +1067,16 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
        struct adv7481_vid_params vid_params;
        struct adv7481_hdmi_params hdmi_params;
 
+       struct device *dev = state->dev;
+       union hdmi_infoframe hdmi_info_frame;
+       uint8_t inf_buffer[AVI_INFOFRAME_SIZE];
+
        pr_debug("Enter %s with command: 0x%x", __func__, cmd);
 
        memset(&vid_params, 0, sizeof(struct adv7481_vid_params));
        memset(&hdmi_params, 0, sizeof(struct adv7481_hdmi_params));
+       memset(&hdmi_info_frame, 0, sizeof(union hdmi_infoframe));
+       memset(inf_buffer, 0, AVI_INFOFRAME_SIZE);
 
        if (!sd)
                return -EINVAL;
@@ -1091,6 +1129,58 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
                }
                break;
        }
+       case VIDIOC_G_AVI_INFOFRAME: {
+               int int_raw = adv7481_rd_byte(&state->i2c_client,
+                       state->i2c_io_addr,
+                       IO_HDMI_EDG_RAW_STATUS_1_ADDR);
+               adv7481_wr_byte(&state->i2c_client,
+                       state->i2c_io_addr,
+                       IO_HDMI_EDG_INT_CLEAR_1_ADDR, int_raw);
+               if (ADV_REG_GETFIELD(int_raw, IO_NEW_AVI_INFO_RAW)) {
+                       inf_buffer[0] = adv7481_rd_byte(&state->i2c_client,
+                               state->i2c_hdmi_inf_addr,
+                               HDMI_REG_AVI_PACKET_ID_ADDR);
+                       inf_buffer[1] = adv7481_rd_byte(&state->i2c_client,
+                               state->i2c_hdmi_inf_addr,
+                               HDMI_REG_AVI_INF_VERS_ADDR);
+                       inf_buffer[2] = adv7481_rd_byte(&state->i2c_client,
+                               state->i2c_hdmi_inf_addr,
+                               HDMI_REG_AVI_INF_LEN_ADDR);
+                       ret = adv7481_rd_block(&state->i2c_client,
+                               state->i2c_hdmi_inf_addr,
+                               HDMI_REG_AVI_INF_PB_ADDR,
+                               &inf_buffer[3],
+                               INFOFRAME_DATA_SIZE);
+                       if (ret) {
+                               pr_err("%s:Error in VIDIOC_G_AVI_INFOFRAME\n",
+                                               __func__);
+                               return -EINVAL;
+                       }
+                       if (hdmi_infoframe_unpack(&hdmi_info_frame,
+                                       (void *)inf_buffer) < 0) {
+                               pr_err("%s: infoframe unpack fail\n", __func__);
+                               return -EINVAL;
+                       }
+                       hdmi_infoframe_log(KERN_ERR, dev, &hdmi_info_frame);
+                       state->hdmi_avi_infoframe.picture_aspect =
+                               (enum picture_aspect_ratio)
+                                       hdmi_info_frame.avi.picture_aspect;
+                       state->hdmi_avi_infoframe.active_aspect =
+                               (enum active_format_aspect_ratio)
+                                       hdmi_info_frame.avi.active_aspect;
+                       state->hdmi_avi_infoframe.video_code =
+                               hdmi_info_frame.avi.video_code;
+               } else {
+                       pr_err("%s: No new AVI Infoframe\n", __func__);
+               }
+               if (copy_to_user((void __user *)adv_arg.ptr,
+                               (void *)&state->hdmi_avi_infoframe,
+                               sizeof(struct avi_infoframe_params))) {
+                       pr_err("%s: Failed to copy Infoframe\n", __func__);
+                       return -EINVAL;
+               }
+               break;
+       }
        case VIDIOC_G_FIELD_INFO:
                /* Select SDP read-only Map 1 */
                adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
@@ -2628,7 +2718,7 @@ static int adv7481_probe(struct platform_device *pdev)
                goto err_media_entity;
        }
        enable_irq(state->irq);
-       pr_debug("Probe successful!\n");
+       pr_info("ADV7481 Probe successful!\n");
 
        return ret;
 
index 76c992c..3d484c6 100644 (file)
 #define HDMI_EDID_A_ENABLE_BMSK                 0x0001
 #define HDMI_EDID_A_ENABLE_SHFT                 0
 
+/* HDMI RX INFOFRAME Map Registers (Read Only) */
+#define HDMI_REG_AVI_INF_PB_ADDR                0x00
+#define HDMI_REG_AVI_PACKET_ID_ADDR             0xE0
+#define HDMI_REG_AVI_INF_VERS_ADDR              0xE1
+#define HDMI_REG_AVI_INF_LEN_ADDR               0xE2
+
 /* CEC Map Registers */
 #define CEC_REG_LOG_ADDR_MASK_ADDR              0x27
 #define CEC_REG_LOG_ADDR_MASK2_BMSK             0x0040
index 95edb5b..42a7377 100644 (file)
@@ -574,6 +574,24 @@ long msm_ba_private_ioctl(void *instance, int cmd, void *arg)
                }
        }
                break;
+       case VIDIOC_G_AVI_INFOFRAME: {
+               dprintk(BA_DBG, "VIDIOC_G_AVI_INFOFRAME\n");
+               sd = inst->sd;
+               if (!sd) {
+                       dprintk(BA_ERR, "No sd registered");
+                       return -EINVAL;
+               }
+               if (arg) {
+                       rc = v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+                       if (rc)
+                               dprintk(BA_ERR, "%s failed: %ld on cmd: 0x%x",
+                                       __func__, rc, cmd);
+               } else {
+                       dprintk(BA_ERR, "%s: NULL argument provided", __func__);
+                       rc = -EINVAL;
+               }
+       }
+               break;
        case VIDIOC_G_FIELD_INFO: {
                dprintk(BA_DBG, "VIDIOC_G_FIELD_INFO");
                sd = inst->sd;
index 933dd85..45ddfb4 100644 (file)
@@ -23,6 +23,35 @@ struct csi_ctrl_params {
        uint32_t lane_count;
 };
 
+/* AVI Infoframe params */
+enum picture_aspect_ratio {
+       PICTURE_ASPECT_RATIO_NONE,
+       PICTURE_ASPECT_RATIO_4_3,
+       PICTURE_ASPECT_RATIO_16_9,
+       PICTURE_ASPECT_RATIO_64_27,
+       PICTURE_ASPECT_RATIO_256_135,
+       PICTURE_ASPECT_RATIO_RESERVED,
+};
+
+enum active_format_aspect_ratio {
+       ACTIVE_ASPECT_RATIO_16_9_TOP = 2,
+       ACTIVE_ASPECT_RATIO_14_9_TOP = 3,
+       ACTIVE_ASPECT_RATIO_16_9_CENTER = 4,
+       ACTIVE_ASPECT_RATIO_PICTURE = 8,
+       ACTIVE_ASPECT_RATIO_4_3 = 9,
+       ACTIVE_ASPECT_RATIO_16_9 = 10,
+       ACTIVE_ASPECT_RATIO_14_9 = 11,
+       ACTIVE_ASPECT_RATIO_4_3_SP_14_9 = 13,
+       ACTIVE_ASPECT_RATIO_16_9_SP_14_9 = 14,
+       ACTIVE_ASPECT_RATIO_16_9_SP_4_3 = 15,
+};
+
+struct avi_infoframe_params {
+       enum picture_aspect_ratio picture_aspect;
+       enum active_format_aspect_ratio active_aspect;
+       unsigned char video_code;
+};
+
 /* Field info params */
 struct field_info_params {
        bool even_field;
@@ -41,5 +70,8 @@ struct msm_ba_v4l2_ioctl_t {
 /* ADV7481 private ioctls for field info query */
 #define VIDIOC_G_FIELD_INFO \
        _IOWR('V', BASE_VIDIOC_PRIVATE + 40, struct msm_ba_v4l2_ioctl_t)
+/* ADV7481 private ioctl for AVI Infoframe query */
+#define VIDIOC_G_AVI_INFOFRAME \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 41, struct msm_ba_v4l2_ioctl_t)
 
 #endif