diff options
author | Philipp Zabel <p.zabel@pengutronix.de> | 2018-06-28 18:20:44 +0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | 2018-09-17 19:30:28 +0200 |
commit | 8e4c97e0f50ac2de28b2ef26a763533623e16cf7 (patch) | |
tree | 89f4ff4a80da9cfd3bbf5c8c5403c185222cbc33 /drivers/media/i2c/tvp5150.c | |
parent | media: tvp5150: remove pin configuration from initialization tables (diff) | |
download | linux-8e4c97e0f50ac2de28b2ef26a763533623e16cf7.tar.xz linux-8e4c97e0f50ac2de28b2ef26a763533623e16cf7.zip |
media: tvp5150: Add sync lock interrupt handling
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>
[m.felsch@pengutronix.de: move added .g_std callback to separate patch]
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'drivers/media/i2c/tvp5150.c')
-rw-r--r-- | drivers/media/i2c/tvp5150.c | 63 |
1 files changed, 60 insertions, 3 deletions
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index eeb48ad01696..b66fc4e3ecbb 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/gpio/consumer.h> +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/of_graph.h> #include <linux/regmap.h> @@ -58,12 +59,14 @@ struct tvp5150 { struct v4l2_ctrl_handler hdl; 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; u16 dev_id; u16 rom_ver; @@ -797,6 +800,33 @@ static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) } } +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_reset(struct v4l2_subdev *sd, u32 val) { struct tvp5150 *decoder = to_tvp5150(sd); @@ -805,8 +835,19 @@ 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); + 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); @@ -1108,7 +1149,7 @@ static const struct media_entity_operations tvp5150_sd_media_ops = { static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) { struct tvp5150 *decoder = to_tvp5150(sd); - unsigned int mask, val = 0; + unsigned int mask, val = 0, int_val = 0; mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | TVP5150_MISC_CTL_CLOCK_OE; @@ -1123,9 +1164,15 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) val = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_CLOCK_OE; if (decoder->mbus_type == V4L2_MBUS_PARALLEL) val |= TVP5150_MISC_CTL_SYNC_OE; + + int_val = TVP5150_INT_A_LOCK; } regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val); + if (decoder->irq) + /* Enable / Disable lock interrupt */ + regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A, + TVP5150_INT_A_LOCK, int_val); return 0; } @@ -1676,7 +1723,17 @@ static int tvp5150_probe(struct i2c_client *c, tvp5150_set_default(tvp5150_read_std(sd), &core->rect); + core->irq = c->irq; tvp5150_reset(sd, 0); /* Calls v4l2_ctrl_handler_setup() */ + 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; + } res = v4l2_async_register_subdev(sd); if (res < 0) |