All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/9] [media] tvp5150: convert register access to regmap
@ 2016-03-14 15:23 Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 2/9] [media] tvp5150: add userspace subdev API Lucas Stach
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

Regmap provides built in debugging, caching and provides dedicated accessors
for bit manipulations in registers, which make the following changes a lot
simpler.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 194 ++++++++++++++++++++++++++++++--------------
 1 file changed, 133 insertions(+), 61 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 6c3769d44b75..6ba93a425640 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -10,6 +10,7 @@
 #include <linux/videodev2.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/regmap.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/i2c/tvp5150.h>
@@ -37,6 +38,7 @@ struct tvp5150 {
 	struct v4l2_subdev sd;
 	struct v4l2_ctrl_handler hdl;
 	struct v4l2_rect rect;
+	struct regmap *regmap;
 
 	v4l2_std_id norm;	/* Current set standard */
 	u32 input;
@@ -56,30 +58,14 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
 
 static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
 {
-	struct i2c_client *c = v4l2_get_subdevdata(sd);
-	int rc;
-
-	rc = i2c_smbus_read_byte_data(c, addr);
-	if (rc < 0) {
-		v4l2_err(sd, "i2c i/o error: rc == %d\n", rc);
-		return rc;
-	}
-
-	v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, rc);
-
-	return rc;
-}
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	int ret, val;
 
-static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
-				 unsigned char value)
-{
-	struct i2c_client *c = v4l2_get_subdevdata(sd);
-	int rc;
+	ret = regmap_read(decoder->regmap, addr, &val);
+	if (ret < 0)
+		return ret;
 
-	v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value);
-	rc = i2c_smbus_write_byte_data(c, addr, value);
-	if (rc < 0)
-		v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc);
+	return val;
 }
 
 static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
@@ -266,8 +252,8 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd)
 			decoder->input, decoder->output,
 			input, opmode);
 
-	tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode);
-	tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input);
+	regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
+	regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
 
 	/* Svideo should enable YCrCb output and disable GPCL output
 	 * For Composite and TV, it should be the reverse
@@ -282,7 +268,7 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd)
 		val = (val & ~0x40) | 0x10;
 	else
 		val = (val & ~0x10) | 0x40;
-	tvp5150_write(sd, TVP5150_MISC_CTL, val);
+	regmap_write(decoder->regmap, TVP5150_MISC_CTL, val);
 };
 
 struct i2c_reg_value {
@@ -553,8 +539,10 @@ static struct i2c_vbi_ram_value vbi_ram_default[] =
 static int tvp5150_write_inittab(struct v4l2_subdev *sd,
 				const struct i2c_reg_value *regs)
 {
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
 	while (regs->reg != 0xff) {
-		tvp5150_write(sd, regs->reg, regs->value);
+		regmap_write(decoder->regmap, regs->reg, regs->value);
 		regs++;
 	}
 	return 0;
@@ -563,22 +551,24 @@ static int tvp5150_write_inittab(struct v4l2_subdev *sd,
 static int tvp5150_vdp_init(struct v4l2_subdev *sd,
 				const struct i2c_vbi_ram_value *regs)
 {
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct regmap *map = decoder->regmap;
 	unsigned int i;
 
 	/* Disable Full Field */
-	tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
+	regmap_write(map, TVP5150_FULL_FIELD_ENA, 0);
 
 	/* Before programming, Line mode should be at 0xff */
 	for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
-		tvp5150_write(sd, i, 0xff);
+		regmap_write(map, i, 0xff);
 
 	/* Load Ram Table */
 	while (regs->reg != (u16)-1) {
-		tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
-		tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
+		regmap_write(map, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
+		regmap_write(map, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
 
 		for (i = 0; i < 16; i++)
-			tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);
+			regmap_write(map, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);
 
 		regs++;
 	}
@@ -658,11 +648,11 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd,
 	reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
 
 	if (fields&1) {
-		tvp5150_write(sd, reg, type);
+		regmap_write(decoder->regmap, reg, type);
 	}
 
 	if (fields&2) {
-		tvp5150_write(sd, reg+1, type);
+		regmap_write(decoder->regmap, reg+1, type);
 	}
 
 	return type;
@@ -731,7 +721,7 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
 	}
 
 	v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt);
-	tvp5150_write(sd, TVP5150_VIDEO_STD, fmt);
+	regmap_write(decoder->regmap, TVP5150_VIDEO_STD, fmt);
 	return 0;
 }
 
@@ -777,20 +767,20 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 
 static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct tvp5150 *decoder = to_tvp5150(to_sd(ctrl));
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val);
+		regmap_write(decoder->regmap, TVP5150_BRIGHT_CTL, ctrl->val);
 		return 0;
 	case V4L2_CID_CONTRAST:
-		tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val);
+		regmap_write(decoder->regmap, TVP5150_CONTRAST_CTL, ctrl->val);
 		return 0;
 	case V4L2_CID_SATURATION:
-		tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val);
+		regmap_write(decoder->regmap, TVP5150_SATURATION_CTL, ctrl->val);
 		return 0;
 	case V4L2_CID_HUE:
-		tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val);
+		regmap_write(decoder->regmap, TVP5150_HUE_CTL, ctrl->val);
 		return 0;
 	}
 	return -EINVAL;
@@ -890,17 +880,17 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
 			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
 			      hmax - rect.top);
 
-	tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
-	tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
+	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
+	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
 		      rect.top + rect.height - hmax);
-	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_MSB,
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
 		      rect.left >> TVP5150_CROP_SHIFT);
-	tvp5150_write(sd, TVP5150_ACT_VD_CROP_ST_LSB,
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
 		      rect.left | (1 << TVP5150_CROP_SHIFT));
-	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_MSB,
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
 		      (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
 		      TVP5150_CROP_SHIFT);
-	tvp5150_write(sd, TVP5150_ACT_VD_CROP_STP_LSB,
+	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
 		      rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
 
 	decoder->rect = rect;
@@ -965,22 +955,25 @@ static int tvp5150_s_routing(struct v4l2_subdev *sd,
 
 static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
 {
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
 	/* this is for capturing 36 raw vbi lines
 	   if there's a way to cut off the beginning 2 vbi lines
 	   with the tvp5150 then the vbi line count could be lowered
 	   to 17 lines/field again, although I couldn't find a register
 	   which could do that cropping */
 	if (fmt->sample_format == V4L2_PIX_FMT_GREY)
-		tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
+		regmap_write(decoder->regmap, TVP5150_LUMA_PROC_CTL_1, 0x70);
 	if (fmt->count[0] == 18 && fmt->count[1] == 18) {
-		tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
-		tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
+		regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, 0x00);
+		regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, 0x01);
 	}
 	return 0;
 }
 
 static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
 {
+	struct tvp5150 *decoder = to_tvp5150(sd);
 	int i;
 
 	if (svbi->service_set != 0) {
@@ -991,17 +984,17 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
 				       svbi->service_lines[0][i], 0xf0, i, 3);
 		}
 		/* Enables FIFO */
-		tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1);
+		regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 1);
 	} else {
 		/* Disables FIFO*/
-		tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0);
+		regmap_write(decoder->regmap, TVP5150_FIFO_OUT_CTRL, 0);
 
 		/* Disable Full Field */
-		tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
+		regmap_write(decoder->regmap, TVP5150_FULL_FIELD_ENA, 0);
 
 		/* Disable Line modes */
 		for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
-			tvp5150_write(sd, i, 0xff);
+			regmap_write(decoder->regmap, i, 0xff);
 	}
 	return 0;
 }
@@ -1039,7 +1032,9 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
-	tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
+	regmap_write(decoder->regmap, reg->reg & 0xff, reg->val & 0xff);
 	return 0;
 }
 #endif
@@ -1105,13 +1100,87 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
 			I2C Client & Driver
  ****************************************************************************/
 
