From 60794484c063805631e50b5a4fbc81538d51944e Mon Sep 17 00:00:00 2001
From: Markus Proeller <markus.proeller@pieye.org>
Date: Tue, 16 Jun 2020 13:33:56 +0200
Subject: [PATCH] media: irs1125: Keep HW in sync after imager reset

When closing the video device, the irs1125 is put in power down state.
To keep V4L2 ctrls and the HW in sync, v4l2_ctrl_handler_setup is
called after power up.

The compound ctrl IRS1125_CID_MOD_PLL however has a default value
of all zeros, which puts the imager into a non responding state.
Thus, this ctrl is not written by the driver into HW after power up.
The userspace has to take care to write senseful data.

Signed-off-by: Markus Proeller <markus.proeller@pieye.org>
---
 drivers/media/i2c/irs1125.c | 121 +++++++++++++++++-------------------
 1 file changed, 58 insertions(+), 63 deletions(-)

--- a/drivers/media/i2c/irs1125.c
+++ b/drivers/media/i2c/irs1125.c
@@ -82,6 +82,7 @@ struct irs1125 {
 	struct v4l2_ctrl *ctrl_numseq;
 
 	int power_count;
+	bool mod_pll_init;
 };
 
 static inline struct irs1125 *to_state(struct v4l2_subdev *sd)
@@ -276,8 +277,7 @@ static struct regval_list irs1125_seq_cf
 	{0xC039, 0x0000},
 	{0xC401, 0x0002},
 
-	{0xFFFF, 1},
-	{0xA87C, 0x0001}
+	{0xFFFF, 1}
 };
 
 static int irs1125_write(struct v4l2_subdev *sd, u16 reg, u16 val)
@@ -471,7 +471,11 @@ static int __sensor_init(struct v4l2_sub
 		return ret;
 	}
 
-	return 0;
+	irs1125->mod_pll_init = true;
+	v4l2_ctrl_handler_setup(&irs1125->ctrl_handler);
+	irs1125->mod_pll_init = false;
+
+	return irs1125_write(sd, 0xA87C, 0x0001);
 }
 
 static int irs1125_sensor_power(struct v4l2_subdev *sd, int on)
@@ -607,8 +611,6 @@ static int irs1125_s_ctrl(struct v4l2_ct
 	struct irs1125 *dev = container_of(ctrl->handler,
 					struct irs1125, ctrl_handler);
 	struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-	struct irs1125_mod_pll *mod_cur, *mod_new;
-	u16 addr, val;
 	int err = 0, i;
 
 	switch (ctrl->id) {
@@ -660,68 +662,61 @@ static int irs1125_s_ctrl(struct v4l2_ct
 				    ctrl->val);
 		break;
 	}
-	case IRS1125_CID_MOD_PLL:
+	case IRS1125_CID_MOD_PLL: {
+		struct irs1125_mod_pll *mod_new;
+
+		if (dev->mod_pll_init)
+			break;
+
 		mod_new = (struct irs1125_mod_pll *)ctrl->p_new.p;
-		mod_cur = (struct irs1125_mod_pll *)ctrl->p_cur.p;
 		for (i = 0; i < IRS1125_NUM_MOD_PLLS; i++) {
-			if (mod_cur[i].pllcfg1 != mod_new[i].pllcfg1) {
-				addr = 0xC3A0 + i * 3;
-				val = mod_new[i].pllcfg1;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
-			if (mod_cur[i].pllcfg2 != mod_new[i].pllcfg2) {
-				addr = 0xC3A1 + i * 3;
-				val = mod_new[i].pllcfg2;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
-			if (mod_cur[i].pllcfg3 != mod_new[i].pllcfg3) {
-				addr = 0xC3A2 + i * 3;
-				val = mod_new[i].pllcfg3;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
-			if (mod_cur[i].pllcfg4 != mod_new[i].pllcfg4) {
-				addr = 0xC24C + i * 5;
-				val = mod_new[i].pllcfg4;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
-			if (mod_cur[i].pllcfg5 != mod_new[i].pllcfg5) {
-				addr = 0xC24D + i * 5;
-				val = mod_new[i].pllcfg5;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
-			if (mod_cur[i].pllcfg6 != mod_new[i].pllcfg6) {
-				addr = 0xC24E + i * 5;
-				val = mod_new[i].pllcfg6;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
-			if (mod_cur[i].pllcfg7 != mod_new[i].pllcfg7) {
-				addr = 0xC24F + i * 5;
-				val = mod_new[i].pllcfg7;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
-			if (mod_cur[i].pllcfg8 != mod_new[i].pllcfg8) {
-				addr = 0xC250 + i * 5;
-				val = mod_new[i].pllcfg8;
-				err = irs1125_write(&dev->sd, addr, val);
-				if (err < 0)
-					break;
-			}
+			unsigned int pll_offset, ssc_offset;
+
+			pll_offset = i * 3;
+			ssc_offset = i * 5;
+
+			err = irs1125_write(&dev->sd, 0xC3A0 + pll_offset,
+					    mod_new[i].pllcfg1);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC3A1 + pll_offset,
+					    mod_new[i].pllcfg2);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC3A2 + pll_offset,
+					    mod_new[i].pllcfg3);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24C + ssc_offset,
+					    mod_new[i].pllcfg4);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24D + ssc_offset,
+					    mod_new[i].pllcfg5);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24E + ssc_offset,
+					    mod_new[i].pllcfg6);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC24F + ssc_offset,
+					    mod_new[i].pllcfg7);
+			if (err < 0)
+				break;
+
+			err = irs1125_write(&dev->sd, 0xC250 + ssc_offset,
+					    mod_new[i].pllcfg8);
+			if (err < 0)
+				break;
 		}
 		break;
+	}
 	case IRS1125_CID_SEQ_CONFIG: {
 		struct irs1125_seq_cfg *cfg_new;
 
