ADV7481: Query lane_count and settle_count from device tree

Get lane count and settle count from device tree.
Add VIDIOC_G_CSI_PARAMS ioctl to pass lane count
and settle count values to userspace.

Change-Id: Ic0e0b7b402908c9970fd1771cf9bf19627f5a5d8
Signed-off-by: Rahul Sharma <sharah@codeaurora.org>
This commit is contained in:
Rahul Sharma 2017-11-14 15:59:46 +05:30 committed by Gerrit - the friendly Code Review server
parent 8ed108c977
commit 720aa591f4
8 changed files with 242 additions and 6 deletions

View file

@ -15,6 +15,12 @@ Required properties
interrupt 1, interrupt 2 and interrupt 3. interrupt 1, interrupt 2 and interrupt 3.
- cam_vdig-supply: Should contain regulator to be used for the digital - cam_vdig-supply: Should contain regulator to be used for the digital
vdd. vdd.
- tx-lanes: Should contain array of csi transmission lanes required
to select csi lane by adv7481 driver.
- settle-count: Should contain array of csi settle count required
to select settle count by adv7481 driver.
- res-array: Should contain array of resolution supported by
adv7481 driver.
- cam_vio-supply: Should contain regulator to be used for the IO vdd. - cam_vio-supply: Should contain regulator to be used for the IO vdd.
- cam_vana-supply: Should contain regulator from which analog voltage - cam_vana-supply: Should contain regulator from which analog voltage
is supplied. is supplied.
@ -35,6 +41,9 @@ Example:
compatible = "qcom,adv7481"; compatible = "qcom,adv7481";
reg = <0x70 0xff>; reg = <0x70 0xff>;
cam_vdig-supply = <&vph_pwr_vreg>; cam_vdig-supply = <&vph_pwr_vreg>;
tx-lanes = <4 2 1>;
settle-count = <16 16 16>;
res-array = "RES_1080P", "RES_720P", "RES_576P_480P";
/* Cameras powered by PMIC: */ /* Cameras powered by PMIC: */
cam_vio-supply = <&pm8994_lvs1>; cam_vio-supply = <&pm8994_lvs1>;
cam_vana-supply = <&pm8994_l17>; cam_vana-supply = <&pm8994_l17>;

View file

@ -1137,9 +1137,9 @@
compatible = "qcom,adv7481"; compatible = "qcom,adv7481";
reg = <0x70 0xff>; reg = <0x70 0xff>;
cam_vdig-supply = <&pm8994_s3>; cam_vdig-supply = <&pm8994_s3>;
tx_lanes = <4 2 1>; tx-lanes = <4 2 1>;
settle_count = <16 16 16>; settle-count = <16 16 16>;
res_array = "RES_1080P", "RES_720P", "RES_576P_480P"; res-array = "RES_1080P", "RES_720P", "RES_576P_480P";
/* Cameras powered by PMIC: */ /* Cameras powered by PMIC: */
cam_vio-supply = <&pm8994_lvs1>; cam_vio-supply = <&pm8994_lvs1>;
cam_vana-supply = <&pm8994_l17>; cam_vana-supply = <&pm8994_l17>;

View file