+static const struct regmap_range tvp5150_readable_ranges[] = {
+	{
+		.range_min = TVP5150_VD_IN_SRC_SEL_1,
+		.range_max = TVP5150_AUTOSW_MSK,
+	}, {
+		.range_min = TVP5150_COLOR_KIL_THSH_CTL,
+		.range_max = TVP5150_CONF_SHARED_PIN,
+	}, {
+		.range_min = TVP5150_ACT_VD_CROP_ST_MSB,
+		.range_max = TVP5150_HORIZ_SYNC_START,
+	}, {
+		.range_min = TVP5150_VERT_BLANKING_START,
+		.range_max = TVP5150_INTT_CONFIG_REG_B,
+	}, {
+		.range_min = TVP5150_VIDEO_STD,
+		.range_max = TVP5150_VIDEO_STD,
+	}, {
+		.range_min = TVP5150_CB_GAIN_FACT,
+		.range_max = TVP5150_REV_SELECT,
+	}, {
+		.range_min = TVP5150_MSB_DEV_ID,
+		.range_max = TVP5150_STATUS_REG_5,
+	}, {
+		.range_min = TVP5150_CC_DATA_INI,
+		.range_max = TVP5150_TELETEXT_FIL_ENA,
+	}, {
+		.range_min = TVP5150_INT_STATUS_REG_A,
+		.range_max = TVP5150_FIFO_OUT_CTRL,
+	}, {
+		.range_min = TVP5150_FULL_FIELD_ENA,
+		.range_max = TVP5150_FULL_FIELD_MODE_REG,
+	},
+};
+
+bool tvp5150_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case TVP5150_VERT_LN_COUNT_MSB:
+	case TVP5150_VERT_LN_COUNT_LSB:
+	case TVP5150_INT_STATUS_REG_A:
+	case TVP5150_INT_STATUS_REG_B:
+	case TVP5150_INT_ACTIVE_REG_B:
+	case TVP5150_STATUS_REG_1:
+	case TVP5150_STATUS_REG_2:
+	case TVP5150_STATUS_REG_3:
+	case TVP5150_STATUS_REG_4:
+	case TVP5150_STATUS_REG_5:
+	/* CC, WSS, VPS, VITC data? */
+	case TVP5150_VBI_FIFO_READ_DATA:
+	case TVP5150_VDP_STATUS_REG:
+	case TVP5150_FIFO_WORD_COUNT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_access_table tvp5150_readable_table = {
+	.yes_ranges = tvp5150_readable_ranges,
+	.n_yes_ranges = ARRAY_SIZE(tvp5150_readable_ranges),
+};
+
+static struct regmap_config tvp5150_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = 0xff,
+
+	.cache_type = REGCACHE_RBTREE,
+
+	.rd_table = &tvp5150_readable_table,
+	.volatile_reg = tvp5150_volatile_reg,
+};
+
 static int tvp5150_probe(struct i2c_client *c,
 			 const struct i2c_device_id *id)
 {
 	struct tvp5150 *core;
 	struct v4l2_subdev *sd;
-	int tvp5150_id[4];
-	int i, res;
+	struct regmap *map;
+	u8 tvp5150_id[4];
+	int res;
 
 	/* Check if the adapter supports the needed features */
 	if (!i2c_check_functionality(c->adapter,
@@ -1121,6 +1190,10 @@ static int tvp5150_probe(struct i2c_client *c,
 	core = devm_kzalloc(&c->dev, sizeof(*core), GFP_KERNEL);
 	if (!core)
 		return -ENOMEM;
+	map = devm_regmap_init_i2c(c, &tvp5150_config);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+	core->regmap = map;
 	sd = &core->sd;
 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
 
@@ -1128,11 +1201,10 @@ static int tvp5150_probe(struct i2c_client *c,
 	 * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
 	 * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 
 	 */
-	for (i = 0; i < 4; i++) {
-		res = tvp5150_read(sd, TVP5150_MSB_DEV_ID + i);
-		if (res < 0)
-			return res;
-		tvp5150_id[i] = res;
+	res = regmap_bulk_read(map, TVP5150_MSB_DEV_ID, tvp5150_id, 4);
+	if (res < 0) {
+		dev_err(&c->dev, "reading ID registers failed: %d\n", res);
+		return res;
 	}
 
 	v4l_info(c, "chip found @ 0x%02x (%s)\n",
@@ -1143,7 +1215,7 @@ static int tvp5150_probe(struct i2c_client *c,
 			  tvp5150_id[0], tvp5150_id[1]);
 
 		/* ITU-T BT.656.4 timing */
-		tvp5150_write(sd, TVP5150_REV_SELECT, 0);
+		regmap_write(map, TVP5150_REV_SELECT, 0);
 	} else {
 		/* Is TVP5150A */
 		if (tvp5150_id[2] == 3 || tvp5150_id[3] == 0x21) {
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 2/9] [media] tvp5150: add userspace subdev API
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  2016-03-14 17:34   ` Mauro Carvalho Chehab
  2016-03-14 15:23 ` [PATCH v3 3/9] [media] tvp5150: determine BT.656 or YUV 4:2:2 mode from device tree Lucas Stach
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

This patch adds userspace V4L2 subdevice API support.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 282 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 223 insertions(+), 59 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 6ba93a425640..67312c9d83c1 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -36,7 +36,9 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 
 struct tvp5150 {
 	struct v4l2_subdev sd;
+	struct media_pad pad;
 	struct v4l2_ctrl_handler hdl;
+	struct v4l2_mbus_framefmt format;
 	struct v4l2_rect rect;
 	struct regmap *regmap;
 
@@ -819,38 +821,68 @@ static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
-		struct v4l2_subdev_pad_config *cfg,
-		struct v4l2_subdev_format *format)
+static void tvp5150_try_crop(struct tvp5150 *decoder, struct v4l2_rect *rect,
+			       v4l2_std_id std)
 {
-	struct v4l2_mbus_framefmt *f;
-	struct tvp5150 *decoder = to_tvp5150(sd);
+	unsigned int hmax;
 
-	if (!format || format->pad)
-		return -EINVAL;
+	/* Clamp the crop rectangle boundaries to tvp5150 limits */
+	rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
+	rect->width = clamp(rect->width,
+			    TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left,
+			    TVP5150_H_MAX - rect->left);
+	rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
 
-	f = &format->format;
+	/* tvp5150 has some special limits */
+	rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
+	rect->width = clamp_t(unsigned int, rect->width,
+			      TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left,
+			      TVP5150_H_MAX - rect->left);
+	rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
+
+	/* Calculate height based on current standard */
+	if (std & V4L2_STD_525_60)
+		hmax = TVP5150_V_MAX_525_60;
+	else
+		hmax = TVP5150_V_MAX_OTHERS;
 
-	tvp5150_reset(sd, 0);
+	rect->height = clamp(rect->height,
+			     hmax - TVP5150_MAX_CROP_TOP - rect->top,
+			     hmax - rect->top);
+}
 
-	f->width = decoder->rect.width;
-	f->height = decoder->rect.height;
+static void tvp5150_set_crop(struct tvp5150 *decoder, struct v4l2_rect *rect,
+			       v4l2_std_id std)
+{
+	struct regmap *map = decoder->regmap;
+	unsigned int hmax;
 
-	f->code = MEDIA_BUS_FMT_UYVY8_2X8;
-	f->field = V4L2_FIELD_SEQ_TB;
-	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
+	if (std & V4L2_STD_525_60)
+		hmax = TVP5150_V_MAX_525_60;
+	else
+		hmax = TVP5150_V_MAX_OTHERS;
 
-	v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width,
-			f->height);
-	return 0;
+	regmap_write(map, TVP5150_VERT_BLANKING_START, rect->top);
+	regmap_write(map, TVP5150_VERT_BLANKING_STOP,
+		     rect->top + rect->height - hmax);
+	regmap_write(map, TVP5150_ACT_VD_CROP_ST_MSB,
+		     rect->left >> TVP5150_CROP_SHIFT);
+	regmap_write(map, TVP5150_ACT_VD_CROP_ST_LSB,
+		     rect->left | (1 << TVP5150_CROP_SHIFT));
+	regmap_write(map, TVP5150_ACT_VD_CROP_STP_MSB,
+		     (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >>
+		     TVP5150_CROP_SHIFT);
+	regmap_write(map, TVP5150_ACT_VD_CROP_STP_LSB,
+		     rect->left + rect->width - TVP5150_MAX_CROP_LEFT);
+
+	decoder->rect = *rect;
 }
 
 static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
 {
-	struct v4l2_rect rect = a->c;
 	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct v4l2_rect rect = a->c;
 	v4l2_std_id std;
-	unsigned int hmax;
 
 	v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
 		__func__, rect.left, rect.top, rect.width, rect.height);
@@ -858,42 +890,13 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
 	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
-	/* tvp5150 has some special limits */
-	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
-	rect.width = clamp_t(unsigned int, rect.width,
-			     TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
-			     TVP5150_H_MAX - rect.left);
-	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
-
-	/* Calculate height based on current standard */
 	if (decoder->norm == V4L2_STD_ALL)
 		std = tvp5150_read_std(sd);
 	else
 		std = decoder->norm;
 
-	if (std & V4L2_STD_525_60)
-		hmax = TVP5150_V_MAX_525_60;
-	else
-		hmax = TVP5150_V_MAX_OTHERS;
-
-	rect.height = clamp_t(unsigned int, rect.height,
-			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
-			      hmax - rect.top);
-
-	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
-	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
-		      rect.top + rect.height - hmax);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
-		      rect.left >> TVP5150_CROP_SHIFT);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
-		      rect.left | (1 << TVP5150_CROP_SHIFT));
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
-		      (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
-		      TVP5150_CROP_SHIFT);
-	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
-		      rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
-
-	decoder->rect = rect;
+	tvp5150_try_crop(decoder, &rect, std);
+	tvp5150_set_crop(decoder, &rect, std);
 
 	return 0;
 }
@@ -1049,6 +1052,153 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 
 /* ----------------------------------------------------------------------- */
 
+static struct v4l2_mbus_framefmt *
+tvp5150_get_pad_format(struct tvp5150 *decoder, struct v4l2_subdev *sd,
+			 struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+			 enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_format(sd, cfg, pad);
+#endif
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &decoder->format;
+	default:
+		return NULL;
+	}
+}
+
+static struct v4l2_rect *
+tvp5150_get_pad_crop(struct tvp5150 *decoder, struct v4l2_subdev *sd,
+		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+		       enum v4l2_subdev_format_whence which)
+{
+	switch (which) {
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	case V4L2_SUBDEV_FORMAT_TRY:
+		return v4l2_subdev_get_try_crop(sd, cfg, pad);
+#endif
+	case V4L2_SUBDEV_FORMAT_ACTIVE:
+		return &decoder->rect;
+	default:
+		return NULL;
+	}
+}
+
+static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_pad_config *cfg,
+				   struct v4l2_subdev_frame_size_enum *fse)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
+
+	if (fse->index > 0 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
+		return -EINVAL;
+
+	fse->min_width = TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT;
+	fse->max_width = TVP5150_H_MAX;
+
+	/* Calculate height based on current standard */
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	if (std & V4L2_STD_525_60) {
+		fse->min_height = TVP5150_V_MAX_525_60 - TVP5150_MAX_CROP_TOP;
+		fse->max_height = TVP5150_V_MAX_525_60;
+	} else {
+		fse->min_height = TVP5150_V_MAX_OTHERS - TVP5150_MAX_CROP_TOP;
+		fse->max_height = TVP5150_V_MAX_OTHERS;
+	}
+
+	return 0;
+}
+
+static int tvp5150_get_format(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *format)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct v4l2_mbus_framefmt *mbus_format;
+
+	mbus_format = tvp5150_get_pad_format(decoder, sd, cfg,
+					     format->pad, format->which);
+	if (!mbus_format)
+		return -ENOTTY;
+
+	format->format = *mbus_format;
+
+	return 0;
+}
+
+static int tvp5150_set_format(struct v4l2_subdev *sd,
+			      struct v4l2_subdev_pad_config *cfg,
+			      struct v4l2_subdev_format *format)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct v4l2_mbus_framefmt *mbus_format;
+	struct v4l2_rect *crop;
+
+	crop = tvp5150_get_pad_crop(decoder, sd, cfg, format->pad,
+				    format->which);
+	mbus_format = tvp5150_get_pad_format(decoder, sd, cfg, format->pad,
+					     format->which);
+	if (!crop || !mbus_format)
+		return -ENOTTY;
+
+	mbus_format->width = crop->width;
+	mbus_format->height = crop->height;
+
+	format->format = *mbus_format;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+		tvp5150_reset(sd, 0);
+
+	v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", mbus_format->width,
+			mbus_format->height);
+
+	return 0;
+}
+
+static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop,
+				struct v4l2_mbus_framefmt *format)
+{
+	crop->left = 0;
+	crop->width = TVP5150_H_MAX;
+	crop->top = 0;
+	if (std & V4L2_STD_525_60)
+		crop->height = TVP5150_V_MAX_525_60;
+	else
+		crop->height = TVP5150_V_MAX_OTHERS;
+
+	format->width = crop->width;
+	format->height = crop->height;
+	format->code = MEDIA_BUS_FMT_UYVY8_2X8;
+	format->field = V4L2_FIELD_SEQ_TB;
+	format->colorspace = V4L2_COLORSPACE_SMPTE170M;
+}
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
+
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	tvp5150_set_default(std, v4l2_subdev_get_try_crop(fh, 0),
+				 v4l2_subdev_get_try_format(fh, 0));
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
 static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
 	.s_ctrl = tvp5150_s_ctrl,
 };
