|
@@ -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)
|