static int hdmi_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_hdmi_platdata *pdata = pdev->dev.platform_data; struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdev = sd_to_hdmi_dev(sd); int ret = 0; dev_dbg(dev, "%s start\n", __func__); /* HDMI PHY power off * HDMI PHY is on as default configuration * So, HDMI PHY must be turned off if it's not used */ if (pdata->hdmiphy_enable) pdata->hdmiphy_enable(pdev, 1); ret = v4l2_subdev_call(hdev->phy_sd, core, s_power, 0); if (ret) dev_err(dev, "failed to turn off hdmiphy\n"); if (pdata->hdmiphy_enable) pdata->hdmiphy_enable(pdev, 0); return ret; }
static int hdmi_s_power(struct v4l2_subdev *sd, int on) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); int ret = 0; /* If runtime PM is not implemented, hdmi_runtime_resume * and hdmi_runtime_suspend functions are directly called. */ if (on) { #ifdef CONFIG_PM_RUNTIME ret = pm_runtime_get_sync(hdev->dev); #else hdmi_runtime_resume(hdev->dev); #endif } else { #ifdef CONFIG_PM_RUNTIME ret = pm_runtime_put_sync(hdev->dev); #else hdmi_runtime_suspend(hdev->dev); #endif } /* only values < 0 indicate errors */ return IS_ERR_VALUE(ret) ? ret : 0; }
int hdmi_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; switch (ctrl->id) { case V4L2_CID_TV_GET_DVI_MODE: ctrl->value = hdev->dvi_mode; break; case V4L2_CID_TV_HPD_STATUS: ctrl->value = switch_get_state(&hdev->hpd_switch); break; case V4L2_CID_TV_HDMI_STATUS: ctrl->value = (hdev->streaming | switch_get_state(&hdev->hpd_switch)); break; case V4L2_CID_TV_MAX_AUDIO_CHANNELS: ctrl->value = edid_max_audio_channels(hdev); break; case V4L2_CID_TV_SOURCE_PHY_ADDR: ctrl->value = edid_source_phy_addr(hdev); break; default: dev_err(dev, "invalid control id\n"); return -EINVAL; } return 0; }
static int hdmi_runtime_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct hdmi_resources *res = &hdev->res; int ret = 0; dev_dbg(dev, "%s\n", __func__); hdmi_resource_poweron(&hdev->res); hdmi_phy_sw_reset(hdev); ret = v4l2_subdev_call(hdev->phy_sd, core, s_power, 1); if (ret) { dev_err(dev, "failed to turn on hdmiphy\n"); goto fail; } ret = hdmi_conf_apply(hdev); if (ret) goto fail; dev_dbg(dev, "poweron succeed\n"); return 0; fail: clk_disable(res->sclk_hdmi); v4l2_subdev_call(hdev->phy_sd, core, s_power, 0); clk_disable(res->hdmiphy); dev_err(dev, "poweron failed\n"); return ret; }
static int hdmi_g_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset) { memset(preset, 0, sizeof(*preset)); preset->preset = sd_to_hdmi_dev(sd)->cur_preset; return 0; }
static int hdmi_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_hdmi_platdata *pdata = pdev->dev.platform_data; struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct hdmi_resources *res = &hdev->res; dev_dbg(dev, "%s\n", __func__); if (hdev->probe_state == HDMI_PROBING) { hdev->probe_state = HDMI_PROBED; return 0; } /* HDMI PHY off sequence * LINK off -> PHY off -> HDMI_PHY_CONTROL disable */ if (is_ip_ver_5a || is_ip_ver_5s) hdmiphy_set_power(hdev, 0); /* turn clocks off */ clk_disable(res->sclk_hdmi); if (is_ip_ver_5g) v4l2_subdev_call(hdev->phy_sd, core, s_power, 0); /* power-off hdmiphy */ if (pdata->hdmiphy_enable) pdata->hdmiphy_enable(pdev, 0); return 0; }
static int hdmi_s_power(struct v4l2_subdev *sd, int on) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); /* If runtime PM is not implemented, hdmi_runtime_resume * and hdmi_runtime_suspend functions are directly called. */ #ifdef CONFIG_PM_RUNTIME int ret; if (on) { clk_enable(hdev->res.hdmi); hdmi_hpd_enable(hdev, 1); ret = pm_runtime_get_sync(hdev->dev); set_internal_hpd_int(hdev); } else { hdmi_hpd_enable(hdev, 0); set_external_hpd_int(hdev); ret = pm_runtime_put_sync(hdev->dev); clk_disable(hdev->res.hdmi); } /* only values < 0 indicate errors */ return IS_ERR_VALUE(ret) ? ret : 0; #else if (on) hdmi_runtime_resume(hdev->dev); else hdmi_runtime_suspend(hdev->dev); return 0; #endif }
int hdmi_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; dev_info(dev, "S_CTRL is not applied yet.\n"); return 0; }
int hdmi_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; int ret = 0; dev_dbg(dev, "%s start\n", __func__); switch (ctrl->id) { case V4L2_CID_TV_SET_DVI_MODE: hdev->dvi_mode = ctrl->value; break; case V4L2_CID_TV_SET_ASPECT_RATIO: hdev->aspect = ctrl->value; break; case V4L2_CID_TV_ENABLE_HDMI_AUDIO: mutex_lock(&hdev->mutex); hdev->audio_enable = !!ctrl->value; if (is_hdmi_streaming(hdev)) { hdmi_set_infoframe(hdev); hdmi_audio_enable(hdev, hdev->audio_enable); } mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_NUM_CHANNELS: mutex_lock(&hdev->mutex); hdmi_audio_information(hdev, ctrl->value); if (is_hdmi_streaming(hdev)) { hdmi_audio_enable(hdev, 0); hdmi_set_infoframe(hdev); hdmi_reg_i2s_audio_init(hdev); hdmi_audio_enable(hdev, 1); } mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_COLOR_RANGE: hdev->color_range = ctrl->value; break; case V4L2_CID_TV_HDCP_ENABLE: hdev->hdcp_info.hdcp_enable = ctrl->value; dev_dbg(hdev->dev, "HDCP %s\n", ctrl->value ? "enable" : "disable"); #ifdef CONFIG_SEC_MHL_HDCP hdev->hdcp_info.hdcp_enable = false; /*MHL8240 control the HDCP*/ dev_dbg(hdev->dev, "MHL control the HDCP\n"); #endif break; default: dev_err(dev, "invalid control id\n"); ret = -EINVAL; break; } return ret; }
static int hdmi_s_stream(struct v4l2_subdev *sd, int enable) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; //dev_dbg(dev, "%s(%d)\n", __func__, enable); if (enable) return hdmi_streamon(hdev); return hdmi_streamoff(hdev); }
static int hdmi_enum_dv_presets(struct v4l2_subdev *sd, struct v4l2_dv_enum_preset *enum_preset) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); u32 preset = edid_enum_presets(hdev, enum_preset->index); if (preset == V4L2_DV_INVALID) return -EINVAL; return v4l_fill_dv_preset_info(preset, enum_preset); }
int hdmi_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; int ret = 0; dev_dbg(dev, "%s start\n", __func__); switch (ctrl->id) { case V4L2_CID_TV_SET_DVI_MODE: hdev->dvi_mode = ctrl->value; break; case V4L2_CID_TV_SET_ASPECT_RATIO: hdev->aspect = ctrl->value; break; case V4L2_CID_TV_ENABLE_HDMI_AUDIO: mutex_lock(&hdev->mutex); hdev->audio_enable = !!ctrl->value; if (is_hdmi_streaming(hdev)) { hdmi_set_infoframe(hdev); hdmi_audio_enable(hdev, hdev->audio_enable); } mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_NUM_CHANNELS: mutex_lock(&hdev->mutex); if ((ctrl->value == 2) || (ctrl->value == 6) || (ctrl->value == 8)) { hdev->audio_channel_count = ctrl->value; } else { dev_err(dev, "invalid channel count\n"); hdev->audio_channel_count = 2; } if (is_hdmi_streaming(hdev)) hdmi_set_infoframe(hdev); mutex_unlock(&hdev->mutex); break; case V4L2_CID_TV_SET_COLOR_RANGE: hdev->color_range = ctrl->value; break; case V4L2_CID_TV_HDCP_ENABLE: hdev->hdcp_info.hdcp_enable = ctrl->value; dev_dbg(hdev->dev, "HDCP %s\n", ctrl->value ? "enable" : "disable"); break; default: dev_err(dev, "invalid control id\n"); ret = -EINVAL; break; } return ret; }
static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; dev_dbg(dev, "%s\n", __func__); if (!hdev->cur_conf) return -EINVAL; *fmt = hdev->cur_conf->mbus_fmt; return 0; }
static int hdmi_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_hdmi_platdata *pdata = pdev->dev.platform_data; struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct hdmi_resources *res = &hdev->res; int ret = 0; dev_dbg(dev, "%s\n", __func__); if (hdev->probe_state == HDMI_PROBING) return 0; /* power-on hdmiphy */ if (pdata->hdmiphy_enable) pdata->hdmiphy_enable(pdev, 1); clk_enable(res->sclk_hdmi); if (is_ip_ver_5a || is_ip_ver_5s) { hdmiphy_set_power(hdev, 1); } else { ret = v4l2_subdev_call(hdev->phy_sd, core, s_power, 1); if (ret) { dev_err(dev, "failed to turn on hdmiphy\n"); goto fail; } } hdmi_sw_reset(hdev); hdmi_phy_sw_reset(hdev); ret = hdmi_conf_apply(hdev); if (ret) goto fail; dev_dbg(dev, "poweron succeed\n"); return 0; fail: clk_disable(res->sclk_hdmi); v4l2_subdev_call(hdev->phy_sd, core, s_power, 0); if (pdata->hdmiphy_enable) pdata->hdmiphy_enable(pdev, 0); dev_err(dev, "poweron failed\n"); return ret; }
static int hdmi_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; dev_dbg(dev, "%s\n", __func__); if (fmt->code == V4L2_MBUS_FMT_YUV8_1X24) hdev->output_fmt = HDMI_OUTPUT_YUV444; else hdev->output_fmt = HDMI_OUTPUT_RGB888; return 0; }
static int hdmi_s_power(struct v4l2_subdev *sd, int on) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); int ret = 0; /* If runtime PM is not implemented, hdmi_runtime_resume * and hdmi_runtime_suspend functions are directly called. */ if (on) { clk_enable(hdev->res.hdmi); #ifdef CONFIG_PM_RUNTIME ret = pm_runtime_get_sync(hdev->dev); #else hdmi_runtime_resume(hdev->dev); #endif disable_irq(hdev->ext_irq); cancel_delayed_work_sync(&hdev->hpd_work_ext); s5p_v4l2_int_src_hdmi_hpd(); hdmi_hpd_enable(hdev, 1); hdmi_hpd_clear_int(hdev); enable_irq(hdev->int_irq); dev_info(hdev->dev, "HDMI interrupt changed to internal\n"); } else { cancel_work_sync(&hdev->work); hdmi_hpd_enable(hdev, 0); disable_irq(hdev->int_irq); cancel_work_sync(&hdev->hpd_work); s5p_v4l2_int_src_ext_hpd(); enable_irq(hdev->ext_irq); dev_info(hdev->dev, "HDMI interrupt changed to external\n"); #ifdef CONFIG_PM_RUNTIME ret = pm_runtime_put_sync(hdev->dev); #else hdmi_runtime_suspend(hdev->dev); #endif clk_disable(hdev->res.hdmi); } /* only values < 0 indicate errors */ return IS_ERR_VALUE(ret) ? ret : 0; }
int hdmi_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; if (!pm_runtime_suspended(hdev->dev) && !hdev->hpd_user_checked) ctrl->value = hdmi_hpd_status(hdev); else ctrl->value = atomic_read(&hdev->hpd_state); dev_dbg(dev, "HDMI cable is %s\n", ctrl->value ? "connected" : "disconnected"); return 0; }
static int hdmi_s_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; const struct hdmi_preset_conf *conf; conf = hdmi_preset2conf(preset->preset); if (conf == NULL) { dev_err(dev, "preset (%u) not supported\n", preset->preset); return -EINVAL; } hdev->cur_conf = conf; hdev->cur_preset = preset->preset; return 0; }
static int __devexit hdmi_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdmi_dev = sd_to_hdmi_dev(sd); pm_runtime_disable(dev); clk_disable(hdmi_dev->res.hdmi); v4l2_device_unregister(&hdmi_dev->v4l2_dev); disable_irq(hdmi_dev->curr_irq); free_irq(hdmi_dev->curr_irq, hdmi_dev); iounmap(hdmi_dev->regs); hdmi_resources_cleanup(hdmi_dev); flush_workqueue(hdmi_dev->hdcp_wq); destroy_workqueue(hdmi_dev->hdcp_wq); kfree(hdmi_dev); dev_info(dev, "remove sucessful\n"); return 0; }
static int hdmi_runtime_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct hdmi_resources *res = &hdev->res; dev_dbg(dev, "%s\n", __func__); /* HDMI PHY off sequence * LINK off -> PHY off -> HDMI_PHY_CONTROL disable */ /* turn clocks off */ clk_disable(res->sclk_hdmi); v4l2_subdev_call(hdev->phy_sd, core, s_power, 0); /* power-off hdmiphy */ clk_disable(res->hdmiphy); return 0; }
static int hdmi_s_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; hdev->cur_conf = hdmi_timing2conf(timings); if (hdev->cur_conf == NULL) { dev_err(dev, "timings not supported\n"); return -EINVAL; } hdev->cur_timings = *timings; if (hdev->streaming == HDMI_STREAMING) { hdmi_streamoff(hdev); hdmi_s_power(sd, 0); hdev->streaming = HDMI_STOP; } return 0; }
static int hdmi_runtime_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct hdmi_resources *res = &hdev->res; int ret = 0; dev_dbg(dev, "%s\n", __func__); hdmiphy_set_isolation(hdev, 1); hdmiphy_set_conf(hdev, 1); clk_prepare_enable(res->hdmiphy); clk_prepare_enable(res->hdmi); hdmiphy_set_power(hdev, 1); hdmi_clock_set(hdev, 1); hdmi_sw_reset(hdev); hdmi_phy_sw_reset(hdev); ret = hdmi_conf_apply(hdev); if (ret) goto fail; dev_dbg(dev, "poweron succeed\n"); return 0; fail: clk_disable_unprepare(res->hdmi); clk_disable_unprepare(res->hdmiphy); hdmiphy_set_isolation(hdev, 0); dev_err(dev, "poweron failed\n"); return ret; }
static int hdmi_s_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; const struct hdmi_preset_conf *conf; conf = hdmi_preset2conf(preset->preset); if (conf == NULL) { dev_err(dev, "preset (%u) not supported\n", preset->preset); return -EINVAL; } hdev->cur_conf = conf; hdev->cur_preset = preset->preset; if (hdev->streaming == HDMI_STREAMING) { hdmi_streamoff(hdev); hdmi_s_power(sd, 0); hdev->streaming = HDMI_STOP; } return 0; }
static int hdmi_runtime_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct hdmi_resources *res = &hdev->res; dev_dbg(dev, "%s\n", __func__); hdmi_clock_set(hdev, 0); /* HDMI PHY off sequence * LINK off -> PHY off -> isolation disable */ hdmiphy_set_power(hdev, 0); /* turn clocks off */ clk_disable_unprepare(res->hdmi); clk_disable_unprepare(res->hdmiphy); hdmiphy_set_conf(hdev, 0); hdmiphy_set_isolation(hdev, 0); return 0; }
int hdmi_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); struct device *dev = hdev->dev; int ret = 0; switch (ctrl->id) { case V4L2_CID_TV_HPD_STATUS: ctrl->value = switch_get_state(&hdev->hpd_switch); break; case V4L2_CID_TV_GET_DVI_MODE: ctrl->value = hdev->dvi_mode; break; case V4L2_CID_TV_MAX_AUDIO_CHANNELS: ctrl->value = edid_max_audio_channels(hdev); break; default: dev_err(dev, "invalid control id\n"); ret = -EINVAL; break; } return ret; }
static int hdmi_g_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { *timings = sd_to_hdmi_dev(sd)->cur_timings; return 0; }