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:
parent
8ed108c977
commit
720aa591f4
8 changed files with 242 additions and 6 deletions
|
@ -15,6 +15,12 @@ Required properties
|
|||
interrupt 1, interrupt 2 and interrupt 3.
|
||||
- cam_vdig-supply: Should contain regulator to be used for the digital
|
||||
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_vana-supply: Should contain regulator from which analog voltage
|
||||
is supplied.
|
||||
|
@ -35,6 +41,9 @@ Example:
|
|||
compatible = "qcom,adv7481";
|
||||
reg = <0x70 0xff>;
|
||||
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: */
|
||||
cam_vio-supply = <&pm8994_lvs1>;
|
||||
cam_vana-supply = <&pm8994_l17>;
|
||||
|
|
|
@ -1137,9 +1137,9 @@
|
|||
compatible = "qcom,adv7481";
|
||||
reg = <0x70 0xff>;
|
||||
cam_vdig-supply = <&pm8994_s3>;
|
||||
tx_lanes = <4 2 1>;
|
||||
settle_count = <16 16 16>;
|
||||
res_array = "RES_1080P", "RES_720P", "RES_576P_480P";
|
||||
tx-lanes = <4 2 1>;
|
||||
settle-count = <16 16 16>;
|
||||
res-array = "RES_1080P", "RES_720P", "RES_576P_480P";
|
||||
/* Cameras powered by PMIC: */
|
||||
cam_vio-supply = <&pm8994_lvs1>;
|
||||
cam_vana-supply = <&pm8994_l17>;
|
||||
|
|
|
@ -75,6 +75,19 @@ enum adv7481_gpio_t {
|
|||
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 device *dev;
|
||||
|
||||
|
@ -125,6 +138,9 @@ struct adv7481_state {
|
|||
int csib_src;
|
||||
int mode;
|
||||
|
||||
/* resolution configuration */
|
||||
struct resolution_config res_configs[RES_MAX];
|
||||
|
||||
/* CSI configuration data */
|
||||
int tx_auto_params;
|
||||
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 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)
|
||||
{
|
||||
|
@ -1005,11 +1028,18 @@ static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
|
|||
{
|
||||
struct adv7481_state *state = to_state(sd);
|
||||
int *ret_val = arg;
|
||||
struct msm_ba_v4l2_ioctl_t adv_arg = *(struct msm_ba_v4l2_ioctl_t *)arg;
|
||||
long ret = 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);
|
||||
|
||||
memset(&vid_params, 0, sizeof(struct adv7481_vid_params));
|
||||
memset(&hdmi_params, 0, sizeof(struct adv7481_hdmi_params));
|
||||
|
||||
if (!sd)
|
||||
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:
|
||||
ret = adv7481_cec_powerup(state, arg);
|
||||
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:
|
||||
pr_err("Not a typewriter! Command: 0x%x", cmd);
|
||||
ret = -ENOTTY;
|
||||
|
@ -1541,6 +1593,65 @@ static bool adv7481_is_timing_locked(struct adv7481_state *state)
|
|||
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,
|
||||
struct adv7481_vid_params *vid_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)
|
||||
{
|
||||
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",
|
||||
__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 (ADV7481_IP_HDMI == state->csia_src) {
|
||||
state->tx_lanes = ADV7481_MIPI_4LANE;
|
||||
if (state->csia_src == ADV7481_IP_HDMI) {
|
||||
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_csi_powerup(state, ADV7481_OP_CSIA);
|
||||
} else {
|
||||
|
@ -2245,6 +2374,9 @@ static int adv7481_parse_dt(struct platform_device *pdev,
|
|||
{
|
||||
struct device_node *np = state->dev->of_node;
|
||||
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;
|
||||
struct resource *adv_addr_res = NULL;
|
||||
int ret = 0;
|
||||
|
@ -2258,6 +2390,36 @@ static int adv7481_parse_dt(struct platform_device *pdev,
|
|||
goto exit;
|
||||
}
|
||||
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);
|
||||
if (!adv_addr_res) {
|
||||
pr_err("%s: failed to read adv7481 resource.\n", __func__);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/msm_ba.h>
|
||||
#include <media/adv7481.h>
|
||||
|
||||
#include "msm_ba_internal.h"
|
||||
#include "msm_ba_debug.h"
|
||||
|
@ -555,6 +556,24 @@ long msm_ba_private_ioctl(void *instance, int cmd, void *arg)
|
|||
}
|
||||
}
|
||||
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:
|
||||
dprintk(BA_WARN, "Not a typewriter! Command: 0x%x", cmd);
|
||||
rc = -ENOTTY;
|
||||
|
|
|
@ -227,6 +227,14 @@ static int msm_ba_v4l2_g_parm(struct file *file, void *fh,
|
|||
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 = {
|
||||
.vidioc_querycap = msm_ba_v4l2_querycap,
|
||||
.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_g_output = msm_ba_v4l2_g_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,
|
||||
|
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -14,6 +14,7 @@
|
|||
#ifndef __ADV7481_H__
|
||||
#define __ADV7481_H__
|
||||
|
||||
#include <uapi/media/msm_ba.h>
|
||||
/**
|
||||
* adv7481_platform_data
|
||||
* structure to pass board specific information to the ADV7481 driver
|
||||
|
|
|
@ -20,3 +20,4 @@ header-y += msmb_ispif.h
|
|||
header-y += msmb_pproc.h
|
||||
header-y += radio-iris.h
|
||||
header-y += radio-iris-commands.h
|
||||
header-y += msm_ba.h
|
||||
|
|
35
include/uapi/media/msm_ba.h
Normal file
35
include/uapi/media/msm_ba.h
Normal 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
|
Loading…
Add table
Reference in a new issue