* [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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).