@@ -1083,8 +1233,9 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
 
 static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
 	.enum_mbus_code = tvp5150_enum_mbus_code,
-	.set_fmt = tvp5150_fill_fmt,
-	.get_fmt = tvp5150_fill_fmt,
+	.enum_frame_size = tvp5150_enum_frame_size,
+	.get_fmt = tvp5150_get_format,
+	.set_fmt = tvp5150_set_format,
 };
 
 static const struct v4l2_subdev_ops tvp5150_ops = {
@@ -1095,6 +1246,11 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
 	.pad = &tvp5150_pad_ops,
 };
 
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
+	.open = tvp5150_open,
+};
+#endif
 
 /****************************************************************************
 			I2C Client & Driver
@@ -1197,6 +1353,19 @@ static int tvp5150_probe(struct i2c_client *c,
 	sd = &core->sd;
 	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
 
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	sd->internal_ops = &tvp5150_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+#endif
+#ifdef CONFIG_MEDIA_CONTROLLER
+	sd->entity.flags |= MEDIA_ENT_F_ATV_DECODER;
+	core->pad.flags = MEDIA_PAD_FL_SOURCE;
+	res = media_entity_pads_init(&sd->entity, 1, &core->pad);
+	if (res < 0)
+		return res;
+#endif
+
 	/* 
 	 * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
 	 * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 
@@ -1250,14 +1419,9 @@ static int tvp5150_probe(struct i2c_client *c,
 	v4l2_ctrl_handler_setup(&core->hdl);
 
 	/* Default is no cropping */
-	core->rect.top = 0;
-	if (tvp5150_read_std(sd) & V4L2_STD_525_60)
-		core->rect.height = TVP5150_V_MAX_525_60;
-	else
-		core->rect.height = TVP5150_V_MAX_OTHERS;
-	core->rect.left = 0;
-	core->rect.width = TVP5150_H_MAX;
+	tvp5150_set_default(tvp5150_read_std(sd), &core->rect, &core->format);
 
+	sd->dev = &c->dev;
 	res = v4l2_async_register_subdev(sd);
 	if (res < 0)
 		goto err;
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 3/9] [media] tvp5150: determine BT.656 or YUV 4:2:2 mode from device tree
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 2/9] [media] tvp5150: add userspace subdev API Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  2016-03-14 18:19   ` Javier Martinez Canillas
  2016-03-14 15:23 ` [PATCH v3 4/9] [media] tvp5150: fix standard autodetection Lucas Stach
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

By looking at the endpoint flags, it can be determined whether the link
should be of V4L2_MBUS_PARALLEL or V4L2_MBUS_BT656 type. Disable the
dedicated HSYNC/VSYNC outputs in BT.656 mode.

For devices that are not instantiated through DT the current behavior
is preserved.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 67312c9d83c1..f6720d1d09ea 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -11,10 +11,12 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
+#include <linux/of_graph.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
 #include <media/i2c/tvp5150.h>
 #include <media/v4l2-ctrls.h>
+#include <media/v4l2-of.h>
 
 #include "tvp5150_reg.h"
 
