diff options
Diffstat (limited to 'drivers/media/platform/s5p-tv')
| -rw-r--r-- | drivers/media/platform/s5p-tv/hdmi_drv.c | 17 | ||||
| -rw-r--r-- | drivers/media/platform/s5p-tv/hdmiphy_drv.c | 9 | ||||
| -rw-r--r-- | drivers/media/platform/s5p-tv/mixer.h | 2 | ||||
| -rw-r--r-- | drivers/media/platform/s5p-tv/mixer_drv.c | 34 | ||||
| -rw-r--r-- | drivers/media/platform/s5p-tv/mixer_grp_layer.c | 2 | ||||
| -rw-r--r-- | drivers/media/platform/s5p-tv/mixer_video.c | 21 | ||||
| -rw-r--r-- | drivers/media/platform/s5p-tv/mixer_vp_layer.c | 2 | ||||
| -rw-r--r-- | drivers/media/platform/s5p-tv/sdo_drv.c | 39 |
8 files changed, 93 insertions, 33 deletions
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 1b34c362985..754740f4b67 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -37,6 +37,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> +#include <media/v4l2-dv-timings.h> #include "regs-hdmi.h" @@ -625,7 +626,7 @@ static int hdmi_s_dv_timings(struct v4l2_subdev *sd, int i; for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++) - if (v4l_match_dv_timings(&hdmi_timings[i].dv_timings, + if (v4l2_match_dv_timings(&hdmi_timings[i].dv_timings, timings, 0)) break; if (i == ARRAY_SIZE(hdmi_timings)) { @@ -673,6 +674,8 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, static int hdmi_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings) { + if (timings->pad != 0) + return -EINVAL; if (timings->index >= ARRAY_SIZE(hdmi_timings)) return -EINVAL; timings->timings = hdmi_timings[timings->index].dv_timings; @@ -686,8 +689,11 @@ static int hdmi_dv_timings_cap(struct v4l2_subdev *sd, { struct hdmi_device *hdev = sd_to_hdmi_dev(sd); + if (cap->pad != 0) + return -EINVAL; + /* Let the phy fill in the pixelclock range */ - v4l2_subdev_call(hdev->phy_sd, video, dv_timings_cap, cap); + v4l2_subdev_call(hdev->phy_sd, pad, dv_timings_cap, cap); cap->type = V4L2_DV_BT_656_1120; cap->bt.min_width = 720; cap->bt.max_width = 1920; @@ -706,12 +712,15 @@ static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = { .s_dv_timings = hdmi_s_dv_timings, .g_dv_timings = hdmi_g_dv_timings, - .enum_dv_timings = hdmi_enum_dv_timings, - .dv_timings_cap = hdmi_dv_timings_cap, .g_mbus_fmt = hdmi_g_mbus_fmt, .s_stream = hdmi_s_stream, }; +static const struct v4l2_subdev_pad_ops hdmi_sd_pad_ops = { + .enum_dv_timings = hdmi_enum_dv_timings, + .dv_timings_cap = hdmi_dv_timings_cap, +}; + static const struct v4l2_subdev_ops hdmi_sd_ops = { .core = &hdmi_sd_core_ops, .video = &hdmi_sd_video_ops, diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c index e19a0af1ea4..c2f2e35642f 100644 --- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c +++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c @@ -225,6 +225,9 @@ static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd, static int hdmiphy_dv_timings_cap(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap) { + if (cap->pad != 0) + return -EINVAL; + cap->type = V4L2_DV_BT_656_1120; /* The phy only determines the pixelclock, leave the other values * at 0 to signify that we have no information for them. */ @@ -259,13 +262,17 @@ static const struct v4l2_subdev_core_ops hdmiphy_core_ops = { static const struct v4l2_subdev_video_ops hdmiphy_video_ops = { .s_dv_timings = hdmiphy_s_dv_timings, - .dv_timings_cap = hdmiphy_dv_timings_cap, .s_stream = hdmiphy_s_stream, }; +static const struct v4l2_subdev_pad_ops hdmiphy_pad_ops = { + .dv_timings_cap = hdmiphy_dv_timings_cap, +}; + static const struct v4l2_subdev_ops hdmiphy_ops = { .core = &hdmiphy_core_ops, .video = &hdmiphy_video_ops, + .pad = &hdmiphy_pad_ops, }; static int hdmiphy_probe(struct i2c_client *client, diff --git a/drivers/media/platform/s5p-tv/mixer.h b/drivers/media/platform/s5p-tv/mixer.h index 04e6490a45b..fb2acc53112 100644 --- a/drivers/media/platform/s5p-tv/mixer.h +++ b/drivers/media/platform/s5p-tv/mixer.h @@ -65,7 +65,7 @@ struct mxr_format { int num_subframes; /** specifies to which subframe belong given plane */ int plane2subframe[MXR_MAX_PLANES]; - /** internal code, driver dependant */ + /** internal code, driver dependent */ unsigned long cookie; }; diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c index 51805a5e2be..bc08b5f28e4 100644 --- a/drivers/media/platform/s5p-tv/mixer_drv.c +++ b/drivers/media/platform/s5p-tv/mixer_drv.c @@ -347,19 +347,41 @@ static int mxr_runtime_resume(struct device *dev) { struct mxr_device *mdev = to_mdev(dev); struct mxr_resources *res = &mdev->res; + int ret; mxr_dbg(mdev, "resume - start\n"); mutex_lock(&mdev->mutex); /* turn clocks on */ - clk_enable(res->mixer); - clk_enable(res->vp); - clk_enable(res->sclk_mixer); + ret = clk_prepare_enable(res->mixer); + if (ret < 0) { + dev_err(mdev->dev, "clk_prepare_enable(mixer) failed\n"); + goto fail; + } + ret = clk_prepare_enable(res->vp); + if (ret < 0) { + dev_err(mdev->dev, "clk_prepare_enable(vp) failed\n"); + goto fail_mixer; + } + ret = clk_prepare_enable(res->sclk_mixer); + if (ret < 0) { + dev_err(mdev->dev, "clk_prepare_enable(sclk_mixer) failed\n"); + goto fail_vp; + } /* apply default configuration */ mxr_reg_reset(mdev); mxr_dbg(mdev, "resume - finished\n"); mutex_unlock(&mdev->mutex); return 0; + +fail_vp: + clk_disable_unprepare(res->vp); +fail_mixer: + clk_disable_unprepare(res->mixer); +fail: + mutex_unlock(&mdev->mutex); + dev_err(mdev->dev, "resume failed\n"); + return ret; } static int mxr_runtime_suspend(struct device *dev) @@ -369,9 +391,9 @@ static int mxr_runtime_suspend(struct device *dev) mxr_dbg(mdev, "suspend - start\n"); mutex_lock(&mdev->mutex); /* turn clocks off */ - clk_disable(res->sclk_mixer); - clk_disable(res->vp); - clk_disable(res->mixer); + clk_disable_unprepare(res->sclk_mixer); + clk_disable_unprepare(res->vp); + clk_disable_unprepare(res->mixer); mutex_unlock(&mdev->mutex); mxr_dbg(mdev, "suspend - finished\n"); return 0; diff --git a/drivers/media/platform/s5p-tv/mixer_grp_layer.c b/drivers/media/platform/s5p-tv/mixer_grp_layer.c index b93a21f5aa1..74344c764da 100644 --- a/drivers/media/platform/s5p-tv/mixer_grp_layer.c +++ b/drivers/media/platform/s5p-tv/mixer_grp_layer.c @@ -226,7 +226,7 @@ static void mxr_graph_fix_geometry(struct mxr_layer *layer, src->width + src->x_offset, 32767); src->full_height = clamp_val(src->full_height, src->height + src->y_offset, 2047); - }; + } } /* PUBLIC API */ diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 641b1f071e0..8a8dbc8fdfd 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -509,9 +509,11 @@ static int mxr_enum_dv_timings(struct file *file, void *fh, struct mxr_device *mdev = layer->mdev; int ret; + timings->pad = 0; + /* lock protects from changing sd_out */ mutex_lock(&mdev->mutex); - ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_timings, timings); + ret = v4l2_subdev_call(to_outsd(mdev), pad, enum_dv_timings, timings); mutex_unlock(&mdev->mutex); return ret ? -EINVAL : 0; @@ -528,7 +530,7 @@ static int mxr_s_dv_timings(struct file *file, void *fh, mutex_lock(&mdev->mutex); /* timings change cannot be done while there is an entity - * dependant on output configuration + * dependent on output configuration */ if (mdev->n_output > 0) { mutex_unlock(&mdev->mutex); @@ -567,9 +569,11 @@ static int mxr_dv_timings_cap(struct file *file, void *fh, struct mxr_device *mdev = layer->mdev; int ret; + cap->pad = 0; + /* lock protects from changing sd_out */ mutex_lock(&mdev->mutex); - ret = v4l2_subdev_call(to_outsd(mdev), video, dv_timings_cap, cap); + ret = v4l2_subdev_call(to_outsd(mdev), pad, dv_timings_cap, cap); mutex_unlock(&mdev->mutex); return ret ? -EINVAL : 0; @@ -585,7 +589,7 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id norm) mutex_lock(&mdev->mutex); /* standard change cannot be done while there is an entity - * dependant on output configuration + * dependent on output configuration */ if (mdev->n_output > 0) { mutex_unlock(&mdev->mutex); @@ -946,11 +950,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) mxr_dbg(mdev, "%s\n", __func__); - if (count == 0) { - mxr_dbg(mdev, "no output buffers queued\n"); - return -EINVAL; - } - /* block any changes in output configuration */ mxr_output_get(mdev); @@ -990,7 +989,7 @@ static void mxr_watchdog(unsigned long arg) spin_unlock_irqrestore(&layer->enq_slock, flags); } -static int stop_streaming(struct vb2_queue *vq) +static void stop_streaming(struct vb2_queue *vq) { struct mxr_layer *layer = vb2_get_drv_priv(vq); struct mxr_device *mdev = layer->mdev; @@ -1036,7 +1035,6 @@ static int stop_streaming(struct vb2_queue *vq) mxr_streamer_put(mdev); /* allow changes in output configuration */ mxr_output_put(mdev); - return 0; } static struct vb2_ops mxr_video_qops = { @@ -1124,6 +1122,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, .drv_priv = layer, .buf_struct_size = sizeof(struct mxr_buffer), .ops = &mxr_video_qops, + .min_buffers_needed = 1, .mem_ops = &vb2_dma_contig_memops, }; diff --git a/drivers/media/platform/s5p-tv/mixer_vp_layer.c b/drivers/media/platform/s5p-tv/mixer_vp_layer.c index 3d13a636877..c9388c45ad7 100644 --- a/drivers/media/platform/s5p-tv/mixer_vp_layer.c +++ b/drivers/media/platform/s5p-tv/mixer_vp_layer.c @@ -197,7 +197,7 @@ static void mxr_vp_fix_geometry(struct mxr_layer *layer, ALIGN(src->width + src->x_offset, 8), 8192U); src->full_height = clamp(src->full_height, src->height + src->y_offset, 8192U); - }; + } } /* PUBLIC API */ diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c index 0afa90f0f6a..5a7c3796f22 100644 --- a/drivers/media/platform/s5p-tv/sdo_drv.c +++ b/drivers/media/platform/s5p-tv/sdo_drv.c @@ -55,6 +55,8 @@ struct sdo_device { struct clk *dacphy; /** clock for control of VPLL */ struct clk *fout_vpll; + /** vpll rate before sdo stream was on */ + unsigned long vpll_rate; /** regulator for SDO IP power */ struct regulator *vdac; /** regulator for SDO plug detection */ @@ -193,17 +195,33 @@ static int sdo_s_power(struct v4l2_subdev *sd, int on) static int sdo_streamon(struct sdo_device *sdev) { + int ret; + /* set proper clock for Timing Generator */ - clk_set_rate(sdev->fout_vpll, 54000000); + sdev->vpll_rate = clk_get_rate(sdev->fout_vpll); + ret = clk_set_rate(sdev->fout_vpll, 54000000); + if (ret < 0) { + dev_err(sdev->dev, "Failed to set vpll rate\n"); + return ret; + } dev_info(sdev->dev, "fout_vpll.rate = %lu\n", clk_get_rate(sdev->fout_vpll)); /* enable clock in SDO */ sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON); - clk_enable(sdev->dacphy); + ret = clk_prepare_enable(sdev->dacphy); + if (ret < 0) { + dev_err(sdev->dev, "clk_prepare_enable(dacphy) failed\n"); + goto fail; + } /* enable DAC */ sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC); sdo_reg_debug(sdev); return 0; + +fail: + sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON); + clk_set_rate(sdev->fout_vpll, sdev->vpll_rate); + return ret; } static int sdo_streamoff(struct sdo_device *sdev) @@ -211,7 +229,7 @@ static int sdo_streamoff(struct sdo_device *sdev) int tries; sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC); - clk_disable(sdev->dacphy); + clk_disable_unprepare(sdev->dacphy); sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON); for (tries = 100; tries; --tries) { if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY) @@ -220,6 +238,7 @@ static int sdo_streamoff(struct sdo_device *sdev) } if (tries == 0) dev_err(sdev->dev, "failed to stop streaming\n"); + clk_set_rate(sdev->fout_vpll, sdev->vpll_rate); return tries ? 0 : -EIO; } @@ -254,7 +273,7 @@ static int sdo_runtime_suspend(struct device *dev) dev_info(dev, "suspend\n"); regulator_disable(sdev->vdet); regulator_disable(sdev->vdac); - clk_disable(sdev->sclk_dac); + clk_disable_unprepare(sdev->sclk_dac); return 0; } @@ -266,7 +285,7 @@ static int sdo_runtime_resume(struct device *dev) dev_info(dev, "resume\n"); - ret = clk_enable(sdev->sclk_dac); + ret = clk_prepare_enable(sdev->sclk_dac); if (ret < 0) return ret; @@ -299,7 +318,7 @@ static int sdo_runtime_resume(struct device *dev) vdac_r_dis: regulator_disable(sdev->vdac); dac_clk_dis: - clk_disable(sdev->sclk_dac); + clk_disable_unprepare(sdev->sclk_dac); return ret; } @@ -405,7 +424,11 @@ static int sdo_probe(struct platform_device *pdev) } /* enable gate for dac clock, because mixer uses it */ - clk_enable(sdev->dac); + ret = clk_prepare_enable(sdev->dac); + if (ret < 0) { + dev_err(dev, "clk_prepare_enable(dac) failed\n"); + goto fail_fout_vpll; + } /* configure power management */ pm_runtime_enable(dev); @@ -444,7 +467,7 @@ static int sdo_remove(struct platform_device *pdev) struct sdo_device *sdev = sd_to_sdev(sd); pm_runtime_disable(&pdev->dev); - clk_disable(sdev->dac); + clk_disable_unprepare(sdev->dac); clk_put(sdev->fout_vpll); clk_put(sdev->dacphy); clk_put(sdev->dac); |
