linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/16] [media] adv7180: Add support for different chip
@ 2015-01-13 12:01 Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 01/16] [media] adv7180: Do not request the IRQ again during resume Lars-Peter Clausen
                   ` (16 more replies)
  0 siblings, 17 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

The adv7180 is part of a larger family of chips which all implement
different features from a feature superset. This patch series step by step
extends the current adv7180 with features from the superset that are
currently not supported and gradually adding support for more variations of
the chip.

The first half of this series contains fixes and cleanups while the second
half adds new features and support for new chips.

- Lars

Lars-Peter Clausen (16):
  [media] adv7180: Do not request the IRQ again during resume
  [media] adv7180: Pass correct flags to request_threaded_irq()
  [media] adv7180: Use inline function instead of macro
  [media] adv7180: Cleanup register define naming
  [media] adv7180: Do implicit register paging
  [media] adv7180: Reset the device before initialization
  [media] adv7180: Add media controller support
  [media] adv7180: Consolidate video mode setting
  [media] adv7180: Prepare for multi-chip support
  [media] adv7180: Add support for the ad7182
  [media] adv7180: Add support for the adv7280/adv7281/adv7282
  [media] adv7180: Add support for the
    adv7280-m/adv7281-m/adv7281-ma/adv7282-m
  [media] adv7180: Add I2P support
  [media] adv7180: Add fast switch support
  [media] adv7180: Add free run mode controls
  [media] Add MAINTAINERS entry for the adv7180

 MAINTAINERS                       |    7 +
 drivers/media/i2c/Kconfig         |    2 +-
 drivers/media/i2c/adv7180.c       | 1137 ++++++++++++++++++++++++++++++-------
 drivers/media/pci/sta2x11/Kconfig |    1 +
 drivers/media/platform/Kconfig    |    2 +-
 5 files changed, 947 insertions(+), 202 deletions(-)

-- 
1.8.0


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

* [PATCH 01/16] [media] adv7180: Do not request the IRQ again during resume
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 02/16] [media] adv7180: Pass correct flags to request_threaded_irq() Lars-Peter Clausen
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Currently the IRQ is requested from within the init_device() function. This
function is not only called during device probe, but also during resume
causing the driver to try to request the IRQ again. Move requesting the IRQ
from init_device() to the probe function to make sure that it is only
requested once.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index bffe6eb..172e4a2 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -553,11 +553,6 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
 
 	/* register for interrupts */
 	if (state->irq > 0) {
-		ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
-					   IRQF_ONESHOT, KBUILD_MODNAME, state);
-		if (ret)
-			return ret;
-
 		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
 						ADV7180_ADI_CTRL_IRQ_SPACE);
 		if (ret < 0)
@@ -597,7 +592,6 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
 	return 0;
 
 err:
-	free_irq(state->irq, state);
 	return ret;
 }
 
@@ -636,6 +630,13 @@ static int adv7180_probe(struct i2c_client *client,
 	if (ret)
 		goto err_free_ctrl;
 
+	if (state->irq) {
+		ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
+					   IRQF_ONESHOT, KBUILD_MODNAME, state);
+		if (ret)
+			goto err_free_ctrl;
+	}
+
 	ret = v4l2_async_register_subdev(sd);
 	if (ret)
 		goto err_free_irq;
-- 
1.8.0


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

* [PATCH 02/16] [media] adv7180: Pass correct flags to request_threaded_irq()
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 01/16] [media] adv7180: Do not request the IRQ again during resume Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 03/16] [media] adv7180: Use inline function instead of macro Lars-Peter Clausen
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Most IRQ controllers support different types of interrupts. The adv7180
generates falling edge interrupts, so make sure to pass IRQF_TRIGGER_FALLING
to request_threaded_irq() so the IRQ controller is configured for the
correct mode.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 172e4a2..f424a4d 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -632,7 +632,8 @@ static int adv7180_probe(struct i2c_client *client,
 
 	if (state->irq) {
 		ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
-					   IRQF_ONESHOT, KBUILD_MODNAME, state);
+					   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+					   KBUILD_MODNAME, state);
 		if (ret)
 			goto err_free_ctrl;
 	}
-- 
1.8.0


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

* [PATCH 03/16] [media] adv7180: Use inline function instead of macro
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 01/16] [media] adv7180: Do not request the IRQ again during resume Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 02/16] [media] adv7180: Pass correct flags to request_threaded_irq() Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 04/16] [media] adv7180: Cleanup register define naming Lars-Peter Clausen
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Use a inline function instead of a macro for the container_of helper for
getting the driver's state struct from a control. A inline function has the
advantage that it is more typesafe and nicer in general.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index f424a4d..f2508abe 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -130,9 +130,11 @@ struct adv7180_state {
 	bool			powered;
 	u8			input;
 };
-#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler,		\
-					    struct adv7180_state,	\
-					    ctrl_hdl)->sd)
+
+static struct adv7180_state *ctrl_to_adv7180(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct adv7180_state, ctrl_hdl);
+}
 
 static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 {
@@ -345,9 +347,8 @@ static int adv7180_s_power(struct v4l2_subdev *sd, int on)
 
 static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
-	struct adv7180_state *state = to_state(sd);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	struct adv7180_state *state = ctrl_to_adv7180(ctrl);
+	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
 	int ret = mutex_lock_interruptible(&state->mutex);
 	int val;
 
-- 
1.8.0


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

* [PATCH 04/16] [media] adv7180: Cleanup register define naming
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (2 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 03/16] [media] adv7180: Use inline function instead of macro Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 05/16] [media] adv7180: Do implicit register paging Lars-Peter Clausen
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Consistently prefix register defines with ADV7180_REG. Also remove the "ADI"
from register names, the ADV7180 prefix should provide enough of a namespace
separation.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 105 ++++++++++++++++++++++----------------------
 1 file changed, 52 insertions(+), 53 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index f2508abe..00ba845 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -31,7 +31,7 @@
 #include <media/v4l2-ctrls.h>
 #include <linux/mutex.h>
 
-#define ADV7180_INPUT_CONTROL_REG			0x00
+#define ADV7180_REG_INPUT_CONTROL			0x00
 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
 #define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
@@ -50,36 +50,36 @@
 #define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
 #define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
 
-#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG		0x04
+#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL		0x04
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
 
-#define ADV7180_AUTODETECT_ENABLE_REG			0x07
+#define ADV7180_REG_AUTODETECT_ENABLE			0x07
 #define ADV7180_AUTODETECT_DEFAULT			0x7f
 /* Contrast */
-#define ADV7180_CON_REG		0x08	/*Unsigned */
+#define ADV7180_REG_CON		0x08	/*Unsigned */
 #define ADV7180_CON_MIN		0
 #define ADV7180_CON_DEF		128
 #define ADV7180_CON_MAX		255
 /* Brightness*/
-#define ADV7180_BRI_REG		0x0a	/*Signed */
+#define ADV7180_REG_BRI		0x0a	/*Signed */
 #define ADV7180_BRI_MIN		-128
 #define ADV7180_BRI_DEF		0
 #define ADV7180_BRI_MAX		127
 /* Hue */
-#define ADV7180_HUE_REG		0x0b	/*Signed, inverted */
+#define ADV7180_REG_HUE		0x0b	/*Signed, inverted */
 #define ADV7180_HUE_MIN		-127
 #define ADV7180_HUE_DEF		0
 #define ADV7180_HUE_MAX		128
 
-#define ADV7180_ADI_CTRL_REG				0x0e
-#define ADV7180_ADI_CTRL_IRQ_SPACE			0x20
+#define ADV7180_REG_CTRL		0x0e
+#define ADV7180_CTRL_IRQ_SPACE		0x20
 
-#define ADV7180_PWR_MAN_REG		0x0f
+#define ADV7180_REG_PWR_MAN		0x0f
 #define ADV7180_PWR_MAN_ON		0x04
 #define ADV7180_PWR_MAN_OFF		0x24
 #define ADV7180_PWR_MAN_RES		0x80
 
-#define ADV7180_STATUS1_REG				0x10
+#define ADV7180_REG_STATUS1		0x10
 #define ADV7180_STATUS1_IN_LOCK		0x01
 #define ADV7180_STATUS1_AUTOD_MASK	0x70
 #define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
@@ -91,33 +91,33 @@
 #define ADV7180_STATUS1_AUTOD_PAL_COMB	0x60
 #define ADV7180_STATUS1_AUTOD_SECAM_525	0x70
 
-#define ADV7180_IDENT_REG 0x11
+#define ADV7180_REG_IDENT 0x11
 #define ADV7180_ID_7180 0x18
 
-#define ADV7180_ICONF1_ADI		0x40
+#define ADV7180_REG_ICONF1		0x40
 #define ADV7180_ICONF1_ACTIVE_LOW	0x01
 #define ADV7180_ICONF1_PSYNC_ONLY	0x10
 #define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
 /* Saturation */
-#define ADV7180_SD_SAT_CB_REG	0xe3	/*Unsigned */
-#define ADV7180_SD_SAT_CR_REG	0xe4	/*Unsigned */
+#define ADV7180_REG_SD_SAT_CB	0xe3	/*Unsigned */
+#define ADV7180_REG_SD_SAT_CR	0xe4	/*Unsigned */
 #define ADV7180_SAT_MIN		0
 #define ADV7180_SAT_DEF		128
 #define ADV7180_SAT_MAX		255
 
 #define ADV7180_IRQ1_LOCK	0x01
 #define ADV7180_IRQ1_UNLOCK	0x02
-#define ADV7180_ISR1_ADI	0x42
-#define ADV7180_ICR1_ADI	0x43
-#define ADV7180_IMR1_ADI	0x44
-#define ADV7180_IMR2_ADI	0x48
+#define ADV7180_REG_ISR1	0x42
+#define ADV7180_REG_ICR1	0x43
+#define ADV7180_REG_IMR1	0x44
+#define ADV7180_REG_IMR2	0x48
 #define ADV7180_IRQ3_AD_CHANGE	0x08
-#define ADV7180_ISR3_ADI	0x4A
-#define ADV7180_ICR3_ADI	0x4B
-#define ADV7180_IMR3_ADI	0x4C
-#define ADV7180_IMR4_ADI	0x50
+#define ADV7180_REG_ISR3	0x4A
+#define ADV7180_REG_ICR3	0x4B
+#define ADV7180_REG_IMR3	0x4C
+#define ADV7180_REG_IMR4	0x50
 
-#define ADV7180_NTSC_V_BIT_END_REG	0xE6
+#define ADV7180_REG_NTSC_V_BIT_END	0xE6
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
 
 struct adv7180_state {
@@ -198,7 +198,7 @@ static u32 adv7180_status_to_v4l2(u8 status1)
 static int __adv7180_status(struct i2c_client *client, u32 *status,
 			    v4l2_std_id *std)
 {
-	int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
+	int status1 = i2c_smbus_read_byte_data(client, ADV7180_REG_STATUS1);
 
 	if (status1 < 0)
 		return status1;
@@ -249,14 +249,13 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
 	if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
 		goto out;
 
-	ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
-
+	ret = i2c_smbus_read_byte_data(client, ADV7180_REG_INPUT_CONTROL);
 	if (ret < 0)
 		goto out;
 
 	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
 	ret = i2c_smbus_write_byte_data(client,
-					ADV7180_INPUT_CONTROL_REG, ret | input);
+					ADV7180_REG_INPUT_CONTROL, ret | input);
 	state->input = input;
 out:
 	mutex_unlock(&state->mutex);
@@ -286,7 +285,7 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 	/* all standards -> autodetect */
 	if (std == V4L2_STD_ALL) {
 		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+		    i2c_smbus_write_byte_data(client, ADV7180_REG_INPUT_CONTROL,
 				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
 					      | state->input);
 		if (ret < 0)
@@ -300,7 +299,7 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 			goto out;
 
 		ret = i2c_smbus_write_byte_data(client,
-						ADV7180_INPUT_CONTROL_REG,
+						ADV7180_REG_INPUT_CONTROL,
 						ret | state->input);
 		if (ret < 0)
 			goto out;
@@ -324,7 +323,7 @@ static int adv7180_set_power(struct adv7180_state *state,
 	else
 		val = ADV7180_PWR_MAN_OFF;
 
-	return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val);
+	return i2c_smbus_write_byte_data(client, ADV7180_REG_PWR_MAN, val);
 }
 
 static int adv7180_s_power(struct v4l2_subdev *sd, int on)
@@ -357,25 +356,25 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 	val = ctrl->val;
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_BRI, val);
 		break;
 	case V4L2_CID_HUE:
 		/*Hue is inverted according to HSL chart */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_HUE, -val);
 		break;
 	case V4L2_CID_CONTRAST:
-		ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_CON, val);
 		break;
 	case V4L2_CID_SATURATION:
 		/*
 		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
 		 *Let's not confuse the user, everybody understands saturation
 		 */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_SD_SAT_CB,
 						val);
 		if (ret < 0)
 			break;
-		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_SD_SAT_CR,
 						val);
 		break;
 	default:
@@ -489,12 +488,12 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
 	u8 isr3;
 
 	mutex_lock(&state->mutex);
-	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-				  ADV7180_ADI_CTRL_IRQ_SPACE);
-	isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
+	i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL,
+				  ADV7180_CTRL_IRQ_SPACE);
+	isr3 = i2c_smbus_read_byte_data(client, ADV7180_REG_ISR3);
 	/* clear */
-	i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
-	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
+	i2c_smbus_write_byte_data(client, ADV7180_REG_ICR3, isr3);
+	i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL, 0);
 
 	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
 		__adv7180_status(client, NULL, &state->curr_norm);
@@ -511,7 +510,7 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
 	/* Enable autodetection */
 	if (state->autodetect) {
 		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+		    i2c_smbus_write_byte_data(client, ADV7180_REG_INPUT_CONTROL,
 				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
 					      | state->input);
 		if (ret < 0)
@@ -519,7 +518,7 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
 
 		ret =
 		    i2c_smbus_write_byte_data(client,
-					      ADV7180_AUTODETECT_ENABLE_REG,
+					      ADV7180_REG_AUTODETECT_ENABLE,
 					      ADV7180_AUTODETECT_DEFAULT);
 		if (ret < 0)
 			return ret;
@@ -529,7 +528,7 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
 			return ret;
 
 		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+		    i2c_smbus_write_byte_data(client, ADV7180_REG_INPUT_CONTROL,
 					      ret | state->input);
 		if (ret < 0)
 			return ret;
@@ -537,14 +536,14 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
 	}
 	/* ITU-R BT.656-4 compatible */
 	ret = i2c_smbus_write_byte_data(client,
-			ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
+			ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
 			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
 	if (ret < 0)
 		return ret;
 
 	/* Manually set V bit end position in NTSC mode */
 	ret = i2c_smbus_write_byte_data(client,
-					ADV7180_NTSC_V_BIT_END_REG,
+					ADV7180_REG_NTSC_V_BIT_END,
 					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
 	if (ret < 0)
 		return ret;
@@ -554,37 +553,37 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
 
 	/* register for interrupts */
 	if (state->irq > 0) {
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
-						ADV7180_ADI_CTRL_IRQ_SPACE);
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL,
+						ADV7180_CTRL_IRQ_SPACE);
 		if (ret < 0)
 			goto err;
 
 		/* config the Interrupt pin to be active low */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_ICONF1,
 						ADV7180_ICONF1_ACTIVE_LOW |
 						ADV7180_ICONF1_PSYNC_ONLY);
 		if (ret < 0)
 			goto err;
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR1, 0);
 		if (ret < 0)
 			goto err;
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR2, 0);
 		if (ret < 0)
 			goto err;
 
 		/* enable AD change interrupts interrupts */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR3,
 						ADV7180_IRQ3_AD_CHANGE);
 		if (ret < 0)
 			goto err;
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR4, 0);
 		if (ret < 0)
 			goto err;
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
+		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL,
 						0);
 		if (ret < 0)
 			goto err;
-- 
1.8.0


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

* [PATCH 05/16] [media] adv7180: Do implicit register paging
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (3 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 04/16] [media] adv7180: Cleanup register define naming Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 06/16] [media] adv7180: Reset the device before initialization Lars-Peter Clausen
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

The ad7180 has multiple register pages which can be switched between by
writing to a register. Currently the driver manually switches between pages
whenever a register outside of the default register map is accessed and
switches back after it has been accessed. This is a bit tedious and also
potential source for bugs.

This patch adds two helper functions that take care of switching between
pages and reading/writing the register. The register numbers for registers
are updated to encode both the page (in the upper 8-bits) and the register
(in the lower 8-bits) numbers.

Having multiple pages means that a register access is not a single atomic
i2c_smbus_write_byte_data() or i2c_smbus_read_byte_data() call and we need
to make sure that concurrent register access does not race against each
other.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 206 ++++++++++++++++++++++----------------------
 1 file changed, 105 insertions(+), 101 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 00ba845..cc05db9 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -31,7 +31,7 @@
 #include <media/v4l2-ctrls.h>
 #include <linux/mutex.h>
 
-#define ADV7180_REG_INPUT_CONTROL			0x00
+#define ADV7180_REG_INPUT_CONTROL			0x0000
 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
 #define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
@@ -50,28 +50,28 @@
 #define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
 #define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
 
-#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL		0x04
+#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL		0x0004
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
 
 #define ADV7180_REG_AUTODETECT_ENABLE			0x07
 #define ADV7180_AUTODETECT_DEFAULT			0x7f
 /* Contrast */
-#define ADV7180_REG_CON		0x08	/*Unsigned */
+#define ADV7180_REG_CON		0x0008	/*Unsigned */
 #define ADV7180_CON_MIN		0
 #define ADV7180_CON_DEF		128
 #define ADV7180_CON_MAX		255
 /* Brightness*/
-#define ADV7180_REG_BRI		0x0a	/*Signed */
+#define ADV7180_REG_BRI		0x000a	/*Signed */
 #define ADV7180_BRI_MIN		-128
 #define ADV7180_BRI_DEF		0
 #define ADV7180_BRI_MAX		127
 /* Hue */
-#define ADV7180_REG_HUE		0x0b	/*Signed, inverted */
+#define ADV7180_REG_HUE		0x000b	/*Signed, inverted */
 #define ADV7180_HUE_MIN		-127
 #define ADV7180_HUE_DEF		0
 #define ADV7180_HUE_MAX		128
 
-#define ADV7180_REG_CTRL		0x0e
+#define ADV7180_REG_CTRL		0x000e
 #define ADV7180_CTRL_IRQ_SPACE		0x20
 
 #define ADV7180_REG_PWR_MAN		0x0f
@@ -79,7 +79,7 @@
 #define ADV7180_PWR_MAN_OFF		0x24
 #define ADV7180_PWR_MAN_RES		0x80
 
-#define ADV7180_REG_STATUS1		0x10
+#define ADV7180_REG_STATUS1		0x0010
 #define ADV7180_STATUS1_IN_LOCK		0x01
 #define ADV7180_STATUS1_AUTOD_MASK	0x70
 #define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
@@ -91,33 +91,33 @@
 #define ADV7180_STATUS1_AUTOD_PAL_COMB	0x60
 #define ADV7180_STATUS1_AUTOD_SECAM_525	0x70
 
-#define ADV7180_REG_IDENT 0x11
+#define ADV7180_REG_IDENT 0x0011
 #define ADV7180_ID_7180 0x18
 
-#define ADV7180_REG_ICONF1		0x40
+#define ADV7180_REG_ICONF1		0x0040
 #define ADV7180_ICONF1_ACTIVE_LOW	0x01
 #define ADV7180_ICONF1_PSYNC_ONLY	0x10
 #define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
 /* Saturation */
-#define ADV7180_REG_SD_SAT_CB	0xe3	/*Unsigned */
-#define ADV7180_REG_SD_SAT_CR	0xe4	/*Unsigned */
+#define ADV7180_REG_SD_SAT_CB	0x00e3	/*Unsigned */
+#define ADV7180_REG_SD_SAT_CR	0x00e4	/*Unsigned */
 #define ADV7180_SAT_MIN		0
 #define ADV7180_SAT_DEF		128
 #define ADV7180_SAT_MAX		255
 
 #define ADV7180_IRQ1_LOCK	0x01
 #define ADV7180_IRQ1_UNLOCK	0x02
-#define ADV7180_REG_ISR1	0x42
-#define ADV7180_REG_ICR1	0x43
-#define ADV7180_REG_IMR1	0x44
-#define ADV7180_REG_IMR2	0x48
+#define ADV7180_REG_ISR1	0x0042
+#define ADV7180_REG_ICR1	0x0043
+#define ADV7180_REG_IMR1	0x0044
+#define ADV7180_REG_IMR2	0x0048
 #define ADV7180_IRQ3_AD_CHANGE	0x08
-#define ADV7180_REG_ISR3	0x4A
-#define ADV7180_REG_ICR3	0x4B
-#define ADV7180_REG_IMR3	0x4C
+#define ADV7180_REG_ISR3	0x004A
+#define ADV7180_REG_ICR3	0x004B
+#define ADV7180_REG_IMR3	0x004C
 #define ADV7180_REG_IMR4	0x50
 
-#define ADV7180_REG_NTSC_V_BIT_END	0xE6
+#define ADV7180_REG_NTSC_V_BIT_END	0x00E6
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
 
 struct adv7180_state {
@@ -129,6 +129,9 @@ struct adv7180_state {
 	bool			autodetect;
 	bool			powered;
 	u8			input;
+
+	struct i2c_client	*client;
+	unsigned int		register_page;
 };
 
 static struct adv7180_state *ctrl_to_adv7180(struct v4l2_ctrl *ctrl)
@@ -136,6 +139,33 @@ static struct adv7180_state *ctrl_to_adv7180(struct v4l2_ctrl *ctrl)
 	return container_of(ctrl->handler, struct adv7180_state, ctrl_hdl);
 }
 
+static int adv7180_select_page(struct adv7180_state *state, unsigned int page)
+{
+	if (state->register_page != page) {
+		i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL,
+			page);
+		state->register_page = page;
+	}
+
+	return 0;
+}
+
+static int adv7180_write(struct adv7180_state *state, unsigned int reg,
+	unsigned int value)
+{
+	lockdep_assert_held(&state->mutex);
+	adv7180_select_page(state, reg >> 8);
+	return i2c_smbus_write_byte_data(state->client, reg & 0xff, value);
+}
+
+static int adv7180_read(struct adv7180_state *state, unsigned int reg)
+{
+	lockdep_assert_held(&state->mutex);
+	adv7180_select_page(state, reg >> 8);
+	return i2c_smbus_read_byte_data(state->client, reg & 0xff);
+}
+
+
 static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 {
 	/* in case V4L2_IN_ST_NO_SIGNAL */
@@ -195,10 +225,10 @@ static u32 adv7180_status_to_v4l2(u8 status1)
 	return 0;
 }
 
-static int __adv7180_status(struct i2c_client *client, u32 *status,
+static int __adv7180_status(struct adv7180_state *state, u32 *status,
 			    v4l2_std_id *std)
 {
-	int status1 = i2c_smbus_read_byte_data(client, ADV7180_REG_STATUS1);
+	int status1 = adv7180_read(state, ADV7180_REG_STATUS1);
 
 	if (status1 < 0)
 		return status1;
@@ -227,7 +257,7 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
 	if (!state->autodetect || state->irq > 0)
 		*std = state->curr_norm;
 	else
-		err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
+		err = __adv7180_status(state, NULL, std);
 
 	mutex_unlock(&state->mutex);
 	return err;
@@ -238,7 +268,6 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
 {
 	struct adv7180_state *state = to_state(sd);
 	int ret = mutex_lock_interruptible(&state->mutex);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 
 	if (ret)
 		return ret;
@@ -249,13 +278,12 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
 	if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
 		goto out;
 
-	ret = i2c_smbus_read_byte_data(client, ADV7180_REG_INPUT_CONTROL);
+	ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
 	if (ret < 0)
 		goto out;
 
 	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
-	ret = i2c_smbus_write_byte_data(client,
-					ADV7180_REG_INPUT_CONTROL, ret | input);
+	ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret | input);
 	state->input = input;
 out:
 	mutex_unlock(&state->mutex);
@@ -269,7 +297,7 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
 	if (ret)
 		return ret;
 
-	ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
+	ret = __adv7180_status(state, status, NULL);
 	mutex_unlock(&state->mutex);
 	return ret;
 }
@@ -277,30 +305,27 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
 static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
 	struct adv7180_state *state = to_state(sd);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	int ret = mutex_lock_interruptible(&state->mutex);
 	if (ret)
 		return ret;
 
 	/* all standards -> autodetect */
 	if (std == V4L2_STD_ALL) {
-		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_REG_INPUT_CONTROL,
-				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
-					      | state->input);
+		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
+				    ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
+				    | state->input);
 		if (ret < 0)
 			goto out;
 
-		__adv7180_status(client, NULL, &state->curr_norm);
+		__adv7180_status(state, NULL, &state->curr_norm);
 		state->autodetect = true;
 	} else {
 		ret = v4l2_std_to_adv7180(std);
 		if (ret < 0)
 			goto out;
 
-		ret = i2c_smbus_write_byte_data(client,
-						ADV7180_REG_INPUT_CONTROL,
-						ret | state->input);
+		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
+				    ret | state->input);
 		if (ret < 0)
 			goto out;
 
@@ -313,8 +338,7 @@ out:
 	return ret;
 }
 
-static int adv7180_set_power(struct adv7180_state *state,
-	struct i2c_client *client, bool on)
+static int adv7180_set_power(struct adv7180_state *state, bool on)
 {
 	u8 val;
 
@@ -323,20 +347,19 @@ static int adv7180_set_power(struct adv7180_state *state,
 	else
 		val = ADV7180_PWR_MAN_OFF;
 
-	return i2c_smbus_write_byte_data(client, ADV7180_REG_PWR_MAN, val);
+	return adv7180_write(state, ADV7180_REG_PWR_MAN, val);
 }
 
 static int adv7180_s_power(struct v4l2_subdev *sd, int on)
 {
 	struct adv7180_state *state = to_state(sd);
-	struct i2c_client *client = v4l2_get_subdevdata(sd);
 	int ret;
 
 	ret = mutex_lock_interruptible(&state->mutex);
 	if (ret)
 		return ret;
 
-	ret = adv7180_set_power(state, client, on);
+	ret = adv7180_set_power(state, on);
 	if (ret == 0)
 		state->powered = on;
 
@@ -347,7 +370,6 @@ static int adv7180_s_power(struct v4l2_subdev *sd, int on)
 static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct adv7180_state *state = ctrl_to_adv7180(ctrl);
-	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
 	int ret = mutex_lock_interruptible(&state->mutex);
 	int val;
 
@@ -356,26 +378,24 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 	val = ctrl->val;
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_BRI, val);
+		ret = adv7180_write(state, ADV7180_REG_BRI, val);
 		break;
 	case V4L2_CID_HUE:
 		/*Hue is inverted according to HSL chart */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_HUE, -val);
+		ret = adv7180_write(state, ADV7180_REG_HUE, -val);
 		break;
 	case V4L2_CID_CONTRAST:
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_CON, val);
+		ret = adv7180_write(state, ADV7180_REG_CON, val);
 		break;
 	case V4L2_CID_SATURATION:
 		/*
 		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
 		 *Let's not confuse the user, everybody understands saturation
 		 */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_SD_SAT_CB,
-						val);
+		ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val);
 		if (ret < 0)
 			break;
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_SD_SAT_CR,
-						val);
+		ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val);
 		break;
 	default:
 		ret = -EINVAL;
@@ -484,114 +504,96 @@ static const struct v4l2_subdev_ops adv7180_ops = {
 static irqreturn_t adv7180_irq(int irq, void *devid)
 {
 	struct adv7180_state *state = devid;
-	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
 	u8 isr3;
 
 	mutex_lock(&state->mutex);
-	i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL,
-				  ADV7180_CTRL_IRQ_SPACE);
-	isr3 = i2c_smbus_read_byte_data(client, ADV7180_REG_ISR3);
+	isr3 = adv7180_read(state, ADV7180_REG_ISR3);
 	/* clear */
-	i2c_smbus_write_byte_data(client, ADV7180_REG_ICR3, isr3);
-	i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL, 0);
+	adv7180_write(state, ADV7180_REG_ICR3, isr3);
 
 	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
-		__adv7180_status(client, NULL, &state->curr_norm);
+		__adv7180_status(state, NULL, &state->curr_norm);
 	mutex_unlock(&state->mutex);
 
 	return IRQ_HANDLED;
 }
 
-static int init_device(struct i2c_client *client, struct adv7180_state *state)
+static int init_device(struct adv7180_state *state)
 {
 	int ret;
 
+	mutex_lock(&state->mutex);
+
 	/* Initialize adv7180 */
 	/* Enable autodetection */
 	if (state->autodetect) {
-		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_REG_INPUT_CONTROL,
+		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
 				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
 					      | state->input);
 		if (ret < 0)
-			return ret;
+			goto out_unlock;
 
-		ret =
-		    i2c_smbus_write_byte_data(client,
-					      ADV7180_REG_AUTODETECT_ENABLE,
+		ret = adv7180_write(state, ADV7180_REG_AUTODETECT_ENABLE,
 					      ADV7180_AUTODETECT_DEFAULT);
 		if (ret < 0)
-			return ret;
+			goto out_unlock;
 	} else {
 		ret = v4l2_std_to_adv7180(state->curr_norm);
 		if (ret < 0)
-			return ret;
+			goto out_unlock;
 
-		ret =
-		    i2c_smbus_write_byte_data(client, ADV7180_REG_INPUT_CONTROL,
+		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
 					      ret | state->input);
 		if (ret < 0)
-			return ret;
+			goto out_unlock;
 
 	}
 	/* ITU-R BT.656-4 compatible */
-	ret = i2c_smbus_write_byte_data(client,
-			ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
+	ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
 			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
 	if (ret < 0)
-		return ret;
+		goto out_unlock;
 
 	/* Manually set V bit end position in NTSC mode */
-	ret = i2c_smbus_write_byte_data(client,
-					ADV7180_REG_NTSC_V_BIT_END,
+	ret = adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END,
 					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
 	if (ret < 0)
-		return ret;
+		goto out_unlock;
 
 	/* read current norm */
-	__adv7180_status(client, NULL, &state->curr_norm);
+	__adv7180_status(state, NULL, &state->curr_norm);
 
 	/* register for interrupts */
 	if (state->irq > 0) {
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL,
-						ADV7180_CTRL_IRQ_SPACE);
-		if (ret < 0)
-			goto err;
-
 		/* config the Interrupt pin to be active low */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_ICONF1,
+		ret = adv7180_write(state, ADV7180_REG_ICONF1,
 						ADV7180_ICONF1_ACTIVE_LOW |
 						ADV7180_ICONF1_PSYNC_ONLY);
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR1, 0);
+		ret = adv7180_write(state, ADV7180_REG_IMR1, 0);
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR2, 0);
+		ret = adv7180_write(state, ADV7180_REG_IMR2, 0);
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
 		/* enable AD change interrupts interrupts */
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR3,
+		ret = adv7180_write(state, ADV7180_REG_IMR3,
 						ADV7180_IRQ3_AD_CHANGE);
 		if (ret < 0)
-			goto err;
-
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_IMR4, 0);
-		if (ret < 0)
-			goto err;
+			goto out_unlock;
 
-		ret = i2c_smbus_write_byte_data(client, ADV7180_REG_CTRL,
-						0);
+		ret = adv7180_write(state, ADV7180_REG_IMR4, 0);
 		if (ret < 0)
-			goto err;
+			goto out_unlock;
 	}
 
-	return 0;
+out_unlock:
+	mutex_unlock(&state->mutex);
 
-err:
 	return ret;
 }
 
@@ -615,6 +617,8 @@ static int adv7180_probe(struct i2c_client *client,
 		goto err;
 	}
 
+	state->client = client;
+
 	state->irq = client->irq;
 	mutex_init(&state->mutex);
 	state->autodetect = true;
@@ -626,7 +630,7 @@ static int adv7180_probe(struct i2c_client *client,
 	ret = adv7180_init_controls(state);
 	if (ret)
 		goto err_unreg_subdev;
-	ret = init_device(client, state);
+	ret = init_device(state);
 	if (ret)
 		goto err_free_ctrl;
 
@@ -682,7 +686,7 @@ static int adv7180_suspend(struct device *dev)
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
 	struct adv7180_state *state = to_state(sd);
 
-	return adv7180_set_power(state, client, false);
+	return adv7180_set_power(state, false);
 }
 
 static int adv7180_resume(struct device *dev)
@@ -693,11 +697,11 @@ static int adv7180_resume(struct device *dev)
 	int ret;
 
 	if (state->powered) {
-		ret = adv7180_set_power(state, client, true);
+		ret = adv7180_set_power(state, true);
 		if (ret)
 			return ret;
 	}
-	ret = init_device(client, state);
+	ret = init_device(state);
 	if (ret < 0)
 		return ret;
 	return 0;
-- 
1.8.0


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

* [PATCH 06/16] [media] adv7180: Reset the device before initialization
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (4 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 05/16] [media] adv7180: Do implicit register paging Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 07/16] [media] adv7180: Add media controller support Lars-Peter Clausen
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Reset the device when initializing it so it is in a good known state and the
assumed register settings matches the actual register settings.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index cc05db9..eeb5a4a 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -30,6 +30,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <linux/mutex.h>
+#include <linux/delay.h>
 
 #define ADV7180_REG_INPUT_CONTROL			0x0000
 #define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
@@ -524,6 +525,9 @@ static int init_device(struct adv7180_state *state)
 
 	mutex_lock(&state->mutex);
 
+	adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
+	usleep_range(2000, 10000);
+
 	/* Initialize adv7180 */
 	/* Enable autodetection */
 	if (state->autodetect) {
@@ -696,14 +700,14 @@ static int adv7180_resume(struct device *dev)
 	struct adv7180_state *state = to_state(sd);
 	int ret;
 
-	if (state->powered) {
-		ret = adv7180_set_power(state, true);
-		if (ret)
-			return ret;
-	}
 	ret = init_device(state);
 	if (ret < 0)
 		return ret;
+
+	ret = adv7180_set_power(state, state->powered);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
1.8.0


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

* [PATCH 07/16] [media] adv7180: Add media controller support
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (5 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 06/16] [media] adv7180: Reset the device before initialization Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 08/16] [media] adv7180: Consolidate video mode setting Lars-Peter Clausen
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Add media controller support to the adv7180 driver by registering a media
entity instance for it as well as implementing pad ops for configuring the
format.

As there currently don't seem to be any users of the video ops format
operations those are removed as well in this patch.

Also set the V4L2_SUBDEV_FL_HAS_DEVNODE flag for the subdevice so it is
possible to create a subdevice device node.

Since the driver now depends on VIDEO_V4L2_SUBDEV_API all drivers which
select the driver need to depend on that symbol as well.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/Kconfig         |  2 +-
 drivers/media/i2c/adv7180.c       | 50 +++++++++++++++++++++++++++++++--------
 drivers/media/pci/sta2x11/Kconfig |  1 +
 drivers/media/platform/Kconfig    |  2 +-
 4 files changed, 43 insertions(+), 12 deletions(-)

diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index ca84543..f37890a 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -177,7 +177,7 @@ comment "Video decoders"
 
 config VIDEO_ADV7180
 	tristate "Analog Devices ADV7180 decoder"
-	depends on VIDEO_V4L2 && I2C
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
 	---help---
 	  Support for the Analog Devices ADV7180 video decoder.
 
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index eeb5a4a..349cae3 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -124,6 +124,7 @@
 struct adv7180_state {
 	struct v4l2_ctrl_handler ctrl_hdl;
 	struct v4l2_subdev	sd;
+	struct media_pad	pad;
 	struct mutex		mutex; /* mutual excl. when accessing chip */
 	int			irq;
 	v4l2_std_id		curr_norm;
@@ -442,13 +443,14 @@ static void adv7180_exit_controls(struct adv7180_state *state)
 	v4l2_ctrl_handler_free(&state->ctrl_hdl);
 }
 
-static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
-				 u32 *code)
+static int adv7180_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
 {
-	if (index > 0)
+	if (code->index != 0)
 		return -EINVAL;
 
-	*code = MEDIA_BUS_FMT_YUYV8_2X8;
+	code->code = MEDIA_BUS_FMT_YUYV8_2X8;
 
 	return 0;
 }
@@ -467,6 +469,20 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static int adv7180_get_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *format)
+{
+	return adv7180_mbus_fmt(sd, &format->format);
+}
+
+static int adv7180_set_pad_format(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *format)
+{
+	return adv7180_mbus_fmt(sd, &format->format);
+}
+
 static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
 				 struct v4l2_mbus_config *cfg)
 {
@@ -486,10 +502,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
 	.querystd = adv7180_querystd,
 	.g_input_status = adv7180_g_input_status,
 	.s_routing = adv7180_s_routing,
-	.enum_mbus_fmt = adv7180_enum_mbus_fmt,
-	.try_mbus_fmt = adv7180_mbus_fmt,
-	.g_mbus_fmt = adv7180_mbus_fmt,
-	.s_mbus_fmt = adv7180_mbus_fmt,
 	.g_mbus_config = adv7180_g_mbus_config,
 };
 
@@ -497,9 +509,16 @@ static const struct v4l2_subdev_core_ops adv7180_core_ops = {
 	.s_power = adv7180_s_power,
 };
 
+static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
+	.enum_mbus_code = adv7180_enum_mbus_code,
+	.set_fmt = adv7180_set_pad_format,
+	.get_fmt = adv7180_get_pad_format,
+};
+
 static const struct v4l2_subdev_ops adv7180_ops = {
 	.core = &adv7180_core_ops,
 	.video = &adv7180_video_ops,
+	.pad = &adv7180_pad_ops,
 };
 
 static irqreturn_t adv7180_irq(int irq, void *devid)
@@ -630,20 +649,28 @@ static int adv7180_probe(struct i2c_client *client,
 	state->input = 0;
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
 
 	ret = adv7180_init_controls(state);
 	if (ret)
 		goto err_unreg_subdev;
-	ret = init_device(state);
+
+	state->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+	ret = media_entity_init(&sd->entity, 1, &state->pad, 0);
 	if (ret)
 		goto err_free_ctrl;
 
+	ret = init_device(state);
+	if (ret)
+		goto err_media_entity_cleanup;
+
 	if (state->irq) {
 		ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
 					   IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
 					   KBUILD_MODNAME, state);
 		if (ret)
-			goto err_free_ctrl;
+			goto err_media_entity_cleanup;
 	}
 
 	ret = v4l2_async_register_subdev(sd);
@@ -655,6 +682,8 @@ static int adv7180_probe(struct i2c_client *client,
 err_free_irq:
 	if (state->irq > 0)
 		free_irq(client->irq, state);
+err_media_entity_cleanup:
+	media_entity_cleanup(&sd->entity);
 err_free_ctrl:
 	adv7180_exit_controls(state);
 err_unreg_subdev:
@@ -673,6 +702,7 @@ static int adv7180_remove(struct i2c_client *client)
 	if (state->irq > 0)
 		free_irq(client->irq, state);
 
+	media_entity_cleanup(&sd->entity);
 	adv7180_exit_controls(state);
 	mutex_destroy(&state->mutex);
 	return 0;
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index f6f30ab..e03587b 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -5,6 +5,7 @@ config STA2X11_VIP
 	select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
 	select VIDEOBUF2_DMA_CONTIG
 	depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
+	depends on VIDEO_V4L2_SUBDEV_API
 	depends on I2C
 	help
 	  Say Y for support for STA2X11 VIP (Video Input Port) capture
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 71e8873..d446b66 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -56,7 +56,7 @@ config VIDEO_VIU
 
 config VIDEO_TIMBERDALE
 	tristate "Support for timberdale Video In/LogiWIN"
-	depends on VIDEO_V4L2 && I2C && DMADEVICES
+	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && DMADEVICES
 	depends on MFD_TIMBERDALE || COMPILE_TEST
 	select DMA_ENGINE
 	select TIMB_DMA
-- 
1.8.0


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

* [PATCH 08/16] [media] adv7180: Consolidate video mode setting
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (6 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 07/16] [media] adv7180: Add media controller support Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-16 10:12   ` Hans Verkuil
  2015-01-13 12:01 ` [PATCH 09/16] [media] adv7180: Prepare for multi-chip support Lars-Peter Clausen
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

We have basically the same code to set the video standard in init_device()
and adv7180_s_std(). Factor this out into a common helper function.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 67 ++++++++++++++++++++++-----------------------
 1 file changed, 32 insertions(+), 35 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 349cae3..4d9bcc8 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -304,37 +304,54 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
 	return ret;
 }
 
-static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+static int adv7180_program_std(struct adv7180_state *state)
 {
-	struct adv7180_state *state = to_state(sd);
-	int ret = mutex_lock_interruptible(&state->mutex);
-	if (ret)
-		return ret;
+	int ret;
 
-	/* all standards -> autodetect */
-	if (std == V4L2_STD_ALL) {
+	if (state->autodetect) {
 		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
 				    ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
 				    | state->input);
 		if (ret < 0)
-			goto out;
+			return ret;
 
 		__adv7180_status(state, NULL, &state->curr_norm);
-		state->autodetect = true;
 	} else {
-		ret = v4l2_std_to_adv7180(std);
+		ret = v4l2_std_to_adv7180(state->curr_norm);
 		if (ret < 0)
-			goto out;
+			return ret;
 
 		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
 				    ret | state->input);
 		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+	struct adv7180_state *state = to_state(sd);
+	int ret = mutex_lock_interruptible(&state->mutex);
+
+	if (ret)
+		return ret;
+
+	/* all standards -> autodetect */
+	if (std == V4L2_STD_ALL) {
+		state->autodetect = true;
+	} else {
+		/* Make sure we can support this std */
+		ret = v4l2_std_to_adv7180(std);
+		if (ret < 0)
 			goto out;
 
 		state->curr_norm = std;
 		state->autodetect = false;
 	}
-	ret = 0;
+
+	ret = adv7180_program_std(state);
 out:
 	mutex_unlock(&state->mutex);
 	return ret;
@@ -547,30 +564,10 @@ static int init_device(struct adv7180_state *state)
 	adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
 	usleep_range(2000, 10000);
 
-	/* Initialize adv7180 */
-	/* Enable autodetection */
-	if (state->autodetect) {
-		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
-				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
-					      | state->input);
-		if (ret < 0)
-			goto out_unlock;
-
-		ret = adv7180_write(state, ADV7180_REG_AUTODETECT_ENABLE,
-					      ADV7180_AUTODETECT_DEFAULT);
-		if (ret < 0)
-			goto out_unlock;
-	} else {
-		ret = v4l2_std_to_adv7180(state->curr_norm);
-		if (ret < 0)
-			goto out_unlock;
-
-		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
-					      ret | state->input);
-		if (ret < 0)
-			goto out_unlock;
+	ret = adv7180_program_std(state);
+	if (ret)
+		goto out_unlock;
 
-	}
 	/* ITU-R BT.656-4 compatible */
 	ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
 			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
-- 
1.8.0


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

* [PATCH 09/16] [media] adv7180: Prepare for multi-chip support
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (7 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 08/16] [media] adv7180: Consolidate video mode setting Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 10/16] [media] adv7180: Add support for the ad7182 Lars-Peter Clausen
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

The adv7180 is part of a larger family of device, which have all a very
similar register map layout. This patch prepares the adv7180 driver for
support for multiple different devices. For now the only difference we care
about is the number of input channel configurations. Also the way the input
format is configured slightly differs between some devices.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 187 ++++++++++++++++++++++++++++++--------------
 1 file changed, 130 insertions(+), 57 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 4d9bcc8..e3f91d5 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -32,23 +32,24 @@
 #include <linux/mutex.h>
 #include <linux/delay.h>
 
+#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM		0x0
+#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED		0x1
+#define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM		0x2
+#define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM		0x3
+#define ADV7180_STD_NTSC_J				0x4
+#define ADV7180_STD_NTSC_M				0x5
+#define ADV7180_STD_PAL60				0x6
+#define ADV7180_STD_NTSC_443				0x7
+#define ADV7180_STD_PAL_BG				0x8
+#define ADV7180_STD_PAL_N				0x9
+#define ADV7180_STD_PAL_M				0xa
+#define ADV7180_STD_PAL_M_PED				0xb
+#define ADV7180_STD_PAL_COMB_N				0xc
+#define ADV7180_STD_PAL_COMB_N_PED			0xd
+#define ADV7180_STD_PAL_SECAM				0xe
+#define ADV7180_STD_PAL_SECAM_PED			0xf
+
 #define ADV7180_REG_INPUT_CONTROL			0x0000
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
-#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
-#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM	0x30
-#define ADV7180_INPUT_CONTROL_NTSC_J			0x40
-#define ADV7180_INPUT_CONTROL_NTSC_M			0x50
-#define ADV7180_INPUT_CONTROL_PAL60			0x60
-#define ADV7180_INPUT_CONTROL_NTSC_443			0x70
-#define ADV7180_INPUT_CONTROL_PAL_BG			0x80
-#define ADV7180_INPUT_CONTROL_PAL_N			0x90
-#define ADV7180_INPUT_CONTROL_PAL_M			0xa0
-#define ADV7180_INPUT_CONTROL_PAL_M_PED			0xb0
-#define ADV7180_INPUT_CONTROL_PAL_COMB_N		0xc0
-#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED		0xd0
-#define ADV7180_INPUT_CONTROL_PAL_SECAM			0xe0
-#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
 #define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
 
 #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL		0x0004
@@ -121,6 +122,30 @@
 #define ADV7180_REG_NTSC_V_BIT_END	0x00E6
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
 
+#define ADV7180_INPUT_CVBS_AIN1 0x00
+#define ADV7180_INPUT_CVBS_AIN2 0x01
+#define ADV7180_INPUT_CVBS_AIN3 0x02
+#define ADV7180_INPUT_CVBS_AIN4 0x03
+#define ADV7180_INPUT_CVBS_AIN5 0x04
+#define ADV7180_INPUT_CVBS_AIN6 0x05
+#define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06
+#define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07
+#define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08
+#define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09
+#define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a
+
+struct adv7180_state;
+
+#define ADV7180_FLAG_RESET_POWERED	BIT(0)
+
+struct adv7180_chip_info {
+	unsigned int flags;
+	unsigned int valid_input_mask;
+	int (*set_std)(struct adv7180_state *st, unsigned int std);
+	int (*select_input)(struct adv7180_state *st, unsigned int input);
+	int (*init)(struct adv7180_state *state);
+};
+
 struct adv7180_state {
 	struct v4l2_ctrl_handler ctrl_hdl;
 	struct v4l2_subdev	sd;
@@ -134,6 +159,7 @@ struct adv7180_state {
 
 	struct i2c_client	*client;
 	unsigned int		register_page;
+	const struct adv7180_chip_info *chip_info;
 };
 
 static struct adv7180_state *ctrl_to_adv7180(struct v4l2_ctrl *ctrl)
@@ -167,6 +193,11 @@ static int adv7180_read(struct adv7180_state *state, unsigned int reg)
 	return i2c_smbus_read_byte_data(state->client, reg & 0xff);
 }
 
+static int adv7180_set_video_standard(struct adv7180_state *state,
+	unsigned int std)
+{
+	return state->chip_info->set_std(state, std);
+}
 
 static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 {
@@ -199,22 +230,22 @@ static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 static int v4l2_std_to_adv7180(v4l2_std_id std)
 {
 	if (std == V4L2_STD_PAL_60)
-		return ADV7180_INPUT_CONTROL_PAL60;
+		return ADV7180_STD_PAL60;
 	if (std == V4L2_STD_NTSC_443)
-		return ADV7180_INPUT_CONTROL_NTSC_443;
+		return ADV7180_STD_NTSC_443;
 	if (std == V4L2_STD_PAL_N)
-		return ADV7180_INPUT_CONTROL_PAL_N;
+		return ADV7180_STD_PAL_N;
 	if (std == V4L2_STD_PAL_M)
-		return ADV7180_INPUT_CONTROL_PAL_M;
+		return ADV7180_STD_PAL_M;
 	if (std == V4L2_STD_PAL_Nc)
-		return ADV7180_INPUT_CONTROL_PAL_COMB_N;
+		return ADV7180_STD_PAL_COMB_N;
 
 	if (std & V4L2_STD_PAL)
-		return ADV7180_INPUT_CONTROL_PAL_BG;
+		return ADV7180_STD_PAL_BG;
 	if (std & V4L2_STD_NTSC)
-		return ADV7180_INPUT_CONTROL_NTSC_M;
+		return ADV7180_STD_NTSC_M;
 	if (std & V4L2_STD_SECAM)
-		return ADV7180_INPUT_CONTROL_PAL_SECAM;
+		return ADV7180_STD_PAL_SECAM;
 
 	return -EINVAL;
 }
@@ -274,19 +305,15 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
 	if (ret)
 		return ret;
 
-	/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
-	 * all inputs and let the card driver take care of validation
-	 */
-	if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
+	if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) {
+		ret = -EINVAL;
 		goto out;
+	}
 
-	ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
-	if (ret < 0)
-		goto out;
+	ret = state->chip_info->select_input(state, input);
 
-	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
-	ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret | input);
-	state->input = input;
+	if (ret == 0)
+		state->input = input;
 out:
 	mutex_unlock(&state->mutex);
 	return ret;
@@ -309,9 +336,8 @@ static int adv7180_program_std(struct adv7180_state *state)
 	int ret;
 
 	if (state->autodetect) {
-		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
-				    ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
-				    | state->input);
+		ret = adv7180_set_video_standard(state,
+			ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
 		if (ret < 0)
 			return ret;
 
@@ -321,8 +347,7 @@ static int adv7180_program_std(struct adv7180_state *state)
 		if (ret < 0)
 			return ret;
 
-		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
-				    ret | state->input);
+		ret = adv7180_set_video_standard(state, ret);
 		if (ret < 0)
 			return ret;
 	}
@@ -522,6 +547,7 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
 	.g_mbus_config = adv7180_g_mbus_config,
 };
 
+
 static const struct v4l2_subdev_core_ops adv7180_core_ops = {
 	.s_power = adv7180_s_power,
 };
@@ -555,33 +581,77 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
 	return IRQ_HANDLED;
 }
 
-static int init_device(struct adv7180_state *state)
+static int adv7180_init(struct adv7180_state *state)
 {
 	int ret;
 
-	mutex_lock(&state->mutex);
-
-	adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
-	usleep_range(2000, 10000);
-
-	ret = adv7180_program_std(state);
-	if (ret)
-		goto out_unlock;
-
 	/* ITU-R BT.656-4 compatible */
 	ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
 			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
 	if (ret < 0)
-		goto out_unlock;
+		return ret;
 
 	/* Manually set V bit end position in NTSC mode */
-	ret = adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END,
+	return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END,
 					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
+}
+
+static int adv7180_set_std(struct adv7180_state *state, unsigned int std)
+{
+	return adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
+		(std << 4) | state->input);
+}
+
+static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
+{
+	int ret;
+
+	ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
 	if (ret < 0)
+		return ret;
+
+	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
+	ret |= input;
+	return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret);
+}
+
+static const struct adv7180_chip_info adv7180_info = {
+	.flags = ADV7180_FLAG_RESET_POWERED,
+	/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
+	 * all inputs and let the card driver take care of validation
+	 */
+	.valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) |
+		BIT(ADV7180_INPUT_CVBS_AIN2) |
+		BIT(ADV7180_INPUT_CVBS_AIN3) |
+		BIT(ADV7180_INPUT_CVBS_AIN4) |
+		BIT(ADV7180_INPUT_CVBS_AIN5) |
+		BIT(ADV7180_INPUT_CVBS_AIN6) |
+		BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) |
+		BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6),
+	.init = adv7180_init,
+	.set_std = adv7180_set_std,
+	.select_input = adv7180_select_input,
+};
+
+static int init_device(struct adv7180_state *state)
+{
+	int ret;
+
+	mutex_lock(&state->mutex);
+
+	adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
+	usleep_range(2000, 10000);
+
+	ret = state->chip_info->init(state);
+	if (ret)
 		goto out_unlock;
 
-	/* read current norm */
-	__adv7180_status(state, NULL, &state->curr_norm);
+	ret = adv7180_program_std(state);
+	if (ret)
+		goto out_unlock;
 
 	/* register for interrupts */
 	if (state->irq > 0) {
@@ -638,11 +708,15 @@ static int adv7180_probe(struct i2c_client *client,
 	}
 
 	state->client = client;
+	state->chip_info = (struct adv7180_chip_info *)id->driver_data;
 
 	state->irq = client->irq;
 	mutex_init(&state->mutex);
 	state->autodetect = true;
-	state->powered = true;
+	if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
+		state->powered = true;
+	else
+		state->powered = false;
 	state->input = 0;
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
@@ -706,9 +780,10 @@ static int adv7180_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adv7180_id[] = {
-	{KBUILD_MODNAME, 0},
+	{ "adv7180", (kernel_ulong_t)&adv7180_info },
 	{},
 };
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
 
 #ifdef CONFIG_PM_SLEEP
 static int adv7180_suspend(struct device *dev)
@@ -745,8 +820,6 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
 #define ADV7180_PM_OPS NULL
 #endif
 
-MODULE_DEVICE_TABLE(i2c, adv7180_id);
-
 static struct i2c_driver adv7180_driver = {
 	.driver = {
 		   .owner = THIS_MODULE,
-- 
1.8.0


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

* [PATCH 10/16] [media] adv7180: Add support for the ad7182
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (8 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 09/16] [media] adv7180: Prepare for multi-chip support Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 11/16] [media] adv7180: Add support for the adv7280/adv7281/adv7282 Lars-Peter Clausen
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

This patch adds support for the adv7182 to the adv7180 driver. The adv7182
is similar to the adv7180, the main difference from the driver's point of
view is how the video input and how the input format are selected.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 149 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 149 insertions(+)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index e3f91d5..4e518d5 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -52,6 +52,8 @@
 #define ADV7180_REG_INPUT_CONTROL			0x0000
 #define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
 
+#define ADV7182_REG_INPUT_VIDSEL			0x0002
+
 #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL		0x0004
 #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
 
@@ -134,6 +136,25 @@
 #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09
 #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a
 
+#define ADV7182_INPUT_CVBS_AIN1 0x00
+#define ADV7182_INPUT_CVBS_AIN2 0x01
+#define ADV7182_INPUT_CVBS_AIN3 0x02
+#define ADV7182_INPUT_CVBS_AIN4 0x03
+#define ADV7182_INPUT_CVBS_AIN5 0x04
+#define ADV7182_INPUT_CVBS_AIN6 0x05
+#define ADV7182_INPUT_CVBS_AIN7 0x06
+#define ADV7182_INPUT_CVBS_AIN8 0x07
+#define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08
+#define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09
+#define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a
+#define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b
+#define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c
+#define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d
+#define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e
+#define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f
+#define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10
+#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
+
 struct adv7180_state;
 
 #define ADV7180_FLAG_RESET_POWERED	BIT(0)
@@ -615,6 +636,118 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
 	return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret);
 }
 
+static int adv7182_init(struct adv7180_state *state)
+{
+	/* ADI required writes */
+	adv7180_write(state, 0x0003, 0x0c);
+	adv7180_write(state, 0x0004, 0x07);
+	adv7180_write(state, 0x0013, 0x00);
+	adv7180_write(state, 0x001d, 0x40);
+
+	return 0;
+}
+
+static int adv7182_set_std(struct adv7180_state *state, unsigned int std)
+{
+	return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4);
+}
+
+enum adv7182_input_type {
+	ADV7182_INPUT_TYPE_CVBS,
+	ADV7182_INPUT_TYPE_DIFF_CVBS,
+	ADV7182_INPUT_TYPE_SVIDEO,
+	ADV7182_INPUT_TYPE_YPBPR,
+};
+
+static enum adv7182_input_type adv7182_get_input_type(unsigned int input)
+{
+	switch (input) {
+	case ADV7182_INPUT_CVBS_AIN1:
+	case ADV7182_INPUT_CVBS_AIN2:
+	case ADV7182_INPUT_CVBS_AIN3:
+	case ADV7182_INPUT_CVBS_AIN4:
+	case ADV7182_INPUT_CVBS_AIN5:
+	case ADV7182_INPUT_CVBS_AIN6:
+	case ADV7182_INPUT_CVBS_AIN7:
+	case ADV7182_INPUT_CVBS_AIN8:
+		return ADV7182_INPUT_TYPE_CVBS;
+	case ADV7182_INPUT_SVIDEO_AIN1_AIN2:
+	case ADV7182_INPUT_SVIDEO_AIN3_AIN4:
+	case ADV7182_INPUT_SVIDEO_AIN5_AIN6:
+	case ADV7182_INPUT_SVIDEO_AIN7_AIN8:
+		return ADV7182_INPUT_TYPE_SVIDEO;
+	case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3:
+	case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6:
+		return ADV7182_INPUT_TYPE_YPBPR;
+	case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2:
+	case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4:
+	case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6:
+	case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8:
+		return ADV7182_INPUT_TYPE_DIFF_CVBS;
+	default: /* Will never happen */
+		return 0;
+	}
+}
+
+/* ADI recommended writes to registers 0x52, 0x53, 0x54 */
+static unsigned int adv7182_lbias_settings[][3] = {
+	[ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
+	[ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
+};
+
+static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
+{
+	enum adv7182_input_type input_type;
+	unsigned int *lbias;
+	unsigned int i;
+	int ret;
+
+	ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input);
+	if (ret)
+		return ret;
+
+	/* Reset clamp circuitry - ADI recommended writes */
+	adv7180_write(state, 0x809c, 0x00);
+	adv7180_write(state, 0x809c, 0xff);
+
+	input_type = adv7182_get_input_type(input);
+
+	switch (input_type) {
+	case ADV7182_INPUT_TYPE_CVBS:
+	case ADV7182_INPUT_TYPE_DIFF_CVBS:
+		/* ADI recommends to use the SH1 filter */
+		adv7180_write(state, 0x0017, 0x41);
+		break;
+	default:
+		adv7180_write(state, 0x0017, 0x01);
+		break;
+	}
+
+	lbias = adv7182_lbias_settings[input_type];
+
+	for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++)
+		adv7180_write(state, 0x0052 + i, lbias[i]);
+
+	if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) {
+		/* ADI required writes to make differential CVBS work */
+		adv7180_write(state, 0x005f, 0xa8);
+		adv7180_write(state, 0x005a, 0x90);
+		adv7180_write(state, 0x0060, 0xb0);
+		adv7180_write(state, 0x80b6, 0x08);
+		adv7180_write(state, 0x80c0, 0xa0);
+	} else {
+		adv7180_write(state, 0x005f, 0xf0);
+		adv7180_write(state, 0x005a, 0xd0);
+		adv7180_write(state, 0x0060, 0x10);
+		adv7180_write(state, 0x80b6, 0x9c);
+		adv7180_write(state, 0x80c0, 0x00);
+	}
+
+	return 0;
+}
+
 static const struct adv7180_chip_info adv7180_info = {
 	.flags = ADV7180_FLAG_RESET_POWERED,
 	/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
@@ -636,6 +769,21 @@ static const struct adv7180_chip_info adv7180_info = {
 	.select_input = adv7180_select_input,
 };
 
+static const struct adv7180_chip_info adv7182_info = {
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
 static int init_device(struct adv7180_state *state)
 {
 	int ret;
@@ -781,6 +929,7 @@ static int adv7180_remove(struct i2c_client *client)
 
 static const struct i2c_device_id adv7180_id[] = {
 	{ "adv7180", (kernel_ulong_t)&adv7180_info },
+	{ "adv7182", (kernel_ulong_t)&adv7182_info },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, adv7180_id);
-- 
1.8.0


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

* [PATCH 11/16] [media] adv7180: Add support for the adv7280/adv7281/adv7282
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (9 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 10/16] [media] adv7180: Add support for the ad7182 Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 12/16] [media] adv7180: Add support for the adv7280-m/adv7281-m/adv7281-ma/adv7282-m Lars-Peter Clausen
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

This patch adds support for the adv7280/adv7281/adv7282 devices to the
adv7180 driver. They are very similar to the adv7182, the main difference
from the drivers point of view are some different tuning constants for
improved video performance.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 56 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 54 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 4e518d5..ea6695c 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -158,6 +158,7 @@
 struct adv7180_state;
 
 #define ADV7180_FLAG_RESET_POWERED	BIT(0)
+#define ADV7180_FLAG_V2			BIT(1)
 
 struct adv7180_chip_info {
 	unsigned int flags;
@@ -638,9 +639,18 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
 
 static int adv7182_init(struct adv7180_state *state)
 {
+	if (state->chip_info->flags & ADV7180_FLAG_V2) {
+		/* ADI recommended writes for improved video quality */
+		adv7180_write(state, 0x0080, 0x51);
+		adv7180_write(state, 0x0081, 0x51);
+		adv7180_write(state, 0x0082, 0x68);
+		adv7180_write(state, 0x0004, 0x17);
+	} else {
+		adv7180_write(state, 0x0004, 0x07);
+	}
+
 	/* ADI required writes */
 	adv7180_write(state, 0x0003, 0x0c);
-	adv7180_write(state, 0x0004, 0x07);
 	adv7180_write(state, 0x0013, 0x00);
 	adv7180_write(state, 0x001d, 0x40);
 
@@ -697,6 +707,13 @@ static unsigned int adv7182_lbias_settings[][3] = {
 	[ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
 };
 
+static unsigned int adv7280_lbias_settings[][3] = {
+	[ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
+	[ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
+	[ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
+};
+
 static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
 {
 	enum adv7182_input_type input_type;
@@ -725,7 +742,10 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
 		break;
 	}
 
-	lbias = adv7182_lbias_settings[input_type];
+	if (state->chip_info->flags & ADV7180_FLAG_V2)
+		lbias = adv7280_lbias_settings[input_type];
+	else
+		lbias = adv7182_lbias_settings[input_type];
 
 	for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++)
 		adv7180_write(state, 0x0052 + i, lbias[i]);
@@ -784,6 +804,35 @@ static const struct adv7180_chip_info adv7182_info = {
 	.select_input = adv7182_select_input,
 };
 
+static const struct adv7180_chip_info adv7280_info = {
+	.flags = ADV7180_FLAG_V2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7281_info = {
+	.flags = ADV7180_FLAG_V2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
 static int init_device(struct adv7180_state *state)
 {
 	int ret;
@@ -930,6 +979,9 @@ static int adv7180_remove(struct i2c_client *client)
 static const struct i2c_device_id adv7180_id[] = {
 	{ "adv7180", (kernel_ulong_t)&adv7180_info },
 	{ "adv7182", (kernel_ulong_t)&adv7182_info },
+	{ "adv7280", (kernel_ulong_t)&adv7280_info },
+	{ "adv7281", (kernel_ulong_t)&adv7281_info },
+	{ "adv7282", (kernel_ulong_t)&adv7281_info },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, adv7180_id);
-- 
1.8.0


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

* [PATCH 12/16] [media] adv7180: Add support for the adv7280-m/adv7281-m/adv7281-ma/adv7282-m
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (10 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 11/16] [media] adv7180: Add support for the adv7280/adv7281/adv7282 Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 13/16] [media] adv7180: Add I2P support Lars-Peter Clausen
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

This patch adds support for the adv7280-m/adv2781-m/adv7281-ma/adv7282-m
devices to the adv7180 driver. They are very similar to the
adv7280/adv7281/adv7282 but instead of parallel video out they feature a
MIPI CSI2 transmitter.

The CSI2 transmitter is configured via a separate I2C address, so we need to
register a dummy device for it.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 170 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 154 insertions(+), 16 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index ea6695c..868a677 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -124,6 +124,11 @@
 #define ADV7180_REG_NTSC_V_BIT_END	0x00E6
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
 
+#define ADV7180_REG_CSI_SLAVE_ADDR	0xFE
+
+#define ADV7180_CSI_REG_PWRDN	0x00
+#define ADV7180_CSI_PWRDN	0x80
+
 #define ADV7180_INPUT_CVBS_AIN1 0x00
 #define ADV7180_INPUT_CVBS_AIN2 0x01
 #define ADV7180_INPUT_CVBS_AIN3 0x02
@@ -155,10 +160,13 @@
 #define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10
 #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
 
+#define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
+
 struct adv7180_state;
 
 #define ADV7180_FLAG_RESET_POWERED	BIT(0)
 #define ADV7180_FLAG_V2			BIT(1)
+#define ADV7180_FLAG_MIPI_CSI2		BIT(2)
 
 struct adv7180_chip_info {
 	unsigned int flags;
@@ -181,6 +189,7 @@ struct adv7180_state {
 
 	struct i2c_client	*client;
 	unsigned int		register_page;
+	struct i2c_client	*csi_client;
 	const struct adv7180_chip_info *chip_info;
 };
 
@@ -215,6 +224,12 @@ static int adv7180_read(struct adv7180_state *state, unsigned int reg)
 	return i2c_smbus_read_byte_data(state->client, reg & 0xff);
 }
 
+static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg,
+	unsigned int value)
+{
+	return i2c_smbus_write_byte_data(state->csi_client, reg, value);
+}
+
 static int adv7180_set_video_standard(struct adv7180_state *state,
 	unsigned int std)
 {
@@ -407,13 +422,31 @@ out:
 static int adv7180_set_power(struct adv7180_state *state, bool on)
 {
 	u8 val;
+	int ret;
 
 	if (on)
 		val = ADV7180_PWR_MAN_ON;
 	else
 		val = ADV7180_PWR_MAN_OFF;
 
-	return adv7180_write(state, ADV7180_REG_PWR_MAN, val);
+	ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val);
+	if (ret)
+		return ret;
+
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		if (on) {
+			adv7180_csi_write(state, 0xDE, 0x02);
+			adv7180_csi_write(state, 0xD2, 0xF7);
+			adv7180_csi_write(state, 0xD8, 0x65);
+			adv7180_csi_write(state, 0xE0, 0x09);
+			adv7180_csi_write(state, 0x2C, 0x00);
+			adv7180_csi_write(state, 0x00, 0x00);
+		} else {
+			adv7180_csi_write(state, 0x00, 0x80);
+		}
+	}
+
+	return 0;
 }
 
 static int adv7180_s_power(struct v4l2_subdev *sd, int on)
@@ -550,13 +583,22 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
 static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
 				 struct v4l2_mbus_config *cfg)
 {
-	/*
-	 * The ADV7180 sensor supports BT.601/656 output modes.
-	 * The BT.656 is default and not yet configurable by s/w.
-	 */
-	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
-		     V4L2_MBUS_DATA_ACTIVE_HIGH;
-	cfg->type = V4L2_MBUS_BT656;
+	struct adv7180_state *state = to_state(sd);
+
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		cfg->type = V4L2_MBUS_CSI2;
+		cfg->flags = V4L2_MBUS_CSI2_1_LANE |
+				V4L2_MBUS_CSI2_CHANNEL_0 |
+				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+	} else {
+		/*
+		 * The ADV7180 sensor supports BT.601/656 output modes.
+		 * The BT.656 is default and not yet configurable by s/w.
+		 */
+		cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+				 V4L2_MBUS_DATA_ACTIVE_HIGH;
+		cfg->type = V4L2_MBUS_BT656;
+	}
 
 	return 0;
 }
@@ -639,20 +681,32 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
 
 static int adv7182_init(struct adv7180_state *state)
 {
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+		adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR,
+			ADV7180_DEFAULT_CSI_I2C_ADDR << 1);
+
 	if (state->chip_info->flags & ADV7180_FLAG_V2) {
 		/* ADI recommended writes for improved video quality */
 		adv7180_write(state, 0x0080, 0x51);
 		adv7180_write(state, 0x0081, 0x51);
 		adv7180_write(state, 0x0082, 0x68);
-		adv7180_write(state, 0x0004, 0x17);
-	} else {
-		adv7180_write(state, 0x0004, 0x07);
 	}
 
 	/* ADI required writes */
-	adv7180_write(state, 0x0003, 0x0c);
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		adv7180_write(state, 0x0003, 0x4e);
+		adv7180_write(state, 0x0004, 0x57);
+		adv7180_write(state, 0x001d, 0xc0);
+	} else {
+		if (state->chip_info->flags & ADV7180_FLAG_V2)
+			adv7180_write(state, 0x0004, 0x17);
+		else
+			adv7180_write(state, 0x0004, 0x07);
+		adv7180_write(state, 0x0003, 0x0c);
+		adv7180_write(state, 0x001d, 0x40);
+	}
+
 	adv7180_write(state, 0x0013, 0x00);
-	adv7180_write(state, 0x001d, 0x40);
 
 	return 0;
 }
@@ -818,15 +872,81 @@ static const struct adv7180_chip_info adv7280_info = {
 	.select_input = adv7182_select_input,
 };
 
+static const struct adv7180_chip_info adv7280_m_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN5) |
+		BIT(ADV7182_INPUT_CVBS_AIN6) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
 static const struct adv7180_chip_info adv7281_info = {
-	.flags = ADV7180_FLAG_V2,
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7281_m_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7281_ma_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
 	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
 		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN5) |
+		BIT(ADV7182_INPUT_CVBS_AIN6) |
 		BIT(ADV7182_INPUT_CVBS_AIN7) |
 		BIT(ADV7182_INPUT_CVBS_AIN8) |
 		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
 		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+		BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) |
 		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) |
 		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
 	.init = adv7182_init,
 	.set_std = adv7182_set_std,
@@ -907,6 +1027,13 @@ static int adv7180_probe(struct i2c_client *client,
 	state->client = client;
 	state->chip_info = (struct adv7180_chip_info *)id->driver_data;
 
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+		state->csi_client = i2c_new_dummy(client->adapter,
+				ADV7180_DEFAULT_CSI_I2C_ADDR);
+		if (!state->csi_client)
+			return -ENOMEM;
+	}
+
 	state->irq = client->irq;
 	mutex_init(&state->mutex);
 	state->autodetect = true;
@@ -921,7 +1048,7 @@ static int adv7180_probe(struct i2c_client *client,
 
 	ret = adv7180_init_controls(state);
 	if (ret)
-		goto err_unreg_subdev;
+		goto err_unregister_csi_client;
 
 	state->pad.flags = MEDIA_PAD_FL_SOURCE;
 	sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
@@ -954,7 +1081,9 @@ err_media_entity_cleanup:
 	media_entity_cleanup(&sd->entity);
 err_free_ctrl:
 	adv7180_exit_controls(state);
-err_unreg_subdev:
+err_unregister_csi_client:
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+		i2c_unregister_device(state->csi_client);
 	mutex_destroy(&state->mutex);
 err:
 	return ret;
@@ -972,7 +1101,12 @@ static int adv7180_remove(struct i2c_client *client)
 
 	media_entity_cleanup(&sd->entity);
 	adv7180_exit_controls(state);
+
+	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+		i2c_unregister_device(state->csi_client);
+
 	mutex_destroy(&state->mutex);
+
 	return 0;
 }
 
@@ -980,8 +1114,12 @@ static const struct i2c_device_id adv7180_id[] = {
 	{ "adv7180", (kernel_ulong_t)&adv7180_info },
 	{ "adv7182", (kernel_ulong_t)&adv7182_info },
 	{ "adv7280", (kernel_ulong_t)&adv7280_info },
+	{ "adv7280-m", (kernel_ulong_t)&adv7280_m_info },
 	{ "adv7281", (kernel_ulong_t)&adv7281_info },
+	{ "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
+	{ "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
 	{ "adv7282", (kernel_ulong_t)&adv7281_info },
+	{ "adv7282-m", (kernel_ulong_t)&adv7281_m_info },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, adv7180_id);
-- 
1.8.0


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

* [PATCH 13/16] [media] adv7180: Add I2P support
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (11 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 12/16] [media] adv7180: Add support for the adv7280-m/adv7281-m/adv7281-ma/adv7282-m Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:01 ` [PATCH 14/16] [media] adv7180: Add fast switch support Lars-Peter Clausen
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Some of the devices supported by this driver have a interlaced-to-
progressive converter which can optionally be enabled. This patch adds
support for enabling and disabling the I2P converter on such devices.