@@ -38,6 +40,7 @@ struct tvp5150 {
 	struct v4l2_subdev sd;
 	struct media_pad pad;
 	struct v4l2_ctrl_handler hdl;
+	enum v4l2_mbus_type bus_type;
 	struct v4l2_mbus_framefmt format;
 	struct v4l2_rect rect;
 	struct regmap *regmap;
@@ -424,8 +427,6 @@ static const struct i2c_reg_value tvp5150_init_enable[] = {
 		TVP5150_MISC_CTL, 0x6f
 	},{	/* Activates video std autodetection for all standards */
 		TVP5150_AUTOSW_MSK, 0x0
-	},{	/* Default format: 0x47. For 4:2:2: 0x40 */
-		TVP5150_DATA_RATE_SEL, 0x47
 	},{
 		TVP5150_CHROMA_PROC_CTL_1, 0x0c
 	},{
@@ -760,6 +761,25 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 	/* Initializes TVP5150 to stream enabled values */
 	tvp5150_write_inittab(sd, tvp5150_init_enable);
 
+	switch (decoder->bus_type) {
+	case V4L2_MBUS_BT656:
+		/* 8-bit ITU BT.656 */
+		regmap_update_bits(decoder->regmap, TVP5150_DATA_RATE_SEL,
+				   0x7, 0x7);
+		/* disable HSYNC, VSYNC/PALI, AVID, and FID/GLCO */
+		regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, 0x4, 0x0);
+		break;
+	case V4L2_MBUS_PARALLEL:
+		/* 8-bit YUV 4:2:2 */
+		regmap_update_bits(decoder->regmap, TVP5150_DATA_RATE_SEL,
+				   0x7, 0x0);
+		/* enable HSYNC, VSYNC/PALI, AVID, and FID/GLCO */
+		regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, 0x4, 0x4);
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	/* Initialize image preferences */
 	v4l2_ctrl_handler_setup(&decoder->hdl);
 
@@ -1332,6 +1352,8 @@ static struct regmap_config tvp5150_config = {
 static int tvp5150_probe(struct i2c_client *c,
 			 const struct i2c_device_id *id)
 {
+	struct v4l2_of_endpoint bus_cfg;
+	struct device_node *endpoint;
 	struct tvp5150 *core;
 	struct v4l2_subdev *sd;
 	struct regmap *map;
@@ -1398,6 +1420,14 @@ static int tvp5150_probe(struct i2c_client *c,
 		}
 	}
 
+	endpoint = of_graph_get_next_endpoint(c->dev.of_node, NULL);
+	if (endpoint) {
+		v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+		core->bus_type = bus_cfg.bus_type;
+	} else {
+		core->bus_type = V4L2_MBUS_BT656;
+	}
+
 	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
 	core->input = TVP5150_COMPOSITE1;
 	core->enable = 1;
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 4/9] [media] tvp5150: fix standard autodetection
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 2/9] [media] tvp5150: add userspace subdev API Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 3/9] [media] tvp5150: determine BT.656 or YUV 4:2:2 mode from device tree Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 5/9] [media] tvp5150: split reset/enable routine Lucas Stach
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

Make sure to not overwrite decoder->norm when setting the standard
in hardware, but only when instructed by V4L2 API calls.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 56 +++++++++++++++++++++++++--------------------
 1 file changed, 31 insertions(+), 25 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index f6720d1d09ea..21d044b564ad 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -703,8 +703,6 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
 	struct tvp5150 *decoder = to_tvp5150(sd);
 	int fmt = 0;
 
-	decoder->norm = std;
-
 	/* First tests should be against specific std */
 
 	if (std == V4L2_STD_NTSC_443) {
@@ -741,13 +739,37 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 	else
 		decoder->rect.height = TVP5150_V_MAX_OTHERS;
 
+	decoder->norm = std;
 
 	return tvp5150_set_std(sd, std);
 }
 
+static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
+{
+	int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
+
+	switch (val & 0x0F) {
+	case 0x01:
+		return V4L2_STD_NTSC;
+	case 0x03:
+		return V4L2_STD_PAL;
+	case 0x05:
+		return V4L2_STD_PAL_M;
+	case 0x07:
+		return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
+	case 0x09:
+		return V4L2_STD_NTSC_443;
+	case 0xb:
+		return V4L2_STD_SECAM;
+	default:
+		return V4L2_STD_UNKNOWN;
+	}
+}
+
 static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
 
 	/* Initializes TVP5150 to its default values */
 	tvp5150_write_inittab(sd, tvp5150_init_default);
@@ -783,7 +805,13 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 	/* Initialize image preferences */
 	v4l2_ctrl_handler_setup(&decoder->hdl);
 
-	tvp5150_set_std(sd, decoder->norm);
+	if (decoder->norm == V4L2_STD_ALL)
+		std = tvp5150_read_std(sd);
+	else
+		std = decoder->norm;
+
+	/* Disable autoswitch mode */
+	tvp5150_set_std(sd, std);
 	return 0;
 };
 
@@ -808,28 +836,6 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
 	return -EINVAL;
 }
 
-static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
-{
-	int val = tvp5150_read(sd, TVP5150_STATUS_REG_5);
-
-	switch (val & 0x0F) {
-	case 0x01:
-		return V4L2_STD_NTSC;
-	case 0x03:
-		return V4L2_STD_PAL;
-	case 0x05:
-		return V4L2_STD_PAL_M;
-	case 0x07:
-		return V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
-	case 0x09:
-		return V4L2_STD_NTSC_443;
-	case 0xb:
-		return V4L2_STD_SECAM;
-	default:
-		return V4L2_STD_UNKNOWN;
-	}
-}
-
 static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
 		struct v4l2_subdev_pad_config *cfg,
 		struct v4l2_subdev_mbus_code_enum *code)
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 5/9] [media] tvp5150: split reset/enable routine
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
                   ` (2 preceding siblings ...)
  2016-03-14 15:23 ` [PATCH v3 4/9] [media] tvp5150: fix standard autodetection Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 6/9] [media] tvp5150: trigger autodetection on subdev open to reset cropping Lucas Stach
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

To trigger standard autodetection only the reset part of the routine
is necessary. Split this out to make it callable on its own.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 21d044b564ad..f5e6bfa9dd7f 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -768,9 +768,6 @@ static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
 
 static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 {
-	struct tvp5150 *decoder = to_tvp5150(sd);
-	v4l2_std_id std;
-
 	/* Initializes TVP5150 to its default values */
 	tvp5150_write_inittab(sd, tvp5150_init_default);
 
@@ -780,6 +777,14 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 	/* Selects decoder input */
 	tvp5150_selmux(sd);
 
+	return 0;
+}
+
+static int tvp5150_enable(struct v4l2_subdev *sd)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	v4l2_std_id std;
+
 	/* Initializes TVP5150 to stream enabled values */
 	tvp5150_write_inittab(sd, tvp5150_init_enable);
 
@@ -844,6 +849,7 @@ static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
 		return -EINVAL;
 
 	code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+
 	return 0;
 }
 
@@ -1179,8 +1185,10 @@ static int tvp5150_set_format(struct v4l2_subdev *sd,
 
 	format->format = *mbus_format;
 
-	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
 		tvp5150_reset(sd, 0);
+		tvp5150_enable(sd);
+	}
 
 	v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", mbus_format->width,
 			mbus_format->height);
@@ -1454,6 +1462,7 @@ static int tvp5150_probe(struct i2c_client *c,
 	}
 	v4l2_ctrl_handler_setup(&core->hdl);
 
+	tvp5150_reset(sd, 0);
 	/* Default is no cropping */
 	tvp5150_set_default(tvp5150_read_std(sd), &core->rect, &core->format);
 
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 6/9] [media] tvp5150: trigger autodetection on subdev open to reset cropping
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
                   ` (3 preceding siblings ...)
  2016-03-14 15:23 ` [PATCH v3 5/9] [media] tvp5150: split reset/enable routine Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 7/9] [media] tvp5150: remove pin configuration from initialization tables Lucas Stach
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

