summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@quicinc.com>2017-12-30 20:50:13 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-12-30 20:50:13 -0800
commit56d2bd6ac9e06db4131e54ab7cded269ca9522d8 (patch)
tree6c497af7ad045ec00be181b9b53e0c7e6d54fb8c
parent978eecc4fef3be1b20184dadc4d2ad6568c04894 (diff)
parentff2dc69c5a24c1a3e1d27844e6076dee564a836f (diff)
Merge "TvTuner: Add support for TV tuner driver"
-rw-r--r--Documentation/devicetree/bindings/arm/msm/adv7481.txt9
-rw-r--r--Documentation/devicetree/bindings/arm/msm/tv-tuner.txt15
-rw-r--r--Documentation/devicetree/bindings/media/video/msm-ba.txt2
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi6
-rw-r--r--drivers/media/i2c/Kconfig12
-rw-r--r--drivers/media/i2c/Makefile1
-rw-r--r--drivers/media/i2c/adv7481.c166
-rw-r--r--drivers/media/i2c/tvtuner.c333
-rw-r--r--drivers/media/i2c/tvtuner.h23
-rw-r--r--drivers/video/msm/ba/msm_ba.c19
-rw-r--r--drivers/video/msm/ba/msm_ba_common.c2
-rw-r--r--drivers/video/msm/ba/msm_ba_internal.h1
-rw-r--r--drivers/video/msm/ba/msm_v4l2_ba.c9
-rw-r--r--include/media/adv7481.h3
-rw-r--r--include/media/msm_ba.h1
-rw-r--r--include/uapi/media/Kbuild1
-rw-r--r--include/uapi/media/msm_ba.h35
17 files changed, 629 insertions, 9 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/adv7481.txt b/Documentation/devicetree/bindings/arm/msm/adv7481.txt
index 974c0877ac30..d09a83cc0d35 100644
--- a/Documentation/devicetree/bindings/arm/msm/adv7481.txt
+++ b/Documentation/devicetree/bindings/arm/msm/adv7481.txt
@@ -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>;
diff --git a/Documentation/devicetree/bindings/arm/msm/tv-tuner.txt b/Documentation/devicetree/bindings/arm/msm/tv-tuner.txt
new file mode 100644
index 000000000000..480cdfd733e6
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/tv-tuner.txt
@@ -0,0 +1,15 @@
+TVTUNER driver (VIDEO_TVTUNER)
+
+VIDEO_TVTUNER is a sample kernel platform driver that is used to control the tv
+tuner hardware for the capture of Tv tuner received a/v signal.
+
+The devicetree representation of the VIDEO_TVTUNER block should be:
+
+Required properties
+
+- compatible: "qcom,tv-tuner"
+
+Example:
+ qcom,tv-tuner {
+ compatible = "qcom,tv-tuner";
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-ba.txt b/Documentation/devicetree/bindings/media/video/msm-ba.txt
index 9a6fe4d7e8ae..462d69cf9801 100644
--- a/Documentation/devicetree/bindings/media/video/msm-ba.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-ba.txt
@@ -12,7 +12,7 @@ Required properties:
"qcom,name", "qcom,ba-input", "qcom,ba-output", "qcom,sd-name",
"qcom,ba-node" and "qcom,user-type".
Required properties:
-- qcom,type: Input type such as CVBS(0), HDMI(4) etc as defined in BA driver.
+- qcom,type: Input type such as CVBS(0), HDMI(4), TUNER(8) etc as defined in BA driver.
This property is of type u32.
- qcom,name: Name of the input type. This property is of type string.
- qcom,ba-input: BA input id supported by a bridge chip for this profile.
diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
index eb7654c26452..83f0bbe86410 100644
--- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
@@ -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>;
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index ba3287d176af..f7f2f09cc06b 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -233,6 +233,18 @@ config VIDEO_ADV7481
To compile this driver as a module, choose M here: the
module will be called adv7481.
+config VIDEO_TVTUNER
+ tristate "Analog Tv Tuner driver"
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ Support for the Dummy TV Tuner.
+
+ This is a Dummy TV Tuner Driver to Validate call flow
+ from tv_input_test unit-test app.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tv-tuner.
+
config VIDEO_BT819
tristate "BT819A VideoStream decoder"
depends on VIDEO_V4L2 && I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index ade6ecaad80d..eec9e870755d 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -39,6 +39,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
endif
obj-$(CONFIG_VIDEO_ADV7481) += adv7481.o
+obj-$(CONFIG_VIDEO_TVTUNER) += tvtuner.o
obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c
index 19c237e8a286..a14f13c44a36 100644
--- a/drivers/media/i2c/adv7481.c
+++ b/drivers/media/i2c/adv7481.c
@@ -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__);
diff --git a/drivers/media/i2c/tvtuner.c b/drivers/media/i2c/tvtuner.c
new file mode 100644
index 000000000000..357491209814
--- /dev/null
+++ b/drivers/media/i2c/tvtuner.c
@@ -0,0 +1,333 @@
+/* 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/media.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+
+#include <media/msm_ba.h>
+
+#include "tvtuner.h"
+
+#define DRIVER_NAME "tv-tuner"
+
+struct Tvtuner_state {
+ struct device *dev;
+
+ /* V4L2 Data */
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler ctrl_hdl;
+ struct v4l2_dv_timings timings;
+
+ /* media entity controls */
+ struct media_pad pad;
+
+ struct mutex mutex;
+};
+
+
+/* Initialize Tvtuner I2C Settings */
+static int Tvtuner_dev_init(struct Tvtuner_state *state)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner dev init is started\n");
+ return ret;
+}
+
+/* Initialize Tvtuner hardware */
+static int Tvtuner_hw_init(struct Tvtuner_state *state)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner hw init is started\n");
+ return ret;
+}
+
+static int Tvtuner_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner set control is started id = 0x%x\n", ctrl->id);
+ return ret;
+}
+
+static int Tvtuner_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ int ret = 0;
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->width = 1280;
+ fmt->height = 720;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ TUNER_DEBUG("tv_tuner get mbus format is started\n");
+ return ret;
+}
+
+static int Tvtuner_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner get frame interval is started\n");
+ return ret;
+}
+
+static int Tvtuner_s_routing(struct v4l2_subdev *sd, u32 input,
+ u32 output, u32 config)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner s_routing is started\n");
+ return ret;
+}
+
+static int Tvtuner_query_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner query dv timings is started\n");
+ return ret;
+}
+
+static int Tvtuner_query_sd_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner query SD input is started\n");
+ return ret;
+}
+
+static int Tvtuner_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ int ret = 0;
+ *status = 1;
+
+ TUNER_DEBUG("tv_tuner get input status is started\n");
+ return ret;
+}
+
+static int Tvtuner_s_stream(struct v4l2_subdev *sd, int on)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("tv_tuner start stream is started\n");
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops Tvtuner_video_ops = {
+ .s_routing = Tvtuner_s_routing,
+ .g_frame_interval = Tvtuner_g_frame_interval,
+ .querystd = Tvtuner_query_sd_std,
+ .g_dv_timings = Tvtuner_query_dv_timings,
+ .g_input_status = Tvtuner_g_input_status,
+ .s_stream = Tvtuner_s_stream,
+};
+
+
+static const struct v4l2_ctrl_ops Tvtuner_ctrl_ops = {
+ .s_ctrl = Tvtuner_s_ctrl,
+};
+
+static const struct v4l2_subdev_pad_ops Tvtuner_pad_ops = {
+ .get_fmt = Tvtuner_get_fmt,
+};
+
+static const struct v4l2_subdev_ops Tvtuner_ops = {
+ .video = &Tvtuner_video_ops,
+ .pad = &Tvtuner_pad_ops,
+};
+
+static int Tvtuner_init_v4l2_controls(struct Tvtuner_state *state)
+{
+ int ret = 0;
+
+ TUNER_DEBUG("%s: Exit with ret: %d\n", __func__, ret);
+ return ret;
+}
+
+static int Tvtuner_parse_dt(struct platform_device *pdev,
+ struct Tvtuner_state *state)
+{
+
+ int ret = 0;
+
+ TUNER_DEBUG("%s: tvtuner parse dt called\n", __func__);
+ return ret;
+}
+
+static const struct of_device_id Tvtuner_id[] = {
+ { .compatible = "qcom,tv-tuner", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, Tvtuner_id);
+
+static int Tvtuner_probe(struct platform_device *pdev)
+{
+ struct Tvtuner_state *state;
+ const struct of_device_id *device_id;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ device_id = of_match_device(Tvtuner_id, &pdev->dev);
+ if (!device_id) {
+ TUNER_DEBUG("%s: device_id is NULL\n", __func__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* Create Tvtuner State */
+ state = devm_kzalloc(&pdev->dev,
+ sizeof(struct Tvtuner_state), GFP_KERNEL);
+ if (state == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ platform_set_drvdata(pdev, state);
+ state->dev = &pdev->dev;
+
+ mutex_init(&state->mutex);
+ ret = Tvtuner_parse_dt(pdev, state);
+ if (ret < 0) {
+ TUNER_ERROR("Error parsing dt tree\n");
+ goto err_mem_free;
+ }
+
+ /* Configure and Register V4L2 Sub-device */
+ sd = &state->sd;
+ v4l2_subdev_init(sd, &Tvtuner_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;
+
+ /* Register as Media Entity */
+ state->pad.flags = MEDIA_PAD_FL_SOURCE;
+ state->sd.entity.flags |= (unsigned long)MEDIA_ENT_T_V4L2_SUBDEV;
+ ret = media_entity_init(&state->sd.entity, 1, &state->pad, 0);
+ if (ret) {
+ ret = -EIO;
+ TUNER_ERROR("%s(%d): Media entity init failed\n",
+ __func__, __LINE__);
+ goto err_media_entity;
+ }
+
+ /* Initialize HW Config */
+ ret = Tvtuner_hw_init(state);
+ if (ret) {
+ ret = -EIO;
+ TUNER_ERROR("%s: HW Initialisation Failed\n", __func__);
+ goto err_media_entity;
+ }
+
+ ret = Tvtuner_init_v4l2_controls(state);
+ if (ret) {
+ TUNER_ERROR("%s: V4L2 Controls Initialisation Failed %d\n",
+ __func__, ret);
+ }
+
+ /* Initialize SW Init Settings and I2C sub maps */
+ ret = Tvtuner_dev_init(state);
+ if (ret) {
+ ret = -EIO;
+ TUNER_ERROR("%s(%d): SW Initialisation Failed\n",
+ __func__, __LINE__);
+ goto err_media_entity;
+ }
+
+ /* BA registration */
+ TUNER_DEBUG(" register msm-ba driver to tv_tuner");
+ ret = msm_ba_register_subdev_node(sd);
+ if (ret) {
+ ret = -EIO;
+ TUNER_DEBUG("%s: BA init failed\n", __func__);
+ goto err_media_entity;
+ }
+ TUNER_DEBUG("Probe of tvtuner successful!\n");
+
+ return ret;
+
+err_media_entity:
+ media_entity_cleanup(&sd->entity);
+
+err_mem_free:
+ devm_kfree(&pdev->dev, state);
+
+err:
+ return ret;
+}
+
+static int Tvtuner_remove(struct platform_device *pdev)
+{
+ struct Tvtuner_state *state = platform_get_drvdata(pdev);
+
+ 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);
+
+ mutex_destroy(&state->mutex);
+ devm_kfree(&pdev->dev, state);
+
+ return 0;
+}
+
+static int Tvtuner_suspend(struct device *dev)
+{
+ TUNER_DEBUG("tv_tuner driver is in suspend state\n");
+ return 0;
+}
+
+static int Tvtuner_resume(struct device *dev)
+{
+ TUNER_DEBUG("tv_tuner driver is in resume state\n");
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(Tvtuner_pm_ops, Tvtuner_suspend, Tvtuner_resume);
+#define TVTUNER_PM_OPS (&Tvtuner_pm_ops)
+
+static struct platform_driver Tvtuner_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tv-tuner",
+ .of_match_table = Tvtuner_id,
+ .pm = TVTUNER_PM_OPS,
+ },
+ .probe = Tvtuner_probe,
+ .remove = Tvtuner_remove,
+};
+
+module_driver(Tvtuner_driver, platform_driver_register,
+ platform_driver_unregister);
+
+MODULE_DESCRIPTION(" TV TUNER Test driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/tvtuner.h b/drivers/media/i2c/tvtuner.h
new file mode 100644
index 000000000000..9a3c15df5936
--- /dev/null
+++ b/drivers/media/i2c/tvtuner.h
@@ -0,0 +1,23 @@
+/*
+ * 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 __TV_TUNER_H__
+#define __TV_TUNER_H__
+
+#define PREFIX "tv_tuner: "
+
+#define TUNER_DEBUG(str, args...) pr_debug(PREFIX str, ##args)
+#define TUNER_ERROR(str, args...) pr_err(PREFIX str, ##args)
+
+#endif
diff --git a/drivers/video/msm/ba/msm_ba.c b/drivers/video/msm/ba/msm_ba.c
index 4200b8f20073..566cb634ae8f 100644
--- a/drivers/video/msm/ba/msm_ba.c
+++ b/drivers/video/msm/ba/msm_ba.c
@@ -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;
diff --git a/drivers/video/msm/ba/msm_ba_common.c b/drivers/video/msm/ba/msm_ba_common.c
index 1306fca46652..e70c264b9765 100644
--- a/drivers/video/msm/ba/msm_ba_common.c
+++ b/drivers/video/msm/ba/msm_ba_common.c
@@ -191,8 +191,6 @@ void msm_ba_add_inputs(struct v4l2_subdev *sd)
int dev_id = 0;
dev_ctxt = get_ba_dev();
- if (!list_empty(&dev_ctxt->inputs))
- start_index = dev_ctxt->num_inputs;
msm_ba_inp_cfg = dev_ctxt->msm_ba_inp_cfg;
dev_id = msm_ba_inp_cfg[start_index].ba_out;
diff --git a/drivers/video/msm/ba/msm_ba_internal.h b/drivers/video/msm/ba/msm_ba_internal.h
index bd52e8e400ce..bb90a3198728 100644
--- a/drivers/video/msm/ba/msm_ba_internal.h
+++ b/drivers/video/msm/ba/msm_ba_internal.h
@@ -106,6 +106,7 @@ enum msm_ba_ip_type {
BA_INPUT_MHL,
BA_INPUT_DVI,
BA_INPUT_TTL,
+ BA_INPUT_TV_TUNER,
BA_INPUT_MAX = 0xffffffff
};
diff --git a/drivers/video/msm/ba/msm_v4l2_ba.c b/drivers/video/msm/ba/msm_v4l2_ba.c
index 89fc08dd3c33..c50d02292398 100644
--- a/drivers/video/msm/ba/msm_v4l2_ba.c
+++ b/drivers/video/msm/ba/msm_v4l2_ba.c
@@ -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,
diff --git a/include/media/adv7481.h b/include/media/adv7481.h
index 80b8ee879ea4..fa5466197889 100644
--- a/include/media/adv7481.h
+++ b/include/media/adv7481.h
@@ -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
diff --git a/include/media/msm_ba.h b/include/media/msm_ba.h
index d630e441590f..4bab36ade468 100644
--- a/include/media/msm_ba.h
+++ b/include/media/msm_ba.h
@@ -35,6 +35,7 @@ enum msm_ba_ip {
BA_IP_HDMI_1,
BA_IP_MHL_1,
BA_IP_TTL,
+ BA_IP_TV_TUNER,
BA_IP_MAX = 0xffffffff
};
diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild
index 421c65d8a901..640002326ace 100644
--- a/include/uapi/media/Kbuild
+++ b/include/uapi/media/Kbuild
@@ -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
diff --git a/include/uapi/media/msm_ba.h b/include/uapi/media/msm_ba.h
new file mode 100644
index 000000000000..587d14652f3f
--- /dev/null
+++ b/include/uapi/media/msm_ba.h
@@ -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