I2P mode can be enabled by selecting V4L2_FIELD_NONE instead of
V4L2_FIELD_INTERLACED for the format.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 156 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 148 insertions(+), 8 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 868a677..4d789c7 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -124,6 +124,7 @@
 #define ADV7180_REG_NTSC_V_BIT_END	0x00E6
 #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
 
+#define ADV7180_REG_VPP_SLAVE_ADDR	0xFD
 #define ADV7180_REG_CSI_SLAVE_ADDR	0xFE
 
 #define ADV7180_CSI_REG_PWRDN	0x00
@@ -161,12 +162,14 @@
 #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
 
 #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
+#define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
 
 struct adv7180_state;
 
 #define ADV7180_FLAG_RESET_POWERED	BIT(0)
 #define ADV7180_FLAG_V2			BIT(1)
 #define ADV7180_FLAG_MIPI_CSI2		BIT(2)
+#define ADV7180_FLAG_I2P		BIT(3)
 
 struct adv7180_chip_info {
 	unsigned int flags;
@@ -190,7 +193,9 @@ struct adv7180_state {
 	struct i2c_client	*client;
 	unsigned int		register_page;
 	struct i2c_client	*csi_client;
+	struct i2c_client	*vpp_client;
 	const struct adv7180_chip_info *chip_info;
+	enum v4l2_field		field;
 };
 
 static struct adv7180_state *ctrl_to_adv7180(struct v4l2_ctrl *ctrl)
@@ -236,6 +241,12 @@ static int adv7180_set_video_standard(struct adv7180_state *state,
 	return state->chip_info->set_std(state, std);
 }
 
+static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg,
+	unsigned int value)
+{
+	return i2c_smbus_write_byte_data(state->vpp_client, reg, value);
+}
+
 static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
 {
 	/* in case V4L2_IN_ST_NO_SIGNAL */
@@ -440,6 +451,8 @@ static int adv7180_set_power(struct adv7180_state *state, bool on)
 			adv7180_csi_write(state, 0xD8, 0x65);
 			adv7180_csi_write(state, 0xE0, 0x09);
 			adv7180_csi_write(state, 0x2C, 0x00);
+			if (state->field == V4L2_FIELD_NONE)
+				adv7180_csi_write(state, 0x1D, 0x80);
 			adv7180_csi_write(state, 0x00, 0x00);
 		} else {
 			adv7180_csi_write(state, 0x00, 0x80);
@@ -559,25 +572,97 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
 
 	fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
-	fmt->field = V4L2_FIELD_INTERLACED;
 	fmt->width = 720;
 	fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
 
 	return 0;
 }
 