If cropping isn't set explicitly by userspace, reset it to the maximum
possible rectangle in subdevice open if a standard change is detected.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index f5e6bfa9dd7f..d0b5e148dcd8 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -46,6 +46,7 @@ struct tvp5150 {
 	struct regmap *regmap;
 
 	v4l2_std_id norm;	/* Current set standard */
+	v4l2_std_id detected_norm;
 	u32 input;
 	u32 output;
 	int enable;
@@ -1220,13 +1221,19 @@ static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 	struct tvp5150 *decoder = to_tvp5150(sd);
 	v4l2_std_id std;
 
-	if (decoder->norm == V4L2_STD_ALL)
+	if (decoder->norm == V4L2_STD_ALL) {
 		std = tvp5150_read_std(sd);
-	else
-		std = decoder->norm;
+		if (std != decoder->detected_norm) {
+			decoder->detected_norm = std;
+
+			if (std & V4L2_STD_525_60)
+				decoder->rect.height = TVP5150_V_MAX_525_60;
+			else
+				decoder->rect.height = TVP5150_V_MAX_OTHERS;
+			decoder->format.height = decoder->rect.height;
+		}
+	}
 
-	tvp5150_set_default(std, v4l2_subdev_get_try_crop(fh, 0),
-				 v4l2_subdev_get_try_format(fh, 0));
 	return 0;
 }
 #endif
@@ -1443,6 +1450,7 @@ static int tvp5150_probe(struct i2c_client *c,
 	}
 
 	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
+	core->detected_norm = V4L2_STD_UNKNOWN;
 	core->input = TVP5150_COMPOSITE1;
 	core->enable = 1;
 
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 7/9] [media] tvp5150: remove pin configuration from initialization tables
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
                   ` (4 preceding siblings ...)
  2016-03-14 15:23 ` [PATCH v3 6/9] [media] tvp5150: trigger autodetection on subdev open to reset cropping Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 8/9] [media] tvp5150: Add sync lock interrupt handling Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 9/9] [media] tvp5150: disable output while signal not locked Lucas Stach
  7 siblings, 0 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

To allow optional interrupt support, we want to configure the pin settings
dynamically. Move those register accesses out of the static initialization
tables.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c     | 19 +++++++------------
 drivers/media/i2c/tvp5150_reg.h |  1 +
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index d0b5e148dcd8..e0f5bc219ced 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -323,9 +323,6 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
 	{ /* 0x0e */
 		TVP5150_LUMA_PROC_CTL_3,0x00
 	},
-	{ /* 0x0f */
-		TVP5150_CONF_SHARED_PIN,0x08
-	},
 	{ /* 0x11 */
 		TVP5150_ACT_VD_CROP_ST_MSB,0x00
 	},
@@ -362,9 +359,6 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
 	{ /* 0x1d */
 		TVP5150_INT_ENABLE_REG_B,0x00
 	},
-	{ /* 0x1e */
-		TVP5150_INTT_CONFIG_REG_B,0x00
-	},
 	{ /* 0x28 */
 		TVP5150_VIDEO_STD,0x00
 	},
@@ -383,9 +377,6 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
 	{ /* 0xc1 */
 		TVP5150_INT_ENABLE_REG_A,0x00
 	},
-	{ /* 0xc2 */
-		TVP5150_INT_CONF,0x04
-	},
 	{ /* 0xc8 */
 		TVP5150_FIFO_INT_THRESHOLD,0x80
 	},
@@ -420,9 +411,7 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
 
 /* Default values as sugested at TVP5150AM1 datasheet */
 static const struct i2c_reg_value tvp5150_init_enable[] = {
-	{
-		TVP5150_CONF_SHARED_PIN, 2
-	},{	/* Automatic offset and AGC enabled */
+	{	/* Automatic offset and AGC enabled */
 		TVP5150_ANAL_CHL_CTL, 0x15
 	},{	/* Activate YCrCb output 0x9 or 0xd ? */
 		TVP5150_MISC_CTL, 0x6f
@@ -772,6 +761,12 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 	/* Initializes TVP5150 to its default values */
 	tvp5150_write_inittab(sd, tvp5150_init_default);
 
+	/* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */
+	regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2);
+	/* Keep interrupt polarity active low */
+	regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE);
+	regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0);
+
 	/* Initializes VDP registers */
 	tvp5150_vdp_init(sd, vbi_ram_default);
 
diff --git a/drivers/media/i2c/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h
index 25a994944918..fc3bcb26413a 100644
--- a/drivers/media/i2c/tvp5150_reg.h
+++ b/drivers/media/i2c/tvp5150_reg.h
@@ -117,6 +117,7 @@
 #define TVP5150_INT_STATUS_REG_A    0xc0 /* Interrupt status register A */
 #define TVP5150_INT_ENABLE_REG_A    0xc1 /* Interrupt enable register A */
 #define TVP5150_INT_CONF            0xc2 /* Interrupt configuration */
+#define   TVP5150_VDPOE             BIT(2)
 #define TVP5150_VDP_CONF_RAM_DATA   0xc3 /* VDP configuration RAM data */
 #define TVP5150_CONF_RAM_ADDR_LOW   0xc4 /* Configuration RAM address low byte */
 #define TVP5150_CONF_RAM_ADDR_HIGH  0xc5 /* Configuration RAM address high byte */
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 8/9] [media] tvp5150: Add sync lock interrupt handling
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
                   ` (5 preceding siblings ...)
  2016-03-14 15:23 ` [PATCH v3 7/9] [media] tvp5150: remove pin configuration from initialization tables Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  2016-03-14 15:23 ` [PATCH v3 9/9] [media] tvp5150: disable output while signal not locked Lucas Stach
  7 siblings, 0 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

This patch adds an optional interrupt handler to handle the sync
lock interrupt and sync lock status.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c     | 103 ++++++++++++++++++++++++++++++++++++++--
 drivers/media/i2c/tvp5150_reg.h |   2 +
 2 files changed, 100 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index e0f5bc219ced..b5140253b648 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -9,6 +9,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
 #include <linux/of_graph.h>
@@ -44,12 +45,14 @@ struct tvp5150 {
 	struct v4l2_mbus_framefmt format;
 	struct v4l2_rect rect;
 	struct regmap *regmap;
+	int irq;
 
 	v4l2_std_id norm;	/* Current set standard */
 	v4l2_std_id detected_norm;
 	u32 input;
 	u32 output;
 	int enable;
+	bool lock;
 };
 
 static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
@@ -716,6 +719,15 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
 	return 0;
 }
 
+static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct tvp5150 *decoder = to_tvp5150(sd);
+
+	*std = decoder->norm;
+
+	return 0;
+}
+
 static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
@@ -758,14 +770,25 @@ static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
 
 static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 {
+	struct tvp5150 *decoder = to_tvp5150(sd);
+	struct regmap *map = decoder->regmap;
+
 	/* Initializes TVP5150 to its default values */
 	tvp5150_write_inittab(sd, tvp5150_init_default);
 
-	/* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */
-	regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2);
-	/* Keep interrupt polarity active low */
-	regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE);
-	regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0);
+	if (decoder->irq) {
+		/* Configure pins: FID, VSYNC, INTREQ, SCLK */
+		regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x0);
+		/* Set interrupt polarity to active high */
+		regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE | 0x1);
+		regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x1);
+	} else {
+		/* Configure pins: FID, VSYNC, GPCL/VBLK, SCLK */
+		regmap_write(map, TVP5150_CONF_SHARED_PIN, 0x2);
+		/* Keep interrupt polarity active low */
+		regmap_write(map, TVP5150_INT_CONF, TVP5150_VDPOE);
+		regmap_write(map, TVP5150_INTT_CONFIG_REG_B, 0x0);
+	}
 
 	/* Initializes VDP registers */
 	tvp5150_vdp_init(sd, vbi_ram_default);
@@ -776,6 +799,33 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 	return 0;
 }
 
+static irqreturn_t tvp5150_isr(int irq, void *dev_id)
+{
+	struct tvp5150 *decoder = dev_id;
+	struct regmap *map = decoder->regmap;
+	unsigned int active = 0, status = 0;
+
+	regmap_read(map, TVP5150_INT_STATUS_REG_A, &status);
+	if (status) {
+		regmap_write(map, TVP5150_INT_STATUS_REG_A, status);
+
+		if (status & TVP5150_INT_A_LOCK)
+			decoder->lock = !!(status & TVP5150_INT_A_LOCK_STATUS);
+
+		return IRQ_HANDLED;
+	}
+
+	regmap_read(map, TVP5150_INT_ACTIVE_REG_B, &active);
+	if (active) {
+		status = 0;
+		regmap_read(map, TVP5150_INT_STATUS_REG_B, &status);
+		if (status)
+			regmap_write(map, TVP5150_INT_RESET_REG_B, status);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int tvp5150_enable(struct v4l2_subdev *sd)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
@@ -939,6 +989,35 @@ static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
 	return 0;
 }
 
+static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+
+	if (enable) {
+		/* Enable YUV(OUT7:0), clock */
+		regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, 0xd,
+			(decoder->bus_type == V4L2_MBUS_BT656) ? 0x9 : 0xd);
+		if (decoder->irq) {
+			/* Enable lock interrupt */
+			regmap_update_bits(decoder->regmap,
+					   TVP5150_INT_ENABLE_REG_A,
+					   TVP5150_INT_A_LOCK,
+					   TVP5150_INT_A_LOCK);
+		}
+	} else {
+		/* Disable YUV(OUT7:0), SYNC, clock */
+		regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, 0xd, 0x0);
+		if (decoder->irq) {
+			/* Disable lock interrupt */
+			regmap_update_bits(decoder->regmap,
+					   TVP5150_INT_ENABLE_REG_A,
+					   TVP5150_INT_A_LOCK, 0);
+		}
+	}
+
+	return 0;
+}
+
 static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
 {
 	struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1254,9 +1333,11 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
 
 static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
 	.s_std = tvp5150_s_std,
+	.g_std = tvp5150_g_std,
 	.s_routing = tvp5150_s_routing,
 	.s_crop = tvp5150_s_crop,
 	.g_crop = tvp5150_g_crop,
+	.s_stream = tvp5150_s_stream,
 	.cropcap = tvp5150_cropcap,
 };
 
@@ -1465,7 +1546,19 @@ static int tvp5150_probe(struct i2c_client *c,
 	}
 	v4l2_ctrl_handler_setup(&core->hdl);
 
+	core->irq = c->irq;
 	tvp5150_reset(sd, 0);
+
+	if (c->irq) {
+		res = devm_request_threaded_irq(&c->dev, c->irq, NULL,
+				tvp5150_isr, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				"tvp5150", core);
+		if (res)
+			return res;
+	} else {
+		core->lock = true;
+	}
+
 	/* Default is no cropping */
 	tvp5150_set_default(tvp5150_read_std(sd), &core->rect, &core->format);
 
diff --git a/drivers/media/i2c/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h
index fc3bcb26413a..282a8a852e45 100644
--- a/drivers/media/i2c/tvp5150_reg.h
+++ b/drivers/media/i2c/tvp5150_reg.h
@@ -115,6 +115,8 @@
 #define TVP5150_TELETEXT_FIL_ENA    0xbb /* Teletext filter enable */
 /* Reserved	BCh-BFh */
 #define TVP5150_INT_STATUS_REG_A    0xc0 /* Interrupt status register A */
+#define   TVP5150_INT_A_LOCK_STATUS BIT(7)
+#define   TVP5150_INT_A_LOCK        BIT(6)
 #define TVP5150_INT_ENABLE_REG_A    0xc1 /* Interrupt enable register A */
 #define TVP5150_INT_CONF            0xc2 /* Interrupt configuration */
 #define   TVP5150_VDPOE             BIT(2)
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 9/9] [media] tvp5150: disable output while signal not locked
  2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
                   ` (6 preceding siblings ...)
  2016-03-14 15:23 ` [PATCH v3 8/9] [media] tvp5150: Add sync lock interrupt handling Lucas Stach
@ 2016-03-14 15:23 ` Lucas Stach
  7 siblings, 0 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-14 15:23 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, linux-media; +Cc: kernel, patchwork-lst