@ -75,6 +75,19 @@ enum adv7481_gpio_t {
ADV7481_GPIO_MAX, ADV7481_GPIO_MAX,
}; };
enum adv7481_resolution {
RES_1080P = 0,
RES_720P,
RES_576P_480P,
RES_MAX,
};
struct resolution_config {
uint32_t lane_cnt;
uint32_t settle_cnt;
char resolution[20];
};
struct adv7481_state { struct adv7481_state {
struct device *dev; struct device *dev;
@ -125,6 +138,9 @@ struct adv7481_state {
int csib_src; int csib_src;
int mode; int mode;
/* resolution configuration */
struct resolution_config res_configs[RES_MAX];
/* CSI configuration data */ /* CSI configuration data */
int tx_auto_params; int tx_auto_params;
enum adv7481_mipi_lane tx_lanes; enum adv7481_mipi_lane tx_lanes;
@ -241,6 +257,13 @@ const uint8_t adv7481_default_edid_data[] = {
static u32 adv7481_inp_to_ba(u32 adv_input); static u32 adv7481_inp_to_ba(u32 adv_input);
static bool adv7481_is_timing_locked(struct adv7481_state *state); static bool adv7481_is_timing_locked(struct adv7481_state *state);
static int adv7481_get_hdmi_timings(struct adv7481_state *state,
struct adv7481_vid_params *vid_params,
struct adv7481_hdmi_params *hdmi_params);
static int get_lane_cnt(struct resolution_config *configs,
enum adv7481_resolution size, int w, int h);
static int get_settle_cnt(struct resolution_config *configs,
enum adv7481_resolution size, int w, int h);
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{ {
@ -1005,11 +1028,18 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{ {
struct adv7481_state *state = to_state(sd); struct adv7481_state *state = to_state(sd);
int *ret_val = arg; int *ret_val = arg;
struct msm_ba_v4l2_ioctl_t adv_arg = *(struct msm_ba_v4l2_ioctl_t *)arg;
long ret = 0; long ret = 0;
int param = 0; int param = 0;
struct csi_ctrl_params user_csi;
struct adv7481_vid_params vid_params;
struct adv7481_hdmi_params hdmi_params;
pr_debug("Enter %s with command: 0x%x", __func__, cmd); 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));
if (!sd) if (!sd)
return -EINVAL; return -EINVAL;
@ -1039,6 +1069,28 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
case VIDIOC_HDMI_RX_CEC_S_ENABLE: case VIDIOC_HDMI_RX_CEC_S_ENABLE:
ret = adv7481_cec_powerup(state, arg); ret = adv7481_cec_powerup(state, arg);
break; break;
case VIDIOC_G_CSI_PARAMS: {
if (state->csia_src == ADV7481_IP_HDMI) {
ret = adv7481_get_hdmi_timings(state,
&vid_params, &hdmi_params);
if (ret) {
pr_err("%s:Error in adv7481_get_hdmi_timings\n",
__func__);
return -EINVAL;
}
}
user_csi.settle_count = get_settle_cnt(state->res_configs,
RES_MAX, vid_params.act_pix, vid_params.act_lines);
user_csi.lane_count = get_lane_cnt(state->res_configs,
RES_MAX, vid_params.act_pix, vid_params.act_lines);
if (copy_to_user((void __user *)adv_arg.ptr,
(void *)&user_csi, sizeof(struct csi_ctrl_params))) {
pr_err("%s: Failed to copy CSI params\n", __func__);
return -EINVAL;
}
break;
}
default: default:
pr_err("Not a typewriter! Command: 0x%x", cmd); pr_err("Not a typewriter! Command: 0x%x", cmd);
ret = -ENOTTY; ret = -ENOTTY;
@ -1541,6 +1593,65 @@ static bool adv7481_is_timing_locked(struct adv7481_state *state)
return ret; return ret;
} }
static int get_settle_cnt(struct resolution_config *configs,
enum adv7481_resolution size, int w, int h)
{
int i;
int ret = -EINVAL;
char res_type[20] = "RES_MAX";
if (w == 1920 && h == 1080) {
strlcpy(res_type, "RES_1080P", sizeof(res_type));
} else if (w == 1280 && h == 720) {
strlcpy(res_type, "RES_720P", sizeof(res_type));
} else if ((w == 720 && h == 576) || (w == 720 && h == 480)) {
strlcpy(res_type, "RES_576P_480P", sizeof(res_type));
} else {
pr_err("%s: Resolution not supported\n", __func__);
return ret;
}
for (i = 0; i < size; i++) {
if (strcmp(configs[i].resolution, res_type) == 0) {
pr_debug("%s: settle count is set to %d\n",
__func__, configs[i].settle_cnt);
ret = configs[i].settle_cnt;
break;
}
}
return ret;
}
static int get_lane_cnt(struct resolution_config *configs,
enum adv7481_resolution size, int w, int h)
{
int i;
int ret = -EINVAL;
char res_type[20] = "RES_MAX";
if (w == 1920 && h == 1080) {
strlcpy(res_type, "RES_1080P", sizeof(res_type));
} else if (w == 1280 && h == 720) {
strlcpy(res_type, "RES_720P", sizeof(res_type));
} else if ((w == 720 && h == 576) || (w == 720 && h == 480)) {
strlcpy(res_type, "RES_576P_480P", sizeof(res_type));
} else {
pr_err("%s: Resolution not supported\n", __func__);
return ret;
}
for (i = 0; i < size; i++) {
if (strcmp(configs[i].resolution, res_type) == 0) {
pr_debug("%s: lane count is set to %d\n",
__func__, configs[i].lane_cnt);
ret = configs[i].lane_cnt;
break;
}
}
return ret;
}
static int adv7481_get_hdmi_timings(struct adv7481_state *state, static int adv7481_get_hdmi_timings(struct adv7481_state *state,
struct adv7481_vid_params *vid_params, struct adv7481_vid_params *vid_params,
struct adv7481_hdmi_params *hdmi_params) struct adv7481_hdmi_params *hdmi_params)
@ -2032,12 +2143,30 @@ static int adv7481_csi_powerup(struct adv7481_state *state,
static int adv7481_set_op_stream(struct adv7481_state *state, bool on) static int adv7481_set_op_stream(struct adv7481_state *state, bool on)
{ {
int ret = 0; int ret = 0;
struct adv7481_vid_params vid_params;
struct adv7481_hdmi_params hdmi_params;
pr_debug("Enter %s: on: %d, a src: %d, b src: %d\n", pr_debug("Enter %s: on: %d, a src: %d, b src: %d\n",
__func__, on, state->csia_src, state->csib_src); __func__, on, state->csia_src, state->csib_src);
memset(&vid_params, 0, sizeof(struct adv7481_vid_params));
memset(&hdmi_params, 0, sizeof(struct adv7481_hdmi_params));
if (on && state->csia_src != ADV7481_IP_NONE) if (on && state->csia_src != ADV7481_IP_NONE)
if (ADV7481_IP_HDMI == state->csia_src) { if (state->csia_src == ADV7481_IP_HDMI) {
state->tx_lanes = ADV7481_MIPI_4LANE; ret = adv7481_get_hdmi_timings(state, &vid_params,
&hdmi_params);
if (ret) {
pr_err("%s: Error %d in adv7481_get_hdmi_timings\n",
__func__, ret);
return -EINVAL;
}
state->tx_lanes = get_lane_cnt(state->res_configs,
RES_MAX, vid_params.act_pix, vid_params.act_lines);
if (state->tx_lanes < 0) {
pr_err("%s: Invalid lane count\n", __func__);
return -EINVAL;
}
ret = adv7481_set_audio_spdif(state, on); ret = adv7481_set_audio_spdif(state, on);
ret |= adv7481_csi_powerup(state, ADV7481_OP_CSIA); ret |= adv7481_csi_powerup(state, ADV7481_OP_CSIA);
} else { } else {
@ -2245,6 +2374,9 @@ static int adv7481_parse_dt(struct platform_device *pdev,
{ {
struct device_node *np = state->dev->of_node; struct device_node *np = state->dev->of_node;
uint32_t i = 0; uint32_t i = 0;
uint32_t lane_count[RES_MAX];
uint32_t settle_count[RES_MAX];
static const char *resolution_array[RES_MAX];
int gpio_count = 0; int gpio_count = 0;
struct resource *adv_addr_res = NULL; struct resource *adv_addr_res = NULL;
int ret = 0; int ret = 0;
@ -2258,6 +2390,36 @@ static int adv7481_parse_dt(struct platform_device *pdev,
goto exit; goto exit;
} }
pr_debug("%s: cci_master: 0x%x\n", __func__, state->cci_master); pr_debug("%s: cci_master: 0x%x\n", __func__, state->cci_master);
/* read CSI data line */
ret = of_property_read_u32_array(np, "tx-lanes",
lane_count, RES_MAX);
if (ret < 0) {
pr_err("%s: failed to read data lane array . ret %d\n",
__func__, ret);
goto exit;
}
/* read settle count */
ret = of_property_read_u32_array(np, "settle-count",
settle_count, RES_MAX);
if (ret < 0) {
pr_err("%s: failed to read settle count . ret %d\n",
__func__, ret);
goto exit;
}
/* read resolution array */
ret = of_property_read_string_array(np, "res-array",
resolution_array, RES_MAX);
if (ret < 0) {
pr_err("%s: failed to read resolution array . ret %d\n",
__func__, ret);
goto exit;
}
for (i = 0; i < RES_MAX; i++) {
state->res_configs[i].lane_cnt = (uint32_t)lane_count[i];
state->res_configs[i].settle_cnt = (uint32_t)settle_count[i];
strlcpy(state->res_configs[i].resolution, resolution_array[i],
sizeof(state->res_configs[i].resolution));
}
adv_addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); adv_addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!adv_addr_res) { if (!adv_addr_res) {
pr_err("%s: failed to read adv7481 resource.\n", __func__); pr_err("%s: failed to read adv7481 resource.\n", __func__);

View file

@ -21,6 +21,7 @@
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/msm_ba.h> #include <media/msm_ba.h>
#include <media/adv7481.h>
#include "msm_ba_internal.h" #include "msm_ba_internal.h"
#include "msm_ba_debug.h" #include "msm_ba_debug.h"
@ -555,6 +556,24 @@ long msm_ba_private_ioctl(void *instance, int cmd, void *arg)
} }
} }
break; break;
case VIDIOC_G_CSI_PARAMS: {
dprintk(BA_DBG, "VIDIOC_G_CSI_PARAMS");
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;
default: default:
dprintk(BA_WARN, "Not a typewriter! Command: 0x%x", cmd); dprintk(BA_WARN, "Not a typewriter! Command: 0x%x", cmd);
rc = -ENOTTY; rc = -ENOTTY;

View file

@ -227,6 +227,14 @@ static int msm_ba_v4l2_g_parm(struct file *file, void *fh,
return 0; return 0;
} }
static long msm_ba_v4l2_private_ioctl(struct file *file, void *fh,
bool valid_prio, unsigned int cmd, void *arg)
{
struct msm_ba_inst *ba_inst = get_ba_inst(file, fh);
return msm_ba_private_ioctl((void *)ba_inst, cmd, (void *)arg);
}
static const struct v4l2_ioctl_ops msm_ba_v4l2_ioctl_ops = { static const struct v4l2_ioctl_ops msm_ba_v4l2_ioctl_ops = {
.vidioc_querycap = msm_ba_v4l2_querycap, .vidioc_querycap = msm_ba_v4l2_querycap,
.vidioc_enum_fmt_vid_cap = msm_ba_v4l2_enum_fmt, .vidioc_enum_fmt_vid_cap = msm_ba_v4l2_enum_fmt,
@ -250,6 +258,7 @@ static const struct v4l2_ioctl_ops msm_ba_v4l2_ioctl_ops = {
.vidioc_enum_output = msm_ba_v4l2_enum_output, .vidioc_enum_output = msm_ba_v4l2_enum_output,
.vidioc_g_output = msm_ba_v4l2_g_output, .vidioc_g_output = msm_ba_v4l2_g_output,
.vidioc_s_output = msm_ba_v4l2_s_output, .vidioc_s_output = msm_ba_v4l2_s_output,
.vidioc_default = msm_ba_v4l2_private_ioctl,
}; };
static unsigned int msm_ba_v4l2_poll(struct file *filp, static unsigned int msm_ba_v4l2_poll(struct file *filp,

View file

@ -1,4 +1,4 @@
/* 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 * 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 * it under the terms of the GNU General Public License version 2 and
@ -14,6 +14,7 @@
#ifndef __ADV7481_H__ #ifndef __ADV7481_H__
#define __ADV7481_H__ #define __ADV7481_H__
#include <uapi/media/msm_ba.h>
/** /**
* adv7481_platform_data * adv7481_platform_data
* structure to pass board specific information to the ADV7481 driver * structure to pass board specific information to the ADV7481 driver

View file

@ -20,3 +20,4 @@ header-y += msmb_ispif.h
header-y += msmb_pproc.h header-y += msmb_pproc.h
header-y += radio-iris.h header-y += radio-iris.h
header-y += radio-iris-commands.h header-y += radio-iris-commands.h
header-y += msm_ba.h

View file

@ -0,0 +1,35 @@
/* Copyright (c) 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
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __UAPI_MSM_BA_H__
#define __UAPI_MSM_BA_H__
#include <linux/videodev2.h>
#include <linux/types.h>
/* CSI control params */
struct csi_ctrl_params {
uint32_t settle_count;
uint32_t lane_count;
};
/* private ioctl structure */
struct msm_ba_v4l2_ioctl_t {
size_t len;
void __user *ptr;
};
/* ADV7481 private ioctls for CSI control params */
#define VIDIOC_G_CSI_PARAMS \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_ba_v4l2_ioctl_t)
#endif