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/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/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#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_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/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 };