From: Philipp Zabel <p.zabel@pengutronix.de>

To avoid short frames on stream start, keep output pins at high impedance
while we are not properly locked onto the input signal.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
---
 drivers/media/i2c/tvp5150.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index b5140253b648..13ce826a4093 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -51,6 +51,7 @@ struct tvp5150 {
 	v4l2_std_id detected_norm;
 	u32 input;
 	u32 output;
+	u32 oe;
 	int enable;
 	bool lock;
 };
@@ -809,8 +810,11 @@ static irqreturn_t tvp5150_isr(int irq, void *dev_id)
 	if (status) {
 		regmap_write(map, TVP5150_INT_STATUS_REG_A, status);
 
-		if (status & TVP5150_INT_A_LOCK)
+		if (status & TVP5150_INT_A_LOCK) {
 			decoder->lock = !!(status & TVP5150_INT_A_LOCK_STATUS);
+			regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL,
+					   0xd, decoder->lock ? decoder->oe : 0);
+		}
 
 		return IRQ_HANDLED;
 	}
@@ -841,6 +845,7 @@ static int tvp5150_enable(struct v4l2_subdev *sd)
 				   0x7, 0x7);
 		/* disable HSYNC, VSYNC/PALI, AVID, and FID/GLCO */
 		regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, 0x4, 0x0);
+		decoder->oe = 0x9;
 		break;
 	case V4L2_MBUS_PARALLEL:
 		/* 8-bit YUV 4:2:2 */
@@ -848,6 +853,7 @@ static int tvp5150_enable(struct v4l2_subdev *sd)
 				   0x7, 0x0);
 		/* enable HSYNC, VSYNC/PALI, AVID, and FID/GLCO */
 		regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, 0x4, 0x4);
+		decoder->oe = 0xd;
 		break;
 	default:
 		return -EINVAL;