+static int adv7180_set_field_mode(struct adv7180_state *state)
+{
+	if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
+		return 0;
+
+	if (state->field == V4L2_FIELD_NONE) {
+		if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+			adv7180_csi_write(state, 0x01, 0x20);
+			adv7180_csi_write(state, 0x02, 0x28);
+			adv7180_csi_write(state, 0x03, 0x38);
+			adv7180_csi_write(state, 0x04, 0x30);
+			adv7180_csi_write(state, 0x05, 0x30);
+			adv7180_csi_write(state, 0x06, 0x80);
+			adv7180_csi_write(state, 0x07, 0x70);
+			adv7180_csi_write(state, 0x08, 0x50);
+		}
+		adv7180_vpp_write(state, 0xa3, 0x00);
+		adv7180_vpp_write(state, 0x5b, 0x00);
+		adv7180_vpp_write(state, 0x55, 0x80);
+	} else {
+		if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+			adv7180_csi_write(state, 0x01, 0x18);
+			adv7180_csi_write(state, 0x02, 0x18);
+			adv7180_csi_write(state, 0x03, 0x30);
+			adv7180_csi_write(state, 0x04, 0x20);
+			adv7180_csi_write(state, 0x05, 0x28);
+			adv7180_csi_write(state, 0x06, 0x40);
+			adv7180_csi_write(state, 0x07, 0x58);
+			adv7180_csi_write(state, 0x08, 0x30);
+		}
+		adv7180_vpp_write(state, 0xa3, 0x70);
+		adv7180_vpp_write(state, 0x5b, 0x80);
+		adv7180_vpp_write(state, 0x55, 0x00);
+	}
+
+	return 0;
+}
+
 static int adv7180_get_pad_format(struct v4l2_subdev *sd,
 				  struct v4l2_subdev_fh *fh,
 				  struct v4l2_subdev_format *format)
 {
-	return adv7180_mbus_fmt(sd, &format->format);
+	struct adv7180_state *state = to_state(sd);
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		format->format = *v4l2_subdev_get_try_format(fh, 0);
+	} else {
+		adv7180_mbus_fmt(sd, &format->format);
+		format->format.field = state->field;
+	}
+
+	return 0;
 }
 
 static int adv7180_set_pad_format(struct v4l2_subdev *sd,
 				  struct v4l2_subdev_fh *fh,
 				  struct v4l2_subdev_format *format)
 {
-	return adv7180_mbus_fmt(sd, &format->format);
+	struct adv7180_state *state = to_state(sd);
+	struct v4l2_mbus_framefmt *framefmt;
+
+	switch (format->format.field) {
+	case V4L2_FIELD_NONE:
+		if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
+			format->format.field = V4L2_FIELD_INTERLACED;
+		break;
+	default:
+		format->format.field = V4L2_FIELD_INTERLACED;
+		break;
+	}
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		framefmt = &format->format;
+		if (state->field != format->format.field) {
+			state->field = format->format.field;
+			adv7180_set_power(state, false);
+			adv7180_set_field_mode(state);
+			adv7180_set_power(state, true);
+		}
+	} else {
+		framefmt = v4l2_subdev_get_try_format(fh, 0);
+		*framefmt = format->format;
+	}
+
+	return adv7180_mbus_fmt(sd, framefmt);
 }
 
 static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
