diff mbox

[v2,8/9,media] tvp5150: Add sync lock interrupt handling

Message ID 1448473116-24735-8-git-send-email-l.stach@pengutronix.de (mailing list archive)
State New, archived
Headers show

Commit Message

Lucas Stach Nov. 25, 2015, 5:38 p.m. UTC
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 mbox

Patch

diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index ceda29aa23f9..85c5c73098fa 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)