@@ -994,9 +1000,9 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
 	struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
 
 	if (enable) {
-		/* Enable YUV(OUT7:0), clock */
+		/* Enable YUV(OUT7:0), (SYNC), clock signal, if locked */
 		regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, 0xd,
-			(decoder->bus_type == V4L2_MBUS_BT656) ? 0x9 : 0xd);
+				   decoder->lock ? decoder->oe : 0);
 		if (decoder->irq) {
 			/* Enable lock interrupt */
 			regmap_update_bits(decoder->regmap,
-- 
2.7.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 2/9] [media] tvp5150: add userspace subdev API
  2016-03-14 15:23 ` [PATCH v3 2/9] [media] tvp5150: add userspace subdev API Lucas Stach
@ 2016-03-14 17:34   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 12+ messages in thread
From: Mauro Carvalho Chehab @ 2016-03-14 17:34 UTC (permalink / raw)
  To: Lucas Stach; +Cc: linux-media, kernel, patchwork-lst

Em Mon, 14 Mar 2016 16:23:30 +0100
Lucas Stach <l.stach@pengutronix.de> escreveu:

> From: Philipp Zabel <p.zabel@pengutronix.de>
> 
> This patch adds userspace V4L2 subdevice API support.
> 
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> ---
>  drivers/media/i2c/tvp5150.c | 282 +++++++++++++++++++++++++++++++++++---------
>  1 file changed, 223 insertions(+), 59 deletions(-)
> 
> diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
> index 6ba93a425640..67312c9d83c1 100644
> --- a/drivers/media/i2c/tvp5150.c
> +++ b/drivers/media/i2c/tvp5150.c
> @@ -36,7 +36,9 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
>  
>  struct tvp5150 {
>  	struct v4l2_subdev sd;
> +	struct media_pad pad;

Huh? tvp5150 has already pads on it:

struct tvp5150 {
	struct v4l2_subdev sd;
#ifdef CONFIG_MEDIA_CONTROLLER
	struct media_pad pads[DEMOD_NUM_PADS];
	struct media_entity input_ent[TVP5150_INPUT_NUM];
	struct media_pad input_pad[TVP5150_INPUT_NUM];
#endif
	struct v4l2_ctrl_handler hdl;
	struct v4l2_rect rect;

	v4l2_std_id norm;	/* Current set standard */
	u32 input;
	u32 output;
	int enable;

	u16 dev_id;
	u16 rom_ver;

	enum v4l2_mbus_type mbus_type;
};

It seems that your patchset is not based on the latest version of
the driver. Please rebase it on the top of the media tree:

	https://git.linuxtv.org/media_tree.git/

Regards,
Mauro

>  	struct v4l2_ctrl_handler hdl;
> +	struct v4l2_mbus_framefmt format;
>  	struct v4l2_rect rect;
>  	struct regmap *regmap;
>  
> @@ -819,38 +821,68 @@ static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd,
>  	return 0;
>  }
>  
> -static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
> -		struct v4l2_subdev_pad_config *cfg,
> -		struct v4l2_subdev_format *format)
> +static void tvp5150_try_crop(struct tvp5150 *decoder, struct v4l2_rect *rect,
> +			       v4l2_std_id std)
>  {
> -	struct v4l2_mbus_framefmt *f;
> -	struct tvp5150 *decoder = to_tvp5150(sd);
> +	unsigned int hmax;
>  
> -	if (!format || format->pad)
> -		return -EINVAL;
> +	/* Clamp the crop rectangle boundaries to tvp5150 limits */
> +	rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
> +	rect->width = clamp(rect->width,
> +			    TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left,
> +			    TVP5150_H_MAX - rect->left);
> +	rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
>  
> -	f = &format->format;
> +	/* tvp5150 has some special limits */
> +	rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
> +	rect->width = clamp_t(unsigned int, rect->width,
> +			      TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left,
> +			      TVP5150_H_MAX - rect->left);
> +	rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
> +
> +	/* Calculate height based on current standard */
> +	if (std & V4L2_STD_525_60)
> +		hmax = TVP5150_V_MAX_525_60;
> +	else
> +		hmax = TVP5150_V_MAX_OTHERS;
>  
> -	tvp5150_reset(sd, 0);
> +	rect->height = clamp(rect->height,
> +			     hmax - TVP5150_MAX_CROP_TOP - rect->top,
> +			     hmax - rect->top);
> +}
>  
> -	f->width = decoder->rect.width;
> -	f->height = decoder->rect.height;
> +static void tvp5150_set_crop(struct tvp5150 *decoder, struct v4l2_rect *rect,
> +			       v4l2_std_id std)
> +{
> +	struct regmap *map = decoder->regmap;
> +	unsigned int hmax;
>  
> -	f->code = MEDIA_BUS_FMT_UYVY8_2X8;
> -	f->field = V4L2_FIELD_SEQ_TB;
> -	f->colorspace = V4L2_COLORSPACE_SMPTE170M;
> +	if (std & V4L2_STD_525_60)
> +		hmax = TVP5150_V_MAX_525_60;
> +	else
> +		hmax = TVP5150_V_MAX_OTHERS;
>  
> -	v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width,
> -			f->height);
> -	return 0;
> +	regmap_write(map, TVP5150_VERT_BLANKING_START, rect->top);
> +	regmap_write(map, TVP5150_VERT_BLANKING_STOP,
> +		     rect->top + rect->height - hmax);
> +	regmap_write(map, TVP5150_ACT_VD_CROP_ST_MSB,
> +		     rect->left >> TVP5150_CROP_SHIFT);
> +	regmap_write(map, TVP5150_ACT_VD_CROP_ST_LSB,
> +		     rect->left | (1 << TVP5150_CROP_SHIFT));
> +	regmap_write(map, TVP5150_ACT_VD_CROP_STP_MSB,
> +		     (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >>
> +		     TVP5150_CROP_SHIFT);
> +	regmap_write(map, TVP5150_ACT_VD_CROP_STP_LSB,
> +		     rect->left + rect->width - TVP5150_MAX_CROP_LEFT);
> +
> +	decoder->rect = *rect;
>  }
>  
>  static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
>  {
> -	struct v4l2_rect rect = a->c;
>  	struct tvp5150 *decoder = to_tvp5150(sd);
> +	struct v4l2_rect rect = a->c;
>  	v4l2_std_id std;
> -	unsigned int hmax;
>  
>  	v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
>  		__func__, rect.left, rect.top, rect.width, rect.height);
> @@ -858,42 +890,13 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
>  	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>  		return -EINVAL;
>  
> -	/* tvp5150 has some special limits */
> -	rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
> -	rect.width = clamp_t(unsigned int, rect.width,
> -			     TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
> -			     TVP5150_H_MAX - rect.left);
> -	rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
> -
> -	/* Calculate height based on current standard */
>  	if (decoder->norm == V4L2_STD_ALL)
>  		std = tvp5150_read_std(sd);
>  	else
>  		std = decoder->norm;
>  
> -	if (std & V4L2_STD_525_60)
> -		hmax = TVP5150_V_MAX_525_60;
> -	else
> -		hmax = TVP5150_V_MAX_OTHERS;
> -
> -	rect.height = clamp_t(unsigned int, rect.height,
> -			      hmax - TVP5150_MAX_CROP_TOP - rect.top,
> -			      hmax - rect.top);
> -
> -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
> -	regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
> -		      rect.top + rect.height - hmax);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
> -		      rect.left >> TVP5150_CROP_SHIFT);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
> -		      rect.left | (1 << TVP5150_CROP_SHIFT));
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
> -		      (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
> -		      TVP5150_CROP_SHIFT);
> -	regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
> -		      rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
> -
> -	decoder->rect = rect;
> +	tvp5150_try_crop(decoder, &rect, std);
> +	tvp5150_set_crop(decoder, &rect, std);
>  
>  	return 0;
>  }
> @@ -1049,6 +1052,153 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
>  
>  /* ----------------------------------------------------------------------- */
>  
> +static struct v4l2_mbus_framefmt *
> +tvp5150_get_pad_format(struct tvp5150 *decoder, struct v4l2_subdev *sd,
> +			 struct v4l2_subdev_pad_config *cfg, unsigned int pad,
> +			 enum v4l2_subdev_format_whence which)
> +{
> +	switch (which) {
> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		return v4l2_subdev_get_try_format(sd, cfg, pad);
> +#endif
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &decoder->format;
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +static struct v4l2_rect *
> +tvp5150_get_pad_crop(struct tvp5150 *decoder, struct v4l2_subdev *sd,
> +		       struct v4l2_subdev_pad_config *cfg, unsigned int pad,
> +		       enum v4l2_subdev_format_whence which)
> +{
> +	switch (which) {
> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		return v4l2_subdev_get_try_crop(sd, cfg, pad);
> +#endif
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &decoder->rect;
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
> +				   struct v4l2_subdev_pad_config *cfg,
> +				   struct v4l2_subdev_frame_size_enum *fse)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	v4l2_std_id std;
> +
> +	if (fse->index > 0 || fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
> +		return -EINVAL;
> +
> +	fse->min_width = TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT;
> +	fse->max_width = TVP5150_H_MAX;
> +
> +	/* Calculate height based on current standard */
> +	if (decoder->norm == V4L2_STD_ALL)
> +		std = tvp5150_read_std(sd);
> +	else
> +		std = decoder->norm;
> +
> +	if (std & V4L2_STD_525_60) {
> +		fse->min_height = TVP5150_V_MAX_525_60 - TVP5150_MAX_CROP_TOP;
> +		fse->max_height = TVP5150_V_MAX_525_60;
> +	} else {
> +		fse->min_height = TVP5150_V_MAX_OTHERS - TVP5150_MAX_CROP_TOP;
> +		fse->max_height = TVP5150_V_MAX_OTHERS;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tvp5150_get_format(struct v4l2_subdev *sd,
> +			      struct v4l2_subdev_pad_config *cfg,
> +			      struct v4l2_subdev_format *format)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	struct v4l2_mbus_framefmt *mbus_format;
> +
> +	mbus_format = tvp5150_get_pad_format(decoder, sd, cfg,
> +					     format->pad, format->which);
> +	if (!mbus_format)
> +		return -ENOTTY;
> +
> +	format->format = *mbus_format;
> +
> +	return 0;
> +}
> +
> +static int tvp5150_set_format(struct v4l2_subdev *sd,
> +			      struct v4l2_subdev_pad_config *cfg,
> +			      struct v4l2_subdev_format *format)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	struct v4l2_mbus_framefmt *mbus_format;
> +	struct v4l2_rect *crop;
> +
> +	crop = tvp5150_get_pad_crop(decoder, sd, cfg, format->pad,
> +				    format->which);
> +	mbus_format = tvp5150_get_pad_format(decoder, sd, cfg, format->pad,
> +					     format->which);
> +	if (!crop || !mbus_format)
> +		return -ENOTTY;
> +
> +	mbus_format->width = crop->width;
> +	mbus_format->height = crop->height;
> +
> +	format->format = *mbus_format;
> +
> +	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
> +		tvp5150_reset(sd, 0);
> +
> +	v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", mbus_format->width,
> +			mbus_format->height);
> +
> +	return 0;
> +}
> +
> +static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop,
> +				struct v4l2_mbus_framefmt *format)
> +{
> +	crop->left = 0;
> +	crop->width = TVP5150_H_MAX;
> +	crop->top = 0;
> +	if (std & V4L2_STD_525_60)
> +		crop->height = TVP5150_V_MAX_525_60;
> +	else
> +		crop->height = TVP5150_V_MAX_OTHERS;
> +
> +	format->width = crop->width;
> +	format->height = crop->height;
> +	format->code = MEDIA_BUS_FMT_UYVY8_2X8;
> +	format->field = V4L2_FIELD_SEQ_TB;
> +	format->colorspace = V4L2_COLORSPACE_SMPTE170M;
> +}
> +
> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
> +static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> +{
> +	struct tvp5150 *decoder = to_tvp5150(sd);
> +	v4l2_std_id std;
> +
> +	if (decoder->norm == V4L2_STD_ALL)
> +		std = tvp5150_read_std(sd);
> +	else
> +		std = decoder->norm;
> +
> +	tvp5150_set_default(std, v4l2_subdev_get_try_crop(fh, 0),
> +				 v4l2_subdev_get_try_format(fh, 0));
> +	return 0;
> +}
> +#endif
> +
> +/* ----------------------------------------------------------------------- */
> +
>  static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
>  	.s_ctrl = tvp5150_s_ctrl,
>  };
> @@ -1083,8 +1233,9 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
>  
>  static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
>  	.enum_mbus_code = tvp5150_enum_mbus_code,
> -	.set_fmt = tvp5150_fill_fmt,
> -	.get_fmt = tvp5150_fill_fmt,
> +	.enum_frame_size = tvp5150_enum_frame_size,
> +	.get_fmt = tvp5150_get_format,
> +	.set_fmt = tvp5150_set_format,
>  };
>  
>  static const struct v4l2_subdev_ops tvp5150_ops = {
> @@ -1095,6 +1246,11 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
>  	.pad = &tvp5150_pad_ops,
>  };
>  
> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
> +static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
> +	.open = tvp5150_open,
> +};
> +#endif
>  
>  /****************************************************************************
>  			I2C Client & Driver
> @@ -1197,6 +1353,19 @@ static int tvp5150_probe(struct i2c_client *c,
>  	sd = &core->sd;
>  	v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
>  
> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
> +	sd->internal_ops = &tvp5150_internal_ops;
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> +#endif
> +#ifdef CONFIG_MEDIA_CONTROLLER
> +	sd->entity.flags |= MEDIA_ENT_F_ATV_DECODER;
> +	core->pad.flags = MEDIA_PAD_FL_SOURCE;
> +	res = media_entity_pads_init(&sd->entity, 1, &core->pad);
> +	if (res < 0)
> +		return res;
> +#endif
> +
>  	/* 
>  	 * Read consequent registers - TVP5150_MSB_DEV_ID, TVP5150_LSB_DEV_ID,
>  	 * TVP5150_ROM_MAJOR_VER, TVP5150_ROM_MINOR_VER 
> @@ -1250,14 +1419,9 @@ static int tvp5150_probe(struct i2c_client *c,
>  	v4l2_ctrl_handler_setup(&core->hdl);
>  
>  	/* Default is no cropping */
> -	core->rect.top = 0;
> -	if (tvp5150_read_std(sd) & V4L2_STD_525_60)
> -		core->rect.height = TVP5150_V_MAX_525_60;
> -	else
> -		core->rect.height = TVP5150_V_MAX_OTHERS;
> -	core->rect.left = 0;
> -	core->rect.width = TVP5150_H_MAX;
> +	tvp5150_set_default(tvp5150_read_std(sd), &core->rect, &core->format);
>  
> +	sd->dev = &c->dev;
>  	res = v4l2_async_register_subdev(sd);
>  	if (res < 0)
>  		goto err;


-- 
Thanks,
Mauro

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/9] [media] tvp5150: determine BT.656 or YUV 4:2:2 mode from device tree
  2016-03-14 15:23 ` [PATCH v3 3/9] [media] tvp5150: determine BT.656 or YUV 4:2:2 mode from device tree Lucas Stach
@ 2016-03-14 18:19   ` Javier Martinez Canillas
  2016-03-15 10:26     ` Lucas Stach
  0 siblings, 1 reply; 12+ messages in thread
From: Javier Martinez Canillas @ 2016-03-14 18:19 UTC (permalink / raw)
  To: Lucas Stach
  Cc: Mauro Carvalho Chehab, Linux Media Mailing List, Sascha Hauer,
	patchwork-lst

Hello Lucas,

On Mon, Mar 14, 2016 at 12:23 PM, Lucas Stach <l.stach@pengutronix.de> wrote:
> From: Philipp Zabel <p.zabel@pengutronix.de>
>
> By looking at the endpoint flags, it can be determined whether the link
> should be of V4L2_MBUS_PARALLEL or V4L2_MBUS_BT656 type. Disable the
> dedicated HSYNC/VSYNC outputs in BT.656 mode.
>
> For devices that are not instantiated through DT the current behavior
> is preserved.
>
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> ---

Similar to Mauro's comment on patch 2/9, the current driver already
supports configuring the interface output format using DT.

Best regards,
Javier

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 3/9] [media] tvp5150: determine BT.656 or YUV 4:2:2 mode from device tree
  2016-03-14 18:19   ` Javier Martinez Canillas
@ 2016-03-15 10:26     ` Lucas Stach
  0 siblings, 0 replies; 12+ messages in thread