@@ -685,6 +770,10 @@ static int adv7182_init(struct adv7180_state *state)
 		adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR,
 			ADV7180_DEFAULT_CSI_I2C_ADDR << 1);
 
+	if (state->chip_info->flags & ADV7180_FLAG_I2P)
+		adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR,
+			ADV7180_DEFAULT_VPP_I2C_ADDR << 1);
+
 	if (state->chip_info->flags & ADV7180_FLAG_V2) {
 		/* ADI recommended writes for improved video quality */
 		adv7180_write(state, 0x0080, 0x51);
@@ -859,7 +948,7 @@ static const struct adv7180_chip_info adv7182_info = {
 };
 
 static const struct adv7180_chip_info adv7280_info = {
-	.flags = ADV7180_FLAG_V2,
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
 	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
 		BIT(ADV7182_INPUT_CVBS_AIN2) |
 		BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -873,7 +962,7 @@ static const struct adv7180_chip_info adv7280_info = {
 };
 
 static const struct adv7180_chip_info adv7280_m_info = {
-	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
 	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
 		BIT(ADV7182_INPUT_CVBS_AIN2) |
 		BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -953,6 +1042,40 @@ static const struct adv7180_chip_info adv7281_ma_info = {
 	.select_input = adv7182_select_input,
 };
 
+static const struct adv7180_chip_info adv7282_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7282_m_info = {
+	.flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
+	.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+		BIT(ADV7182_INPUT_CVBS_AIN2) |
+		BIT(ADV7182_INPUT_CVBS_AIN3) |
+		BIT(ADV7182_INPUT_CVBS_AIN4) |
+		BIT(ADV7182_INPUT_CVBS_AIN7) |
+		BIT(ADV7182_INPUT_CVBS_AIN8) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+		BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+	.init = adv7182_init,
+	.set_std = adv7182_set_std,
+	.select_input = adv7182_select_input,
+};
+
 static int init_device(struct adv7180_state *state)
 {
 	int ret;
@@ -970,6 +1093,8 @@ static int init_device(struct adv7180_state *state)
 	if (ret)
 		goto out_unlock;
 
+	adv7180_set_field_mode(state);
+
 	/* register for interrupts */
 	if (state->irq > 0) {
 		/* config the Interrupt pin to be active low */
@@ -1025,6 +1150,7 @@ static int adv7180_probe(struct i2c_client *client,
 	}
 
 	state->client = client;
+	state->field = V4L2_FIELD_INTERLACED;
 	state->chip_info = (struct adv7180_chip_info *)id->driver_data;
 
 	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
@@ -1034,6 +1160,15 @@ static int adv7180_probe(struct i2c_client *client,
 			return -ENOMEM;
 	}
 
+	if (state->chip_info->flags & ADV7180_FLAG_I2P) {
+		state->vpp_client = i2c_new_dummy(client->adapter,
+				ADV7180_DEFAULT_VPP_I2C_ADDR);
+		if (!state->vpp_client) {
+			ret = -ENOMEM;
+			goto err_unregister_csi_client;
+		}
+	}
+
 	state->irq = client->irq;
 	mutex_init(&state->mutex);
 	state->autodetect = true;
@@ -1048,7 +1183,7 @@ static int adv7180_probe(struct i2c_client *client,
 
 	ret = adv7180_init_controls(state);
 	if (ret)
-		goto err_unregister_csi_client;
+		goto err_unregister_vpp_client;
 
 	state->pad.flags = MEDIA_PAD_FL_SOURCE;
 	sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
@@ -1081,6 +1216,9 @@ err_media_entity_cleanup:
 	media_entity_cleanup(&sd->entity);
 err_free_ctrl:
 	adv7180_exit_controls(state);
+err_unregister_vpp_client:
+	if (state->chip_info->flags & ADV7180_FLAG_I2P)
+		i2c_unregister_device(state->vpp_client);
 err_unregister_csi_client:
 	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
 		i2c_unregister_device(state->csi_client);
@@ -1102,6 +1240,8 @@ static int adv7180_remove(struct i2c_client *client)
 	media_entity_cleanup(&sd->entity);
 	adv7180_exit_controls(state);
 
+	if (state->chip_info->flags & ADV7180_FLAG_I2P)
+		i2c_unregister_device(state->vpp_client);
 	if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
 		i2c_unregister_device(state->csi_client);
 
@@ -1118,8 +1258,8 @@ static const struct i2c_device_id adv7180_id[] = {
 	{ "adv7281", (kernel_ulong_t)&adv7281_info },
 	{ "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
 	{ "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
-	{ "adv7282", (kernel_ulong_t)&adv7281_info },
-	{ "adv7282-m", (kernel_ulong_t)&adv7281_m_info },
+	{ "adv7282", (kernel_ulong_t)&adv7282_info },
+	{ "adv7282-m", (kernel_ulong_t)&adv7282_m_info },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, adv7180_id);
-- 
1.8.0


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

* [PATCH 14/16] [media] adv7180: Add fast switch support
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (12 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 13/16] [media] adv7180: Add I2P support Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:54   ` Hans Verkuil
  2015-01-13 12:01 ` [PATCH 15/16] [media] adv7180: Add free run mode controls Lars-Peter Clausen
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

In fast switch mode the adv7180 (and similar) can lock onto a new signal
faster when switching between different inputs. As a downside though it is
no longer able to auto-detect the incoming format.

The fast switch mode is exposed as a boolean v4l control that allows
userspace applications to either enable or disable fast switch mode.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 4d789c7..82c8296 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -127,6 +127,9 @@
 #define ADV7180_REG_VPP_SLAVE_ADDR	0xFD
 #define ADV7180_REG_CSI_SLAVE_ADDR	0xFE
 
+#define ADV7180_REG_FLCONTROL 0x40e0
+#define ADV7180_FLCONTROL_FL_ENABLE 0x1
+
 #define ADV7180_CSI_REG_PWRDN	0x00
 #define ADV7180_CSI_PWRDN	0x80
 
@@ -164,6 +167,8 @@
 #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
 #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
 
+#define V4L2_CID_ADV_FAST_SWITCH	(V4L2_CID_DV_CLASS_BASE + 0x1010)
+
 struct adv7180_state;
 
 #define ADV7180_FLAG_RESET_POWERED	BIT(0)
@@ -509,6 +514,18 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 			break;
 		ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val);
 		break;
+	case V4L2_CID_ADV_FAST_SWITCH:
+		if (ctrl->val) {
+			/* ADI required write */
+			adv7180_write(state, 0x80d9, 0x44);
+			adv7180_write(state, ADV7180_REG_FLCONTROL,
+				ADV7180_FLCONTROL_FL_ENABLE);
+		} else {
+			/* ADI required write */
+			adv7180_write(state, 0x80d9, 0xc4);
+			adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
+		}
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -521,6 +538,16 @@ static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
 	.s_ctrl = adv7180_s_ctrl,
 };
 
+static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
+	.ops = &adv7180_ctrl_ops,
+	.id = V4L2_CID_ADV_FAST_SWITCH,
+	.name = "Fast switching",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+};
+
 static int adv7180_init_controls(struct adv7180_state *state)
 {
 	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
@@ -537,6 +564,8 @@ static int adv7180_init_controls(struct adv7180_state *state)
 	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
 			  V4L2_CID_HUE, ADV7180_HUE_MIN,
 			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
+	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
+
 	state->sd.ctrl_handler = &state->ctrl_hdl;
 	if (state->ctrl_hdl.error) {
 		int err = state->ctrl_hdl.error;
-- 
1.8.0


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

* [PATCH 15/16] [media] adv7180: Add free run mode controls
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (13 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 14/16] [media] adv7180: Add fast switch support Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-16 10:20   ` Hans Verkuil
  2015-01-13 12:01 ` [PATCH 16/16] [media] Add MAINTAINERS entry for the adv7180 Lars-Peter Clausen
  2015-01-13 13:04 ` [PATCH 00/16] [media] adv7180: Add support for different chip Hans Verkuil
  16 siblings, 1 reply; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

The adv7180 (and similar) has support for a so called free run mode in which
it will output a predefined test signal. This patch adds support for
configuring the various aspects of the so called free run mode.

The patch adds three new v4l controls:
	* Free Running Mode: Allows to either disable or enable free running
	  mode or set it to automatic. In automatic mode the adv7180 will go to
	  free run mode if no external signal source could be detected
	* Free Running Pattern: Allows to select which pattern will be displayed
	  in free run mode
	* Free Running Color: Allows to select the color of the pattern

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/media/i2c/adv7180.c | 125 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 122 insertions(+), 3 deletions(-)

diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 82c8296..678d6c9 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -75,6 +75,9 @@
 #define ADV7180_HUE_DEF		0
 #define ADV7180_HUE_MAX		128
 
+#define ADV7180_REG_DEF_VAL_Y		0x000c
+#define ADV7180_REG_DEF_VAL_C		0x000d
+
 #define ADV7180_REG_CTRL		0x000e
 #define ADV7180_CTRL_IRQ_SPACE		0x20
 
@@ -168,6 +171,11 @@
 #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
 
 #define V4L2_CID_ADV_FAST_SWITCH	(V4L2_CID_DV_CLASS_BASE + 0x1010)
+#define V4L2_CID_ADV_FREE_RUN_COLOR	(V4L2_CID_DV_CLASS_BASE + 0x1002)
+#define V4L2_CID_ADV_FREE_RUN_MODE	(V4L2_CID_DV_CLASS_BASE + 0x1003)
+#define V4L2_CID_ADV_FREE_RUN_PATTERN	(V4L2_CID_DV_CLASS_BASE + 0x1004)
+
+#define ADV7180_INPUT_DISABLED (~0x00)
 
 struct adv7180_state;
 
@@ -193,6 +201,7 @@ struct adv7180_state {
 	v4l2_std_id		curr_norm;
 	bool			autodetect;
 	bool			powered;
+	bool			force_free_run;
 	u8			input;
 
 	struct i2c_client	*client;
@@ -363,10 +372,13 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
 		goto out;
 	}
 
-	ret = state->chip_info->select_input(state, input);
-
-	if (ret == 0)
+	if (state->force_free_run) {
 		state->input = input;
+	} else {
+		ret = state->chip_info->select_input(state, input);
+		if (ret == 0)
+			state->input = input;
+	}
 out:
 	mutex_unlock(&state->mutex);
 	return ret;
@@ -488,6 +500,7 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct adv7180_state *state = ctrl_to_adv7180(ctrl);
 	int ret = mutex_lock_interruptible(&state->mutex);
+	int reg_val;
 	int val;
 
 	if (ret)
@@ -526,6 +539,53 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
 			adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
 		}
 		break;
+	case V4L2_CID_ADV_FREE_RUN_MODE:
+		switch (ctrl->val) {
+		case 1: /* Enabled */
+			ret = state->chip_info->select_input(state,
+				ADV7180_INPUT_DISABLED);
+			state->force_free_run = true;
+			break;
+		case 0: /* Disabled */
+		case 2: /* Automatic */
+			ret = state->chip_info->select_input(state,
+				state->input);
+			state->force_free_run = false;
+			break;
+		default:
+			break;
+		}
+		reg_val = adv7180_read(state, ADV7180_REG_DEF_VAL_Y);
+		reg_val &= 0xfc;
+		reg_val |= ctrl->val;
+		adv7180_write(state, ADV7180_REG_DEF_VAL_Y, reg_val);
+		break;
+	case V4L2_CID_ADV_FREE_RUN_PATTERN:
+		reg_val = adv7180_read(state, 0x14);
+		reg_val &= 0xf8;
+		reg_val |= ctrl->val;
+		adv7180_write(state, 0x14, reg_val);
+		break;
+	case V4L2_CID_ADV_FREE_RUN_COLOR: {
+		int r = (ctrl->val & 0xff0000) >> 16;
+		int g = (ctrl->val & 0x00ff00) >> 8;
+		int b = (ctrl->val & 0x0000ff);
+		/* RGB -> YCbCr, numerical approximation */
+		int y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
+		int cb = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
+		int cr = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
+
+		/* Y is 6-bit, Cb and Cr 4-bit */
+		y >>= 2;
+		cb >>= 4;
+		cr >>= 4;
+
+		reg_val = adv7180_read(state, ADV7180_REG_DEF_VAL_Y);
+		adv7180_write(state, ADV7180_REG_DEF_VAL_Y,
+			(y << 2) | (reg_val & 0x03));
+		adv7180_write(state, ADV7180_REG_DEF_VAL_C, (cr << 4) | cb);
+		break;
+	}
 	default:
 		ret = -EINVAL;
 	}
@@ -548,6 +608,53 @@ static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
 	.step = 1,
 };
 
+static const char * const adv7180_free_run_pattern_strings[] = {
+	"Solid",
+	"Bars",
+	"Luma Ramp",
+	"Reserved",
+	"Reserved",
+	"Boundary Box",
+};
+
+static const char * const adv7180_free_run_mode_strings[] = {
+	"Disabled",
+	"Enabled",
+	"Automatic",
+};
+
+static const struct v4l2_ctrl_config adv7180_ctrl_free_run_color = {
+	.ops = &adv7180_ctrl_ops,
+	.id = V4L2_CID_ADV_FREE_RUN_COLOR,
+	.name = "Free Running Color",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = 0,
+	.max = 0xffffff,
+	.step = 0x1,
+};
+
+static const struct v4l2_ctrl_config adv7180_ctrl_free_run_mode = {
+	.ops = &adv7180_ctrl_ops,
+	.id = V4L2_CID_ADV_FREE_RUN_MODE,
+	.name = "Free Running Mode",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 0,
+	.max = ARRAY_SIZE(adv7180_free_run_mode_strings) - 1,
+	.def = 2,
+	.qmenu = adv7180_free_run_mode_strings,
+};
+
+static const struct v4l2_ctrl_config adv7180_ctrl_free_run_pattern = {
+	.ops = &adv7180_ctrl_ops,
+	.id = V4L2_CID_ADV_FREE_RUN_PATTERN,
+	.name = "Free Running Pattern",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 0,
+	.max = ARRAY_SIZE(adv7180_free_run_pattern_strings) - 1,
+	.menu_skip_mask = 0x18, /* 0x3 and 0x4 are reserved */
+	.qmenu = adv7180_free_run_pattern_strings,
+};
+
 static int adv7180_init_controls(struct adv7180_state *state)
 {
 	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
@@ -565,6 +672,12 @@ static int adv7180_init_controls(struct adv7180_state *state)
 			  V4L2_CID_HUE, ADV7180_HUE_MIN,
 			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
 	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
+	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_free_run_color,
+		NULL);
+	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_free_run_mode,
+		NULL);
+	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_free_run_pattern,
+		NULL);
 
 	state->sd.ctrl_handler = &state->ctrl_hdl;
 	if (state->ctrl_hdl.error) {
@@ -784,6 +897,9 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
 {
 	int ret;
 
+	if (input == ADV7180_INPUT_DISABLED)
+		input = 0x00;
+
 	ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
 	if (ret < 0)
 		return ret;
@@ -893,6 +1009,9 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
 	unsigned int i;
 	int ret;
 
+	if (input == ADV7180_INPUT_DISABLED)
+		return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 0xff);
+
 	ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input);
 	if (ret)
 		return ret;
-- 
1.8.0


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

* [PATCH 16/16] [media] Add MAINTAINERS entry for the adv7180
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (14 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 15/16] [media] adv7180: Add free run mode controls Lars-Peter Clausen
@ 2015-01-13 12:01 ` Lars-Peter Clausen
  2015-01-13 12:55   ` Mats Randgaard (matrandg)
  2015-01-13 13:04 ` [PATCH 00/16] [media] adv7180: Add support for different chip Hans Verkuil
  16 siblings, 1 reply; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 12:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Lars-Peter Clausen

Add myself as the maintainer for the adv7180 video subdev driver.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4318f34..22bb77e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -659,6 +659,13 @@ L:	linux-media@vger.kernel.org
 S:	Maintained
 F:	drivers/media/i2c/ad9389b*
 
+ANALOG DEVICES INC ADV7180 DRIVER
+M:	Lars-Peter Clausen <lars@metafoo.de>
+L:	linux-media@vger.kernel.org
+W:	http://ez.analog.com/community/linux-device-drivers
+S:	Supported
+F:	drivers/media/i2c/adv7180.c
+
 ANALOG DEVICES INC ADV7511 DRIVER
 M:	Hans Verkuil <hans.verkuil@cisco.com>
 L:	linux-media@vger.kernel.org
-- 
1.8.0


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

* Re: [PATCH 14/16] [media] adv7180: Add fast switch support
  2015-01-13 12:01 ` [PATCH 14/16] [media] adv7180: Add fast switch support Lars-Peter Clausen
@ 2015-01-13 12:54   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-01-13 12:54 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: linux-media

Hi Lars-Peter,

A few small comments:

On 01/13/15 13:01, Lars-Peter Clausen wrote:
> In fast switch mode the adv7180 (and similar) can lock onto a new signal
> faster when switching between different inputs. As a downside though it is
> no longer able to auto-detect the incoming format.
> 
> The fast switch mode is exposed as a boolean v4l control that allows
> userspace applications to either enable or disable fast switch mode.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/media/i2c/adv7180.c | 29 +++++++++++++++++++++++++++++
>  1 file changed, 29 insertions(+)
> 
> diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
> index 4d789c7..82c8296 100644
> --- a/drivers/media/i2c/adv7180.c
> +++ b/drivers/media/i2c/adv7180.c
> @@ -127,6 +127,9 @@
>  #define ADV7180_REG_VPP_SLAVE_ADDR	0xFD
>  #define ADV7180_REG_CSI_SLAVE_ADDR	0xFE
>  
> +#define ADV7180_REG_FLCONTROL 0x40e0
> +#define ADV7180_FLCONTROL_FL_ENABLE 0x1
> +
>  #define ADV7180_CSI_REG_PWRDN	0x00
>  #define ADV7180_CSI_PWRDN	0x80
>  
> @@ -164,6 +167,8 @@
>  #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
>  #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
>  
> +#define V4L2_CID_ADV_FAST_SWITCH	(V4L2_CID_DV_CLASS_BASE + 0x1010)

You need to reserve a range for private controls in uapi/linux/v4l2-controls.h
(see e.g. V4L2_CID_USER_SAA7134_BASE). Currently only user class controls
have a range reservation, but it can be done for other control classes as well.
However, I would put this control in the user class anyway. The DV class isn't
really appropriate for an SDTV device.

> +
>  struct adv7180_state;
>  
>  #define ADV7180_FLAG_RESET_POWERED	BIT(0)
> @@ -509,6 +514,18 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
>  			break;
>  		ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val);
>  		break;
> +	case V4L2_CID_ADV_FAST_SWITCH:
> +		if (ctrl->val) {
> +			/* ADI required write */
> +			adv7180_write(state, 0x80d9, 0x44);
> +			adv7180_write(state, ADV7180_REG_FLCONTROL,
> +				ADV7180_FLCONTROL_FL_ENABLE);
> +		} else {
> +			/* ADI required write */
> +			adv7180_write(state, 0x80d9, 0xc4);
> +			adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
> +		}
> +		break;
>  	default:
>  		ret = -EINVAL;
>  	}
> @@ -521,6 +538,16 @@ static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
>  	.s_ctrl = adv7180_s_ctrl,
>  };
>  
> +static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
> +	.ops = &adv7180_ctrl_ops,
> +	.id = V4L2_CID_ADV_FAST_SWITCH,
> +	.name = "Fast switching",

This should be "Fast Switching" to be consistent with the standard control naming
convention.

> +	.type = V4L2_CTRL_TYPE_BOOLEAN,
> +	.min = 0,
> +	.max = 1,
> +	.step = 1,
> +};
> +
>  static int adv7180_init_controls(struct adv7180_state *state)
>  {
>  	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
> @@ -537,6 +564,8 @@ static int adv7180_init_controls(struct adv7180_state *state)
>  	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
>  			  V4L2_CID_HUE, ADV7180_HUE_MIN,
>  			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
> +	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
> +
>  	state->sd.ctrl_handler = &state->ctrl_hdl;
>  	if (state->ctrl_hdl.error) {
>  		int err = state->ctrl_hdl.error;
> 

Regards,

	Hans

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

* Re: [PATCH 16/16] [media] Add MAINTAINERS entry for the adv7180
  2015-01-13 12:01 ` [PATCH 16/16] [media] Add MAINTAINERS entry for the adv7180 Lars-Peter Clausen
@ 2015-01-13 12:55   ` Mats Randgaard (matrandg)
  2015-01-13 13:02     ` Lars-Peter Clausen
  0 siblings, 1 reply; 24+ messages in thread
From: Mats Randgaard (matrandg) @ 2015-01-13 12:55 UTC (permalink / raw)
  To: Lars-Peter Clausen, Hans Verkuil; +Cc: linux-media

On 01/13/2015 01:01 PM, Lars-Peter Clausen wrote:
> Add myself as the maintainer  for the adv7180 video subdev driver.
 >
 > Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> --- MAINTAINERS |
 > 7 +++++++ 1 file changed, 7 insertions(+)
 >
 > diff --git a/MAINTAINERS b/MAINTAINERS index 4318f34..22bb77e 100644
 > --- a/MAINTAINERS +++ b/MAINTAINERS @@ -659,6 +659,13 @@ L:
 > linux-media@vger.kernel.org S:    Maintained F:
 > drivers/media/i2c/ad9389b*
 >
 > +ANALOG DEVICES INC ADV7180 DRIVER +M:    Lars-Peter Clausen
 > <lars@metafoo.de> +L:    linux-media@vger.kernel.org +W:
 > http://ez.analog.com/community/linux-device-drivers

I think the web address should be http://ez.analog.com/community/video

It is written much more about ADV7180 there, and people asking questions 
about video devices has been directed to the Video forum in the past.

Regards,

Mats Randgaard

>
 > +S:    Supported +F:    drivers/media/i2c/adv7180.c + ANALOG DEVICES INC
 > ADV7511 DRIVER M:    Hans Verkuil <hans.verkuil@cisco.com> L:
 > linux-media@vger.kernel.org



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

* Re: [PATCH 16/16] [media] Add MAINTAINERS entry for the adv7180
  2015-01-13 12:55   ` Mats Randgaard (matrandg)
@ 2015-01-13 13:02     ` Lars-Peter Clausen
  0 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 13:02 UTC (permalink / raw)
  To: Mats Randgaard (matrandg), Hans Verkuil; +Cc: linux-media

On 01/13/2015 01:55 PM, Mats Randgaard (matrandg) wrote:
> On 01/13/2015 01:01 PM, Lars-Peter Clausen wrote:
>> Add myself as the maintainer  for the adv7180 video subdev driver.
>  >
>  > Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> --- MAINTAINERS |
>  > 7 +++++++ 1 file changed, 7 insertions(+)
>  >
>  > diff --git a/MAINTAINERS b/MAINTAINERS index 4318f34..22bb77e 100644
>  > --- a/MAINTAINERS +++ b/MAINTAINERS @@ -659,6 +659,13 @@ L:
>  > linux-media@vger.kernel.org S:    Maintained F:
>  > drivers/media/i2c/ad9389b*
>  >
>  > +ANALOG DEVICES INC ADV7180 DRIVER +M:    Lars-Peter Clausen
>  > <lars@metafoo.de> +L:    linux-media@vger.kernel.org +W:
>  > http://ez.analog.com/community/linux-device-drivers
>
> I think the web address should be http://ez.analog.com/community/video
>
> It is written much more about ADV7180 there, and people asking questions
> about video devices has been directed to the Video forum in the past.

Well depends on the subject of the question. If you have a question about 
the Linux device driver the correct section is the Linux device driver 
section. If you have question about the chip itself it should be in the 
video section. But this maintainers entry is about the driver not the chip.

- Lars

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

* Re: [PATCH 00/16] [media] adv7180: Add support for different chip
  2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
                   ` (15 preceding siblings ...)
  2015-01-13 12:01 ` [PATCH 16/16] [media] Add MAINTAINERS entry for the adv7180 Lars-Peter Clausen
@ 2015-01-13 13:04 ` Hans Verkuil
  2015-01-13 13:15   ` Lars-Peter Clausen
  16 siblings, 1 reply; 24+ messages in thread
From: Hans Verkuil @ 2015-01-13 13:04 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: linux-media

Hi Lars,

On 01/13/15 13:01, Lars-Peter Clausen wrote:
> The adv7180 is part of a larger family of chips which all implement
> different features from a feature superset. This patch series step by step
> extends the current adv7180 with features from the superset that are
> currently not supported and gradually adding support for more variations of
> the chip.
> 
> The first half of this series contains fixes and cleanups while the second
> half adds new features and support for new chips.

For patches 1-7, 9-13 and 16:

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

I need a bit more time to review patches 8 and 15. Ping me if you haven't
heard from me by Friday.

BTW: is the adv7183 part of the same family? There is a separate i2c driver
for it in the kernel, so I was wondering if that could be merged into this
driver eventually.

Did you check with authors of drivers that use the adv7180 to ensure nothing
broke? They should be pinged about this at least.

Regards,

	Hans

> 
> - Lars
> 
> Lars-Peter Clausen (16):
>   [media] adv7180: Do not request the IRQ again during resume
>   [media] adv7180: Pass correct flags to request_threaded_irq()
>   [media] adv7180: Use inline function instead of macro
>   [media] adv7180: Cleanup register define naming
>   [media] adv7180: Do implicit register paging
>   [media] adv7180: Reset the device before initialization
>   [media] adv7180: Add media controller support
>   [media] adv7180: Consolidate video mode setting
>   [media] adv7180: Prepare for multi-chip support
>   [media] adv7180: Add support for the ad7182
>   [media] adv7180: Add support for the adv7280/adv7281/adv7282
>   [media] adv7180: Add support for the
>     adv7280-m/adv7281-m/adv7281-ma/adv7282-m
>   [media] adv7180: Add I2P support
>   [media] adv7180: Add fast switch support
>   [media] adv7180: Add free run mode controls
>   [media] Add MAINTAINERS entry for the adv7180
> 
>  MAINTAINERS                       |    7 +
>  drivers/media/i2c/Kconfig         |    2 +-
>  drivers/media/i2c/adv7180.c       | 1137 ++++++++++++++++++++++++++++++-------
>  drivers/media/pci/sta2x11/Kconfig |    1 +
>  drivers/media/platform/Kconfig    |    2 +-
>  5 files changed, 947 insertions(+), 202 deletions(-)
> 


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

* Re: [PATCH 00/16] [media] adv7180: Add support for different chip
  2015-01-13 13:04 ` [PATCH 00/16] [media] adv7180: Add support for different chip Hans Verkuil
@ 2015-01-13 13:15   ` Lars-Peter Clausen
  0 siblings, 0 replies; 24+ messages in thread
From: Lars-Peter Clausen @ 2015-01-13 13:15 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media

On 01/13/2015 02:04 PM, Hans Verkuil wrote:
> Hi Lars,
>
> On 01/13/15 13:01, Lars-Peter Clausen wrote:
>> The adv7180 is part of a larger family of chips which all implement
>> different features from a feature superset. This patch series step by step
>> extends the current adv7180 with features from the superset that are
>> currently not supported and gradually adding support for more variations of
>> the chip.
>>
>> The first half of this series contains fixes and cleanups while the second
>> half adds new features and support for new chips.
>
> For patches 1-7, 9-13 and 16:
>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
>
> I need a bit more time to review patches 8 and 15. Ping me if you haven't
> heard from me by Friday.

Thanks.

>
> BTW: is the adv7183 part of the same family? There is a separate i2c driver
> for it in the kernel, so I was wondering if that could be merged into this
> driver eventually.

Yea, I had a look at that, and it appears to be related, but it seems to be 
some early derivative and things weren't fully standardized at that point, 
so while similar there were a few notable differences. And I think the 
adv7183 isn't even produced anymore. So I didn't try to integrate it yet, 
but it might happen at some point.

>
> Did you check with authors of drivers that use the adv7180 to ensure nothing
> broke? They should be pinged about this at least.

I tried to make sure that the register write sequence is still the same for 
adv7180 as it was before. The only thing new for the adv7180 is support for 
the new controls.

I'll include a few more people on Cc for v2.

- Lars

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

* Re: [PATCH 08/16] [media] adv7180: Consolidate video mode setting
  2015-01-13 12:01 ` [PATCH 08/16] [media] adv7180: Consolidate video mode setting Lars-Peter Clausen
@ 2015-01-16 10:12   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-01-16 10:12 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: linux-media

Hi Lars,

On 01/13/2015 01:01 PM, Lars-Peter Clausen wrote:
> We have basically the same code to set the video standard in init_device()
> and adv7180_s_std(). Factor this out into a common helper function.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/media/i2c/adv7180.c | 67 ++++++++++++++++++++++-----------------------
>  1 file changed, 32 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
> index 349cae3..4d9bcc8 100644
> --- a/drivers/media/i2c/adv7180.c
> +++ b/drivers/media/i2c/adv7180.c
> @@ -304,37 +304,54 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
>  	return ret;
>  }
>  
> -static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
> +static int adv7180_program_std(struct adv7180_state *state)
>  {
> -	struct adv7180_state *state = to_state(sd);
> -	int ret = mutex_lock_interruptible(&state->mutex);
> -	if (ret)
> -		return ret;
> +	int ret;
>  
> -	/* all standards -> autodetect */
> -	if (std == V4L2_STD_ALL) {
> +	if (state->autodetect) {

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

That said, I am unhappy about this autodetect handling. That isn't something
that this patch changes, which is why I've Acked it, but I hope you can look
at this yourself.

The reason I don't like it is because 1) it is non-standard behavior of a video
receiver to turn on autodetect if STD_ALL is passed in. And 2) there are
multiple autodetect modes and the one chosen seems to imply that NTSC M is not
autodetected, only NTSC-J. I have no adv7180 hardware, so I can't test if that
is indeed what is happening. In any case, every autodetect mode seems to
autodetect only a subset of all possible standards according to the adv7180
datasheet, which doesn't really make it a real autodetect IMHO.

The third and last reason is that if the autodetect system switches from NTSC to
PAL you suddenly get larger frames. Depending on the exact DMA configuration
of the board this could lead to buffer overflows (e.g. if the DMA configuration
just DMAs until the end of frame, and yes, such terrible DMA implementations
exist).

An initial autodetect when the driver is loaded might make sense in order to get
a reasonable initial standard, but I am skeptical about using it anywhere else.

BTW, if you can easily detect standard changes via an interrupt, then you can
use that interrupt to send a V4L2_EVENT_SOURCE_CHANGE event. That would allow
applications to dynamically react to changes in the standard.

As I said, I have no adv718x hardware so I am unable to test this, but if you
could test this autodetect functionality and think about whether it should be
kept at all, then that would be useful.

Regards,

	Hans

>  		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
>  				    ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
>  				    | state->input);
>  		if (ret < 0)
> -			goto out;
> +			return ret;
>  
>  		__adv7180_status(state, NULL, &state->curr_norm);
> -		state->autodetect = true;
>  	} else {
> -		ret = v4l2_std_to_adv7180(std);
> +		ret = v4l2_std_to_adv7180(state->curr_norm);
>  		if (ret < 0)
> -			goto out;
> +			return ret;
>  
>  		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
>  				    ret | state->input);
>  		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
> +{
> +	struct adv7180_state *state = to_state(sd);
> +	int ret = mutex_lock_interruptible(&state->mutex);
> +
> +	if (ret)
> +		return ret;
> +
> +	/* all standards -> autodetect */
> +	if (std == V4L2_STD_ALL) {
> +		state->autodetect = true;
> +	} else {
> +		/* Make sure we can support this std */
> +		ret = v4l2_std_to_adv7180(std);
> +		if (ret < 0)
>  			goto out;
>  
>  		state->curr_norm = std;
>  		state->autodetect = false;
>  	}
> -	ret = 0;
> +
> +	ret = adv7180_program_std(state);
>  out:
>  	mutex_unlock(&state->mutex);
>  	return ret;
> @@ -547,30 +564,10 @@ static int init_device(struct adv7180_state *state)
>  	adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
>  	usleep_range(2000, 10000);
>  
> -	/* Initialize adv7180 */
> -	/* Enable autodetection */
> -	if (state->autodetect) {
> -		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
> -				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
> -					      | state->input);
> -		if (ret < 0)
> -			goto out_unlock;
> -
> -		ret = adv7180_write(state, ADV7180_REG_AUTODETECT_ENABLE,
> -					      ADV7180_AUTODETECT_DEFAULT);
> -		if (ret < 0)
> -			goto out_unlock;
> -	} else {
> -		ret = v4l2_std_to_adv7180(state->curr_norm);
> -		if (ret < 0)
> -			goto out_unlock;
> -
> -		ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
> -					      ret | state->input);
> -		if (ret < 0)
> -			goto out_unlock;
> +	ret = adv7180_program_std(state);
> +	if (ret)
> +		goto out_unlock;
>  
> -	}
>  	/* ITU-R BT.656-4 compatible */
>  	ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
>  			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
> 


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

* Re: [PATCH 15/16] [media] adv7180: Add free run mode controls
  2015-01-13 12:01 ` [PATCH 15/16] [media] adv7180: Add free run mode controls Lars-Peter Clausen
@ 2015-01-16 10:20   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-01-16 10:20 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: linux-media

Hi Lars,

On 01/13/2015 01:01 PM, Lars-Peter Clausen wrote:
> The adv7180 (and similar) has support for a so called free run mode in which
> it will output a predefined test signal. This patch adds support for
> configuring the various aspects of the so called free run mode.
> 
> The patch adds three new v4l controls:
> 	* Free Running Mode: Allows to either disable or enable free running
> 	  mode or set it to automatic. In automatic mode the adv7180 will go to
> 	  free run mode if no external signal source could be detected
> 	* Free Running Pattern: Allows to select which pattern will be displayed
> 	  in free run mode
> 	* Free Running Color: Allows to select the color of the pattern
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/media/i2c/adv7180.c | 125 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 122 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
> index 82c8296..678d6c9 100644
> --- a/drivers/media/i2c/adv7180.c
> +++ b/drivers/media/i2c/adv7180.c
> @@ -75,6 +75,9 @@
>  #define ADV7180_HUE_DEF		0
>  #define ADV7180_HUE_MAX		128
>  
> +#define ADV7180_REG_DEF_VAL_Y		0x000c
> +#define ADV7180_REG_DEF_VAL_C		0x000d
> +
>  #define ADV7180_REG_CTRL		0x000e
>  #define ADV7180_CTRL_IRQ_SPACE		0x20
>  
> @@ -168,6 +171,11 @@
>  #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
>  
>  #define V4L2_CID_ADV_FAST_SWITCH	(V4L2_CID_DV_CLASS_BASE + 0x1010)
> +#define V4L2_CID_ADV_FREE_RUN_COLOR	(V4L2_CID_DV_CLASS_BASE + 0x1002)
> +#define V4L2_CID_ADV_FREE_RUN_MODE	(V4L2_CID_DV_CLASS_BASE + 0x1003)
> +#define V4L2_CID_ADV_FREE_RUN_PATTERN	(V4L2_CID_DV_CLASS_BASE + 0x1004)

See same comment as I made in patch 8 regarding private controls.

> +
> +#define ADV7180_INPUT_DISABLED (~0x00)
>  
>  struct adv7180_state;
>  
> @@ -193,6 +201,7 @@ struct adv7180_state {
>  	v4l2_std_id		curr_norm;
>  	bool			autodetect;
>  	bool			powered;
> +	bool			force_free_run;
>  	u8			input;
>  
>  	struct i2c_client	*client;
> @@ -363,10 +372,13 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
>  		goto out;
>  	}
>  
> -	ret = state->chip_info->select_input(state, input);
> -
> -	if (ret == 0)
> +	if (state->force_free_run) {
>  		state->input = input;
> +	} else {
> +		ret = state->chip_info->select_input(state, input);
> +		if (ret == 0)
> +			state->input = input;
> +	}
>  out:
>  	mutex_unlock(&state->mutex);
>  	return ret;
> @@ -488,6 +500,7 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
>  {
>  	struct adv7180_state *state = ctrl_to_adv7180(ctrl);
>  	int ret = mutex_lock_interruptible(&state->mutex);
> +	int reg_val;
>  	int val;
>  
>  	if (ret)
> @@ -526,6 +539,53 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
>  			adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
>  		}
>  		break;
> +	case V4L2_CID_ADV_FREE_RUN_MODE:
> +		switch (ctrl->val) {
> +		case 1: /* Enabled */
> +			ret = state->chip_info->select_input(state,
> +				ADV7180_INPUT_DISABLED);
> +			state->force_free_run = true;
> +			break;
> +		case 0: /* Disabled */
> +		case 2: /* Automatic */
> +			ret = state->chip_info->select_input(state,
> +				state->input);
> +			state->force_free_run = false;
> +			break;
> +		default:
> +			break;
> +		}
> +		reg_val = adv7180_read(state, ADV7180_REG_DEF_VAL_Y);
> +		reg_val &= 0xfc;
> +		reg_val |= ctrl->val;
> +		adv7180_write(state, ADV7180_REG_DEF_VAL_Y, reg_val);
> +		break;
> +	case V4L2_CID_ADV_FREE_RUN_PATTERN:
> +		reg_val = adv7180_read(state, 0x14);
> +		reg_val &= 0xf8;
> +		reg_val |= ctrl->val;
> +		adv7180_write(state, 0x14, reg_val);
> +		break;
> +	case V4L2_CID_ADV_FREE_RUN_COLOR: {
> +		int r = (ctrl->val & 0xff0000) >> 16;
> +		int g = (ctrl->val & 0x00ff00) >> 8;
> +		int b = (ctrl->val & 0x0000ff);
> +		/* RGB -> YCbCr, numerical approximation */
> +		int y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
> +		int cb = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
> +		int cr = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
> +
> +		/* Y is 6-bit, Cb and Cr 4-bit */
> +		y >>= 2;
> +		cb >>= 4;
> +		cr >>= 4;
> +
> +		reg_val = adv7180_read(state, ADV7180_REG_DEF_VAL_Y);
> +		adv7180_write(state, ADV7180_REG_DEF_VAL_Y,
> +			(y << 2) | (reg_val & 0x03));
> +		adv7180_write(state, ADV7180_REG_DEF_VAL_C, (cr << 4) | cb);
> +		break;
> +	}
>  	default:
>  		ret = -EINVAL;
>  	}
> @@ -548,6 +608,53 @@ static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
>  	.step = 1,
>  };
>  
> +static const char * const adv7180_free_run_pattern_strings[] = {
> +	"Solid",
> +	"Bars",
> +	"Luma Ramp",
> +	"Reserved",
> +	"Reserved",
> +	"Boundary Box",
> +};
> +
> +static const char * const adv7180_free_run_mode_strings[] = {
> +	"Disabled",
> +	"Enabled",
> +	"Automatic",
> +};
> +
> +static const struct v4l2_ctrl_config adv7180_ctrl_free_run_color = {
> +	.ops = &adv7180_ctrl_ops,
> +	.id = V4L2_CID_ADV_FREE_RUN_COLOR,
> +	.name = "Free Running Color",
> +	.type = V4L2_CTRL_TYPE_INTEGER,
> +	.min = 0,
> +	.max = 0xffffff,
> +	.step = 0x1,
> +};
> +
> +static const struct v4l2_ctrl_config adv7180_ctrl_free_run_mode = {
> +	.ops = &adv7180_ctrl_ops,
> +	.id = V4L2_CID_ADV_FREE_RUN_MODE,
> +	.name = "Free Running Mode",
> +	.type = V4L2_CTRL_TYPE_MENU,
> +	.min = 0,
> +	.max = ARRAY_SIZE(adv7180_free_run_mode_strings) - 1,
> +	.def = 2,
> +	.qmenu = adv7180_free_run_mode_strings,
> +};

The adv7604 and adv7842 drivers have similar free-run controls. I am wondering
if these controls shouldn't be promoted to standard controls. Free-run support
is fairly common after all.

> +
> +static const struct v4l2_ctrl_config adv7180_ctrl_free_run_pattern = {
> +	.ops = &adv7180_ctrl_ops,
> +	.id = V4L2_CID_ADV_FREE_RUN_PATTERN,
> +	.name = "Free Running Pattern",
> +	.type = V4L2_CTRL_TYPE_MENU,
> +	.min = 0,
> +	.max = ARRAY_SIZE(adv7180_free_run_pattern_strings) - 1,
> +	.menu_skip_mask = 0x18, /* 0x3 and 0x4 are reserved */
> +	.qmenu = adv7180_free_run_pattern_strings,
> +};

Wouldn't it be better to use V4L2_CID_TEST_PATTERN for this?

> +
>  static int adv7180_init_controls(struct adv7180_state *state)
>  {
>  	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
> @@ -565,6 +672,12 @@ static int adv7180_init_controls(struct adv7180_state *state)
>  			  V4L2_CID_HUE, ADV7180_HUE_MIN,
>  			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
>  	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
> +	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_free_run_color,
> +		NULL);
> +	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_free_run_mode,
> +		NULL);
> +	v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_free_run_pattern,
> +		NULL);
>  
>  	state->sd.ctrl_handler = &state->ctrl_hdl;
>  	if (state->ctrl_hdl.error) {
> @@ -784,6 +897,9 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
>  {
>  	int ret;
>  
> +	if (input == ADV7180_INPUT_DISABLED)
> +		input = 0x00;
> +
>  	ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
>  	if (ret < 0)
>  		return ret;
> @@ -893,6 +1009,9 @@ static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
>  	unsigned int i;
>  	int ret;
>  
> +	if (input == ADV7180_INPUT_DISABLED)
> +		return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 0xff);
> +
>  	ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input);
>  	if (ret)
>  		return ret;
> 

Regards,

	Hans

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

end of thread, other threads:[~2015-01-16 10:20 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-13 12:01 [PATCH 00/16] [media] adv7180: Add support for different chip Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 01/16] [media] adv7180: Do not request the IRQ again during resume Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 02/16] [media] adv7180: Pass correct flags to request_threaded_irq() Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 03/16] [media] adv7180: Use inline function instead of macro Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 04/16] [media] adv7180: Cleanup register define naming Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 05/16] [media] adv7180: Do implicit register paging Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 06/16] [media] adv7180: Reset the device before initialization Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 07/16] [media] adv7180: Add media controller support Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 08/16] [media] adv7180: Consolidate video mode setting Lars-Peter Clausen
2015-01-16 10:12   ` Hans Verkuil
2015-01-13 12:01 ` [PATCH 09/16] [media] adv7180: Prepare for multi-chip support Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 10/16] [media] adv7180: Add support for the ad7182 Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 11/16] [media] adv7180: Add support for the adv7280/adv7281/adv7282 Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 12/16] [media] adv7180: Add support for the adv7280-m/adv7281-m/adv7281-ma/adv7282-m Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 13/16] [media] adv7180: Add I2P support Lars-Peter Clausen
2015-01-13 12:01 ` [PATCH 14/16] [media] adv7180: Add fast switch support Lars-Peter Clausen
2015-01-13 12:54   ` Hans Verkuil
2015-01-13 12:01 ` [PATCH 15/16] [media] adv7180: Add free run mode controls Lars-Peter Clausen
2015-01-16 10:20   ` Hans Verkuil
2015-01-13 12:01 ` [PATCH 16/16] [media] Add MAINTAINERS entry for the adv7180 Lars-Peter Clausen
2015-01-13 12:55   ` Mats Randgaard (matrandg)
2015-01-13 13:02     ` Lars-Peter Clausen
2015-01-13 13:04 ` [PATCH 00/16] [media] adv7180: Add support for different chip Hans Verkuil
2015-01-13 13:15   ` Lars-Peter Clausen

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