diff options
| author | Linux Build Service Account <lnxbuild@quicinc.com> | 2017-12-30 20:50:13 -0800 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-12-30 20:50:13 -0800 |
| commit | 56d2bd6ac9e06db4131e54ab7cded269ca9522d8 (patch) | |
| tree | 6c497af7ad045ec00be181b9b53e0c7e6d54fb8c | |
| parent | 978eecc4fef3be1b20184dadc4d2ad6568c04894 (diff) | |
| parent | ff2dc69c5a24c1a3e1d27844e6076dee564a836f (diff) | |
Merge "TvTuner: Add support for TV tuner driver"
| -rw-r--r-- | Documentation/devicetree/bindings/arm/msm/adv7481.txt | 9 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/arm/msm/tv-tuner.txt | 15 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/media/video/msm-ba.txt | 2 | ||||
| -rw-r--r-- | arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi | 6 | ||||
| -rw-r--r-- | drivers/media/i2c/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/media/i2c/Makefile | 1 | ||||
| -rw-r--r-- | drivers/media/i2c/adv7481.c | 166 | ||||
| -rw-r--r-- | drivers/media/i2c/tvtuner.c | 333 | ||||
| -rw-r--r-- | drivers/media/i2c/tvtuner.h | 23 | ||||
| -rw-r--r-- | drivers/video/msm/ba/msm_ba.c | 19 | ||||
| -rw-r--r-- | drivers/video/msm/ba/msm_ba_common.c | 2 | ||||
| -rw-r--r-- | drivers/video/msm/ba/msm_ba_internal.h | 1 | ||||
| -rw-r--r-- | drivers/video/msm/ba/msm_v4l2_ba.c | 9 | ||||
| -rw-r--r-- | include/media/adv7481.h | 3 | ||||
| -rw-r--r-- | include/media/msm_ba.h | 1 | ||||
| -rw-r--r-- | include/uapi/media/Kbuild | 1 | ||||
| -rw-r--r-- | include/uapi/media/msm_ba.h | 35 |
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 |