From: Lucas Stach @ 2016-03-15 10:26 UTC (permalink / raw)
  To: Javier Martinez Canillas
  Cc: Linux Media Mailing List, patchwork-lst, Sascha Hauer,
	Mauro Carvalho Chehab

Am Montag, den 14.03.2016, 15:19 -0300 schrieb Javier Martinez Canillas:
> Hello Lucas,
> 
> On Mon, Mar 14, 2016 at 12:23 PM, Lucas Stach <l.stach@pengutronix.de> wrote:
> > From: Philipp Zabel <p.zabel@pengutronix.de>
> >
> > By looking at the endpoint flags, it can be determined whether the link
> > should be of V4L2_MBUS_PARALLEL or V4L2_MBUS_BT656 type. Disable the
> > dedicated HSYNC/VSYNC outputs in BT.656 mode.
> >
> > For devices that are not instantiated through DT the current behavior
> > is preserved.
> >
> > Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> > Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
> > ---
> 
> Similar to Mauro's comment on patch 2/9, the current driver already
> supports configuring the interface output format using DT.

Sorry about that. I've lost touch with the current media tree, will look
into what is already there. Sorry for the noise.



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2016-03-15 10:26 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-14 15:23 [PATCH v3 1/9] [media] tvp5150: convert register access to regmap Lucas Stach
2016-03-14 15:23 ` [PATCH v3 2/9] [media] tvp5150: add userspace subdev API Lucas Stach
2016-03-14 17:34   ` Mauro Carvalho Chehab
2016-03-14 15:23 ` [PATCH v3 3/9] [media] tvp5150: determine BT.656 or YUV 4:2:2 mode from device tree Lucas Stach
2016-03-14 18:19   ` Javier Martinez Canillas
2016-03-15 10:26     ` Lucas Stach
2016-03-14 15:23 ` [PATCH v3 4/9] [media] tvp5150: fix standard autodetection Lucas Stach
2016-03-14 15:23 ` [PATCH v3 5/9] [media] tvp5150: split reset/enable routine Lucas Stach
2016-03-14 15:23 ` [PATCH v3 6/9] [media] tvp5150: trigger autodetection on subdev open to reset cropping Lucas Stach
2016-03-14 15:23 ` [PATCH v3 7/9] [media] tvp5150: remove pin configuration from initialization tables Lucas Stach
2016-03-14 15:23 ` [PATCH v3 8/9] [media] tvp5150: Add sync lock interrupt handling Lucas Stach
2016-03-14 15:23 ` [PATCH v3 9/9] [media] tvp5150: disable output while signal not locked Lucas Stach

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.