Hi,
This series has two main parts: 1) add error handling all around, and 2) update the drivers according to latest (mostly non-public) information from TI.
Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- Changes in v3: - Now that this series is closer to being merged, squash "Remove old ub9702 RX port init code (SQUASH)" and "Update UB9702 init sequences" as they were only split to ease review. - Drop SSCG bindings and driver changes. - Fix Sakari's minor review comments on "Speed-up I2C watchdog timer". - Link to v2: https://lore.kernel.org/r/20250124-ub9xx-improvements-v2-0-f7075c99ea20@idea...
--- Jai Luthra (4): media: i2c: ds90ub953: Speed-up I2C watchdog timer media: dt-bindings: ti,ds90ub960: Allow setting serializer address media: i2c: ds90ub960: Configure serializer using back-channel media: i2c: ds90ub9xx: Set serializer temperature ramp
Tomi Valkeinen (15): media: i2c: ds90ub953: Fix error prints media: i2c: ds90ub913: Fix returned fmt from .set_fmt() media: i2c: ds90ub913: Align ub913_read() with other similar functions media: i2c: ds90ub9xx: Add err parameter to read/write funcs media: i2c: ds90ub960: Add error handling to multiple places media: i2c: ds90ub953: Add error handling to ub953_log_status() media: i2c: ds90ub913: Add error handling to ub913_log_status() media: i2c: ds90ub960: Move UB9702 registers to a separate section media: i2c: ds90ub960: Add UB9702 specific registers media: i2c: ds90ub960: Split ub960_init_tx_ports() media: i2c: ds90ub960: Refresh ub960_init_tx_ports_ub9702() media: i2c: ds90ub960: Add RX port iteration support media: i2c: ds90ub960: Move all RX port init code into ub960_init_rx_ports() media: i2c: ds90ub960: Update UB9702 init sequences media: i2c: ds90ub953: Move reg defines to a header file
.../bindings/media/i2c/ti,ds90ub953.yaml | 77 +- .../bindings/media/i2c/ti,ds90ub960.yaml | 16 +- drivers/media/i2c/ds90ub913.c | 82 +- drivers/media/i2c/ds90ub953.c | 242 ++- drivers/media/i2c/ds90ub953.h | 104 + drivers/media/i2c/ds90ub960.c | 2166 +++++++++++++++----- 6 files changed, 1966 insertions(+), 721 deletions(-) --- base-commit: 2014c95afecee3e76ca4a56956a936e23283f05b change-id: 20250303-b4-ub9xx-err-handling-57a89508ea5e
Best regards,
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
ub953_read_ind() and ub953_write_ind() have broken error prints, and the register address is printed incorrectly. Fix the prints.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub953.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index 46569381b332de3dfd89a0720ada64cdfa3297de..7b33b8cc83c17fce7d3ce6bf73c2ec8bc13a0bfd 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -258,7 +258,7 @@ static int ub953_read_ind(struct ub953_data *priv, u8 block, u8 reg, u8 *val) ret = regmap_write(priv->regmap, UB953_REG_IND_ACC_ADDR, reg); if (ret) { dev_err(&priv->client->dev, - "Write to IND_ACC_ADDR failed when reading %u:%x02x: %d\n", + "Write to IND_ACC_ADDR failed when reading %u:0x%02x: %d\n", block, reg, ret); goto out_unlock; } @@ -266,7 +266,7 @@ static int ub953_read_ind(struct ub953_data *priv, u8 block, u8 reg, u8 *val) ret = regmap_read(priv->regmap, UB953_REG_IND_ACC_DATA, &v); if (ret) { dev_err(&priv->client->dev, - "Write to IND_ACC_DATA failed when reading %u:%x02x: %d\n", + "Write to IND_ACC_DATA failed when reading %u:0x%02x: %d\n", block, reg, ret); goto out_unlock; } @@ -293,7 +293,7 @@ static int ub953_write_ind(struct ub953_data *priv, u8 block, u8 reg, u8 val) ret = regmap_write(priv->regmap, UB953_REG_IND_ACC_ADDR, reg); if (ret) { dev_err(&priv->client->dev, - "Write to IND_ACC_ADDR failed when writing %u:%x02x: %d\n", + "Write to IND_ACC_ADDR failed when writing %u:0x%02x: %d\n", block, reg, ret); goto out_unlock; } @@ -301,7 +301,7 @@ static int ub953_write_ind(struct ub953_data *priv, u8 block, u8 reg, u8 val) ret = regmap_write(priv->regmap, UB953_REG_IND_ACC_DATA, val); if (ret) { dev_err(&priv->client->dev, - "Write to IND_ACC_DATA failed when writing %u:%x02x\n: %d\n", + "Write to IND_ACC_DATA failed when writing %u:0x%02x: %d\n", block, reg, ret); }
Hi,
Thanks for your patch.
FYI: kernel test robot notices the stable kernel rule is not satisfied.
The check is based on https://www.kernel.org/doc/html/latest/process/stable-kernel-rules.html#opti...
Rule: add the tag "Cc: stable@vger.kernel.org" in the sign-off area to have the patch automatically included in the stable tree. Subject: [PATCH v3 01/19] media: i2c: ds90ub953: Fix error prints Link: https://lore.kernel.org/stable/20250303-b4-ub9xx-err-handling-v3-1-7d178796a...
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
When setting the sink pad's stream format, set_fmt accidentally changes the returned format's code to 'outcode', while the purpose is to only use the 'outcode' for the propagated source stream format.
Fixes: c158d0d4ff15 ("media: i2c: add DS90UB913 driver") Cc: stable@vger.kernel.org Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub913.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index fd2d2d5272bfb688f00d7bf5a109e978f6c322e6..1445ebbcc9cabb3ab43a670aa165deea52db5f35 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -450,10 +450,10 @@ static int ub913_set_fmt(struct v4l2_subdev *sd, if (!fmt) return -EINVAL;
- format->format.code = finfo->outcode; - *fmt = format->format;
+ fmt->code = finfo->outcode; + return 0; }
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Adjust the ub913_read() to have similar form than the other similar functions in ub9xx drivers. This makes it easier to deal with all the read/write functions with a semantic patch.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub913.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index 1445ebbcc9cabb3ab43a670aa165deea52db5f35..facbee79164eec1fbccaea2c1d4d62cf439e49b6 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -125,14 +125,16 @@ static int ub913_read(const struct ub913_data *priv, u8 reg, u8 *val) int ret;
ret = regmap_read(priv->regmap, reg, &v); - if (ret < 0) { + if (ret) { dev_err(&priv->client->dev, "Cannot read register 0x%02x: %d!\n", reg, ret); - return ret; + goto out; }
*val = v; - return 0; + +out: + return ret; }
static int ub913_write(const struct ub913_data *priv, u8 reg, u8 val)
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
To make future error handling in the drivers easier, add "int *err" parameter to all the i2c register access functions. It functions the same was as with e.g. CCI reg write/read helpers.
This was accomplished with the following semantic patch:
@@ identifier FUNC =~ "^ub9.._(rxport_|txport_|ind_)?(read|write|update_bits)(16|_ind)?$"; @@ FUNC(... + , int *err ) { ... int ret; + + if (err && *err) + return *err;
...
+ if (ret && err) + *err = ret; + return ret; }
@@ identifier FUNC =~ "^ub9.._(rxport_|txport_|ind_)?(read|write|update_bits)(16|_ind)?$"; @@ FUNC(... + , NULL )
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub913.c | 52 +++-- drivers/media/i2c/ds90ub953.c | 94 +++++---- drivers/media/i2c/ds90ub960.c | 441 ++++++++++++++++++++++++++++-------------- 3 files changed, 390 insertions(+), 197 deletions(-)
diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index facbee79164eec1fbccaea2c1d4d62cf439e49b6..f38421d34d204fa9ab898d10c6b69942858bced2 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -119,11 +119,15 @@ static const struct ub913_format_info *ub913_find_format(u32 incode) return NULL; }
-static int ub913_read(const struct ub913_data *priv, u8 reg, u8 *val) +static int ub913_read(const struct ub913_data *priv, u8 reg, u8 *val, + int *err) { unsigned int v; int ret;
+ if (err && *err) + return *err; + ret = regmap_read(priv->regmap, reg, &v); if (ret) { dev_err(&priv->client->dev, @@ -134,31 +138,47 @@ static int ub913_read(const struct ub913_data *priv, u8 reg, u8 *val) *val = v;
out: + if (ret && err) + *err = ret; + return ret; }
-static int ub913_write(const struct ub913_data *priv, u8 reg, u8 val) +static int ub913_write(const struct ub913_data *priv, u8 reg, u8 val, + int *err) { int ret;
+ if (err && *err) + return *err; + ret = regmap_write(priv->regmap, reg, val); if (ret < 0) dev_err(&priv->client->dev, "Cannot write register 0x%02x: %d!\n", reg, ret);
+ if (ret && err) + *err = ret; + return ret; }
static int ub913_update_bits(const struct ub913_data *priv, u8 reg, u8 mask, - u8 val) + u8 val, int *err) { int ret;
+ if (err && *err) + return *err; + ret = regmap_update_bits(priv->regmap, reg, mask, val); if (ret < 0) dev_err(&priv->client->dev, "Cannot update register 0x%02x %d!\n", reg, ret);
+ if (ret && err) + *err = ret; + return ret; }
@@ -206,7 +226,7 @@ static int ub913_gpiochip_probe(struct ub913_data *priv) int ret;
/* Initialize GPIOs 0 and 1 to local control, tri-state */ - ub913_write(priv, UB913_REG_GPIO_CFG(0), 0); + ub913_write(priv, UB913_REG_GPIO_CFG(0), 0, NULL);
gc->label = dev_name(dev); gc->parent = dev; @@ -486,23 +506,23 @@ static int ub913_log_status(struct v4l2_subdev *sd) struct device *dev = &priv->client->dev; u8 v = 0, v1 = 0, v2 = 0;
- ub913_read(priv, UB913_REG_MODE_SEL, &v); + ub913_read(priv, UB913_REG_MODE_SEL, &v, NULL); dev_info(dev, "MODE_SEL %#02x\n", v);
- ub913_read(priv, UB913_REG_CRC_ERRORS_LSB, &v1); - ub913_read(priv, UB913_REG_CRC_ERRORS_MSB, &v2); + ub913_read(priv, UB913_REG_CRC_ERRORS_LSB, &v1, NULL); + ub913_read(priv, UB913_REG_CRC_ERRORS_MSB, &v2, NULL); dev_info(dev, "CRC errors %u\n", v1 | (v2 << 8));
/* clear CRC errors */ - ub913_read(priv, UB913_REG_GENERAL_CFG, &v); + ub913_read(priv, UB913_REG_GENERAL_CFG, &v, NULL); ub913_write(priv, UB913_REG_GENERAL_CFG, - v | UB913_REG_GENERAL_CFG_CRC_ERR_RESET); - ub913_write(priv, UB913_REG_GENERAL_CFG, v); + v | UB913_REG_GENERAL_CFG_CRC_ERR_RESET, NULL); + ub913_write(priv, UB913_REG_GENERAL_CFG, v, NULL);
- ub913_read(priv, UB913_REG_GENERAL_STATUS, &v); + ub913_read(priv, UB913_REG_GENERAL_STATUS, &v, NULL); dev_info(dev, "GENERAL_STATUS %#02x\n", v);
- ub913_read(priv, UB913_REG_PLL_OVR, &v); + ub913_read(priv, UB913_REG_PLL_OVR, &v, NULL); dev_info(dev, "PLL_OVR %#02x\n", v);
return 0; @@ -658,11 +678,11 @@ static int ub913_i2c_master_init(struct ub913_data *priv) scl_high = div64_u64((u64)scl_high * ref, 1000000000); scl_low = div64_u64((u64)scl_low * ref, 1000000000);
- ret = ub913_write(priv, UB913_REG_SCL_HIGH_TIME, scl_high); + ret = ub913_write(priv, UB913_REG_SCL_HIGH_TIME, scl_high, NULL); if (ret) return ret;
- ret = ub913_write(priv, UB913_REG_SCL_LOW_TIME, scl_low); + ret = ub913_write(priv, UB913_REG_SCL_LOW_TIME, scl_low, NULL); if (ret) return ret;
@@ -731,7 +751,7 @@ static int ub913_hw_init(struct ub913_data *priv) int ret; u8 v;
- ret = ub913_read(priv, UB913_REG_MODE_SEL, &v); + ret = ub913_read(priv, UB913_REG_MODE_SEL, &v, NULL); if (ret) return ret;
@@ -752,7 +772,7 @@ static int ub913_hw_init(struct ub913_data *priv) ret = ub913_update_bits(priv, UB913_REG_GENERAL_CFG, UB913_REG_GENERAL_CFG_PCLK_RISING, FIELD_PREP(UB913_REG_GENERAL_CFG_PCLK_RISING, - priv->pclk_polarity_rising)); + priv->pclk_polarity_rising), NULL);
if (ret) return ret; diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index 7b33b8cc83c17fce7d3ce6bf73c2ec8bc13a0bfd..fbd977760c6b1ccdec90b90bced4dc29932f3893 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -185,11 +185,14 @@ static inline struct ub953_data *sd_to_ub953(struct v4l2_subdev *sd) * HW Access */
-static int ub953_read(struct ub953_data *priv, u8 reg, u8 *val) +static int ub953_read(struct ub953_data *priv, u8 reg, u8 *val, int *err) { unsigned int v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = regmap_read(priv->regmap, reg, &v); @@ -204,13 +207,19 @@ static int ub953_read(struct ub953_data *priv, u8 reg, u8 *val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
-static int ub953_write(struct ub953_data *priv, u8 reg, u8 val) +static int ub953_write(struct ub953_data *priv, u8 reg, u8 val, int *err) { int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = regmap_write(priv->regmap, reg, val); @@ -220,6 +229,9 @@ static int ub953_write(struct ub953_data *priv, u8 reg, u8 val)
mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
@@ -244,11 +256,15 @@ static int ub953_select_ind_reg_block(struct ub953_data *priv, u8 block) }
__maybe_unused -static int ub953_read_ind(struct ub953_data *priv, u8 block, u8 reg, u8 *val) +static int ub953_read_ind(struct ub953_data *priv, u8 block, u8 reg, u8 *val, + int *err) { unsigned int v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub953_select_ind_reg_block(priv, block); @@ -276,14 +292,21 @@ static int ub953_read_ind(struct ub953_data *priv, u8 block, u8 reg, u8 *val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
__maybe_unused -static int ub953_write_ind(struct ub953_data *priv, u8 block, u8 reg, u8 val) +static int ub953_write_ind(struct ub953_data *priv, u8 block, u8 reg, u8 val, + int *err) { int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub953_select_ind_reg_block(priv, block); @@ -308,6 +331,9 @@ static int ub953_write_ind(struct ub953_data *priv, u8 block, u8 reg, u8 val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
@@ -320,7 +346,7 @@ static int ub953_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) int ret; u8 v;
- ret = ub953_read(priv, UB953_REG_GPIO_INPUT_CTRL, &v); + ret = ub953_read(priv, UB953_REG_GPIO_INPUT_CTRL, &v, NULL); if (ret) return ret;
@@ -366,7 +392,7 @@ static int ub953_gpio_get(struct gpio_chip *gc, unsigned int offset) int ret; u8 v;
- ret = ub953_read(priv, UB953_REG_GPIO_PIN_STS, &v); + ret = ub953_read(priv, UB953_REG_GPIO_PIN_STS, &v, NULL); if (ret) return ret;
@@ -400,11 +426,11 @@ static int ub953_gpiochip_probe(struct ub953_data *priv) int ret;
/* Set all GPIOs to local input mode */ - ret = ub953_write(priv, UB953_REG_LOCAL_GPIO_DATA, 0); + ret = ub953_write(priv, UB953_REG_LOCAL_GPIO_DATA, 0, NULL); if (ret) return ret;
- ret = ub953_write(priv, UB953_REG_GPIO_INPUT_CTRL, 0xf); + ret = ub953_write(priv, UB953_REG_GPIO_INPUT_CTRL, 0xf, NULL); if (ret) return ret;
@@ -615,15 +641,15 @@ static int ub953_log_status(struct v4l2_subdev *sd) u8 gpio_pin_sts = 0;
for (i = 0; i < sizeof(id); i++) - ub953_read(priv, UB953_REG_FPD3_RX_ID(i), &id[i]); + ub953_read(priv, UB953_REG_FPD3_RX_ID(i), &id[i], NULL);
dev_info(dev, "ID '%.*s'\n", (int)sizeof(id), id);
- ub953_read(priv, UB953_REG_GENERAL_STATUS, &v); + ub953_read(priv, UB953_REG_GENERAL_STATUS, &v, NULL); dev_info(dev, "GENERAL_STATUS %#02x\n", v);
- ub953_read(priv, UB953_REG_CRC_ERR_CNT1, &v1); - ub953_read(priv, UB953_REG_CRC_ERR_CNT2, &v2); + ub953_read(priv, UB953_REG_CRC_ERR_CNT1, &v1, NULL); + ub953_read(priv, UB953_REG_CRC_ERR_CNT2, &v2, NULL); dev_info(dev, "CRC error count %u\n", v1 | (v2 << 8));
/* Clear CRC error counter */ @@ -632,34 +658,34 @@ static int ub953_log_status(struct v4l2_subdev *sd) UB953_REG_BC_CTRL_CRC_ERR_CLR, UB953_REG_BC_CTRL_CRC_ERR_CLR);
- ub953_read(priv, UB953_REG_CSI_ERR_CNT, &v); + ub953_read(priv, UB953_REG_CSI_ERR_CNT, &v, NULL); dev_info(dev, "CSI error count %u\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_STATUS, &v); + ub953_read(priv, UB953_REG_CSI_ERR_STATUS, &v, NULL); dev_info(dev, "CSI_ERR_STATUS %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_DLANE01, &v); + ub953_read(priv, UB953_REG_CSI_ERR_DLANE01, &v, NULL); dev_info(dev, "CSI_ERR_DLANE01 %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_DLANE23, &v); + ub953_read(priv, UB953_REG_CSI_ERR_DLANE23, &v, NULL); dev_info(dev, "CSI_ERR_DLANE23 %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_CLK_LANE, &v); + ub953_read(priv, UB953_REG_CSI_ERR_CLK_LANE, &v, NULL); dev_info(dev, "CSI_ERR_CLK_LANE %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_PKT_HDR_VC_ID, &v); + ub953_read(priv, UB953_REG_CSI_PKT_HDR_VC_ID, &v, NULL); dev_info(dev, "CSI packet header VC %u ID %u\n", v >> 6, v & 0x3f);
- ub953_read(priv, UB953_REG_PKT_HDR_WC_LSB, &v1); - ub953_read(priv, UB953_REG_PKT_HDR_WC_MSB, &v2); + ub953_read(priv, UB953_REG_PKT_HDR_WC_LSB, &v1, NULL); + ub953_read(priv, UB953_REG_PKT_HDR_WC_MSB, &v2, NULL); dev_info(dev, "CSI packet header WC %u\n", (v2 << 8) | v1);
- ub953_read(priv, UB953_REG_CSI_ECC, &v); + ub953_read(priv, UB953_REG_CSI_ECC, &v, NULL); dev_info(dev, "CSI ECC %#02x\n", v);
- ub953_read(priv, UB953_REG_LOCAL_GPIO_DATA, &gpio_local_data); - ub953_read(priv, UB953_REG_GPIO_INPUT_CTRL, &gpio_input_ctrl); - ub953_read(priv, UB953_REG_GPIO_PIN_STS, &gpio_pin_sts); + ub953_read(priv, UB953_REG_LOCAL_GPIO_DATA, &gpio_local_data, NULL); + ub953_read(priv, UB953_REG_GPIO_INPUT_CTRL, &gpio_input_ctrl, NULL); + ub953_read(priv, UB953_REG_GPIO_PIN_STS, &gpio_pin_sts, NULL);
for (i = 0; i < UB953_NUM_GPIOS; i++) { dev_info(dev, @@ -843,11 +869,11 @@ static int ub953_i2c_master_init(struct ub953_data *priv) scl_high = div64_u64((u64)scl_high * ref, 1000000000) - 5; scl_low = div64_u64((u64)scl_low * ref, 1000000000) - 5;
- ret = ub953_write(priv, UB953_REG_SCL_HIGH_TIME, scl_high); + ret = ub953_write(priv, UB953_REG_SCL_HIGH_TIME, scl_high, NULL); if (ret) return ret;
- ret = ub953_write(priv, UB953_REG_SCL_LOW_TIME, scl_low); + ret = ub953_write(priv, UB953_REG_SCL_LOW_TIME, scl_low, NULL); if (ret) return ret;
@@ -986,11 +1012,11 @@ static int ub953_write_clkout_regs(struct ub953_data *priv,
clkout_ctrl1 = clkout_data->n;
- ret = ub953_write(priv, UB953_REG_CLKOUT_CTRL0, clkout_ctrl0); + ret = ub953_write(priv, UB953_REG_CLKOUT_CTRL0, clkout_ctrl0, NULL); if (ret) return ret;
- ret = ub953_write(priv, UB953_REG_CLKOUT_CTRL1, clkout_ctrl1); + ret = ub953_write(priv, UB953_REG_CLKOUT_CTRL1, clkout_ctrl1, NULL); if (ret) return ret;
@@ -1009,13 +1035,13 @@ static unsigned long ub953_clkout_recalc_rate(struct clk_hw *hw, u64 rate; int ret;
- ret = ub953_read(priv, UB953_REG_CLKOUT_CTRL0, &ctrl0); + ret = ub953_read(priv, UB953_REG_CLKOUT_CTRL0, &ctrl0, NULL); if (ret) { dev_err(dev, "Failed to read CLKOUT_CTRL0: %d\n", ret); return 0; }
- ret = ub953_read(priv, UB953_REG_CLKOUT_CTRL1, &ctrl1); + ret = ub953_read(priv, UB953_REG_CLKOUT_CTRL1, &ctrl1, NULL); if (ret) { dev_err(dev, "Failed to read CLKOUT_CTRL1: %d\n", ret); return 0; @@ -1191,7 +1217,7 @@ static int ub953_hw_init(struct ub953_data *priv) int ret; u8 v;
- ret = ub953_read(priv, UB953_REG_MODE_SEL, &v); + ret = ub953_read(priv, UB953_REG_MODE_SEL, &v, NULL); if (ret) return ret;
@@ -1231,13 +1257,13 @@ static int ub953_hw_init(struct ub953_data *priv) return dev_err_probe(dev, -EINVAL, "clkin required for non-sync ext mode\n");
- ret = ub953_read(priv, UB953_REG_REV_MASK_ID, &v); + ret = ub953_read(priv, UB953_REG_REV_MASK_ID, &v, NULL); if (ret) return dev_err_probe(dev, ret, "Failed to read revision");
dev_info(dev, "Found %s rev/mask %#04x\n", priv->hw_data->model, v);
- ret = ub953_read(priv, UB953_REG_GENERAL_CFG, &v); + ret = ub953_read(priv, UB953_REG_GENERAL_CFG, &v, NULL); if (ret) return ret;
@@ -1254,7 +1280,7 @@ static int ub953_hw_init(struct ub953_data *priv) UB953_REG_GENERAL_CFG_CSI_LANE_SEL_SHIFT; v |= UB953_REG_GENERAL_CFG_CRC_TX_GEN_ENABLE;
- ret = ub953_write(priv, UB953_REG_GENERAL_CFG, v); + ret = ub953_write(priv, UB953_REG_GENERAL_CFG, v, NULL); if (ret) return ret;
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 5dde8452739b64dd5b847a7bc1dac556ea43ca6c..09e6d820edc193f4db9c0ebf02bc89b384d75f5b 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -618,12 +618,15 @@ static const struct ub960_format_info *ub960_find_format(u32 code) * Basic device access */
-static int ub960_read(struct ub960_data *priv, u8 reg, u8 *val) +static int ub960_read(struct ub960_data *priv, u8 reg, u8 *val, int *err) { struct device *dev = &priv->client->dev; unsigned int v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = regmap_read(priv->regmap, reg, &v); @@ -638,14 +641,20 @@ static int ub960_read(struct ub960_data *priv, u8 reg, u8 *val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
-static int ub960_write(struct ub960_data *priv, u8 reg, u8 val) +static int ub960_write(struct ub960_data *priv, u8 reg, u8 val, int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = regmap_write(priv->regmap, reg, val); @@ -655,14 +664,21 @@ static int ub960_write(struct ub960_data *priv, u8 reg, u8 val)
mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
-static int ub960_update_bits(struct ub960_data *priv, u8 reg, u8 mask, u8 val) +static int ub960_update_bits(struct ub960_data *priv, u8 reg, u8 mask, u8 val, + int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = regmap_update_bits(priv->regmap, reg, mask, val); @@ -672,15 +688,21 @@ static int ub960_update_bits(struct ub960_data *priv, u8 reg, u8 mask, u8 val)
mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
-static int ub960_read16(struct ub960_data *priv, u8 reg, u16 *val) +static int ub960_read16(struct ub960_data *priv, u8 reg, u16 *val, int *err) { struct device *dev = &priv->client->dev; __be16 __v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = regmap_bulk_read(priv->regmap, reg, &__v, sizeof(__v)); @@ -695,6 +717,9 @@ static int ub960_read16(struct ub960_data *priv, u8 reg, u16 *val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
@@ -721,12 +746,16 @@ static int ub960_rxport_select(struct ub960_data *priv, u8 nport) return 0; }
-static int ub960_rxport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) +static int ub960_rxport_read(struct ub960_data *priv, u8 nport, u8 reg, + u8 *val, int *err) { struct device *dev = &priv->client->dev; unsigned int v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_rxport_select(priv, nport); @@ -745,14 +774,21 @@ static int ub960_rxport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
-static int ub960_rxport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) +static int ub960_rxport_write(struct ub960_data *priv, u8 nport, u8 reg, + u8 val, int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_rxport_select(priv, nport); @@ -767,15 +803,21 @@ static int ub960_rxport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
static int ub960_rxport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, - u8 mask, u8 val) + u8 mask, u8 val, int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_rxport_select(priv, nport); @@ -790,16 +832,22 @@ static int ub960_rxport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
static int ub960_rxport_read16(struct ub960_data *priv, u8 nport, u8 reg, - u16 *val) + u16 *val, int *err) { struct device *dev = &priv->client->dev; __be16 __v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_rxport_select(priv, nport); @@ -818,6 +866,9 @@ static int ub960_rxport_read16(struct ub960_data *priv, u8 nport, u8 reg, out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
@@ -844,12 +895,16 @@ static int ub960_txport_select(struct ub960_data *priv, u8 nport) return 0; }
-static int ub960_txport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) +static int ub960_txport_read(struct ub960_data *priv, u8 nport, u8 reg, + u8 *val, int *err) { struct device *dev = &priv->client->dev; unsigned int v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_txport_select(priv, nport); @@ -868,14 +923,21 @@ static int ub960_txport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
-static int ub960_txport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) +static int ub960_txport_write(struct ub960_data *priv, u8 nport, u8 reg, + u8 val, int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_txport_select(priv, nport); @@ -890,15 +952,21 @@ static int ub960_txport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
static int ub960_txport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, - u8 mask, u8 val) + u8 mask, u8 val, int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_txport_select(priv, nport); @@ -913,6 +981,9 @@ static int ub960_txport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
@@ -938,12 +1009,16 @@ static int ub960_select_ind_reg_block(struct ub960_data *priv, u8 block) return 0; }
-static int ub960_read_ind(struct ub960_data *priv, u8 block, u8 reg, u8 *val) +static int ub960_read_ind(struct ub960_data *priv, u8 block, u8 reg, u8 *val, + int *err) { struct device *dev = &priv->client->dev; unsigned int v; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_select_ind_reg_block(priv, block); @@ -971,14 +1046,21 @@ static int ub960_read_ind(struct ub960_data *priv, u8 block, u8 reg, u8 *val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
-static int ub960_write_ind(struct ub960_data *priv, u8 block, u8 reg, u8 val) +static int ub960_write_ind(struct ub960_data *priv, u8 block, u8 reg, u8 val, + int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_select_ind_reg_block(priv, block); @@ -1004,15 +1086,21 @@ static int ub960_write_ind(struct ub960_data *priv, u8 block, u8 reg, u8 val) out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
static int ub960_ind_update_bits(struct ub960_data *priv, u8 block, u8 reg, - u8 mask, u8 val) + u8 mask, u8 val, int *err) { struct device *dev = &priv->client->dev; int ret;
+ if (err && *err) + return *err; + mutex_lock(&priv->reg_lock);
ret = ub960_select_ind_reg_block(priv, block); @@ -1039,6 +1127,9 @@ static int ub960_ind_update_bits(struct ub960_data *priv, u8 block, u8 reg, out_unlock: mutex_unlock(&priv->reg_lock);
+ if (ret && err) + *err = ret; + return ret; }
@@ -1067,9 +1158,9 @@ static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, rxport->aliased_clients[reg_idx] = client;
ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ID(reg_idx), - client->addr << 1); + client->addr << 1, NULL); ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), - alias << 1); + alias << 1, NULL);
dev_dbg(dev, "rx%u: client 0x%02x assigned alias 0x%02x at slot %u\n", rxport->nport, client->addr, alias, reg_idx); @@ -1098,7 +1189,8 @@ static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id,
rxport->aliased_clients[reg_idx] = NULL;
- ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 0); + ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 0, + NULL);
dev_dbg(dev, "rx%u: client 0x%02x released at slot %u\n", rxport->nport, client->addr, reg_idx); @@ -1199,7 +1291,8 @@ static void ub960_csi_handle_events(struct ub960_data *priv, u8 nport) u8 csi_tx_isr; int ret;
- ret = ub960_txport_read(priv, nport, UB960_TR_CSI_TX_ISR, &csi_tx_isr); + ret = ub960_txport_read(priv, nport, UB960_TR_CSI_TX_ISR, &csi_tx_isr, + NULL); if (ret) return;
@@ -1264,15 +1357,15 @@ static void ub960_rxport_clear_errors(struct ub960_data *priv, { u8 v;
- ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v); - ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v); - ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &v); - ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &v); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v, NULL); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v, NULL); + ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &v, NULL); + ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &v, NULL);
- ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v); - ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_LO, &v); + ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v, NULL); + ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_LO, &v, NULL);
- ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v); + ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v, NULL); }
static void ub960_clear_rx_errors(struct ub960_data *priv) @@ -1291,24 +1384,24 @@ static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, int ret;
ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_CLK, &v); + UB960_IR_RX_ANA_STROBE_SET_CLK, &v, NULL);
clk_delay = (v & UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY) ? 0 : UB960_MANUAL_STROBE_EXTRA_DELAY;
ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_DATA, &v); + UB960_IR_RX_ANA_STROBE_SET_DATA, &v, NULL);
data_delay = (v & UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY) ? 0 : UB960_MANUAL_STROBE_EXTRA_DELAY;
- ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_0, &v); + ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_0, &v, NULL); if (ret) return ret;
clk_delay += v & UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK;
- ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v); + ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v, NULL); if (ret) return ret;
@@ -1337,10 +1430,10 @@ static void ub960_rxport_set_strobe_pos(struct ub960_data *priv, data_delay = strobe_pos | UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY;
ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_CLK, clk_delay); + UB960_IR_RX_ANA_STROBE_SET_CLK, clk_delay, NULL);
ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_DATA, data_delay); + UB960_IR_RX_ANA_STROBE_SET_DATA, data_delay, NULL); }
static void ub960_rxport_set_strobe_range(struct ub960_data *priv, @@ -1352,7 +1445,8 @@ static void ub960_rxport_set_strobe_range(struct ub960_data *priv,
ub960_write(priv, UB960_XR_SFILTER_CFG, ((u8)strobe_min << UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) | - ((u8)strobe_max << UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT)); + ((u8)strobe_max << UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT), + NULL); }
static int ub960_rxport_get_eq_level(struct ub960_data *priv, @@ -1361,7 +1455,7 @@ static int ub960_rxport_get_eq_level(struct ub960_data *priv, int ret; u8 v;
- ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_STATUS, &v); + ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_STATUS, &v, NULL); if (ret) return ret;
@@ -1386,7 +1480,7 @@ static void ub960_rxport_set_eq_level(struct ub960_data *priv, eq_stage_2_select_value = eq_level - eq_stage_max; }
- ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v); + ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v, NULL);
v &= ~(UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_MASK | UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_MASK); @@ -1394,7 +1488,7 @@ static void ub960_rxport_set_eq_level(struct ub960_data *priv, v |= eq_stage_2_select_value << UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_SHIFT; v |= UB960_RR_AEQ_BYPASS_ENABLE;
- ub960_rxport_write(priv, nport, UB960_RR_AEQ_BYPASS, v); + ub960_rxport_write(priv, nport, UB960_RR_AEQ_BYPASS, v, NULL); }
static void ub960_rxport_set_eq_range(struct ub960_data *priv, @@ -1402,12 +1496,13 @@ static void ub960_rxport_set_eq_range(struct ub960_data *priv, { ub960_rxport_write(priv, nport, UB960_RR_AEQ_MIN_MAX, (eq_min << UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT) | - (eq_max << UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT)); + (eq_max << UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT), + NULL);
/* Enable AEQ min setting */ ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_CTL2, UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR, - UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR); + UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR, NULL); }
static void ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport) @@ -1419,12 +1514,12 @@ static void ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport) if (priv->strobe.manual) { /* Disable AEQ_SFILTER_EN */ ub960_update_bits(priv, UB960_XR_AEQ_CTL1, - UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, 0); + UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, 0, NULL); } else { /* Enable SFILTER and error control */ ub960_write(priv, UB960_XR_AEQ_CTL1, UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_MASK | - UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN); + UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, NULL);
/* Set AEQ strobe range */ ub960_rxport_set_strobe_range(priv, priv->strobe.min, @@ -1445,7 +1540,7 @@ static void ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport) /* Enable AEQ Bypass */ ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, UB960_RR_AEQ_BYPASS_ENABLE, - UB960_RR_AEQ_BYPASS_ENABLE); + UB960_RR_AEQ_BYPASS_ENABLE, NULL); } else { ub960_rxport_set_eq_range(priv, nport, rxport->eq.aeq.eq_level_min, @@ -1453,7 +1548,7 @@ static void ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport)
/* Disable AEQ Bypass */ ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, - UB960_RR_AEQ_BYPASS_ENABLE, 0); + UB960_RR_AEQ_BYPASS_ENABLE, 0, NULL); } }
@@ -1469,7 +1564,7 @@ static int ub960_rxport_link_ok(struct ub960_data *priv, unsigned int nport, bool errors;
ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, - &rx_port_sts1); + &rx_port_sts1, NULL); if (ret) return ret;
@@ -1479,25 +1574,27 @@ static int ub960_rxport_link_ok(struct ub960_data *priv, unsigned int nport, }
ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, - &rx_port_sts2); + &rx_port_sts2, NULL); if (ret) return ret;
- ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &csi_rx_sts); + ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &csi_rx_sts, + NULL); if (ret) return ret;
ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, - &csi_err_cnt); + &csi_err_cnt, NULL); if (ret) return ret;
- ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &bcc_sts); + ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &bcc_sts, + NULL); if (ret) return ret;
ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, - &parity_errors); + &parity_errors, NULL); if (ret) return ret;
@@ -1600,7 +1697,8 @@ static int ub960_rxport_wait_locks(struct ub960_data *priv, continue; }
- ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v); + ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v, + NULL);
if (priv->hw_data->is_ub9702) { dev_dbg(dev, "\trx%u: locked, freq %llu Hz\n", @@ -1787,7 +1885,7 @@ static void ub960_init_tx_port(struct ub960_data *priv, if (!txport->non_continous_clk) csi_ctl |= UB960_TR_CSI_CTL_CSI_CONTS_CLOCK;
- ub960_txport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl); + ub960_txport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl, NULL); }
static int ub960_init_tx_ports(struct ub960_data *priv) @@ -1818,24 +1916,30 @@ static int ub960_init_tx_ports(struct ub960_data *priv) break; }
- ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select); + ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select, NULL);
if (priv->hw_data->is_ub9702) { - ub960_write(priv, UB960_SR_CSI_PLL_DIV, pll_div); + ub960_write(priv, UB960_SR_CSI_PLL_DIV, pll_div, NULL);
switch (priv->tx_data_rate) { case MHZ(1600): default: - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x80); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, + 0x80, NULL); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, + 0x2a, NULL); break; case MHZ(800): - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x90); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, 0x2a); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, + 0x90, NULL); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, + 0x2a, NULL); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, + 0x2a, NULL); break; case MHZ(400): - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0xa0); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, + 0xa0, NULL); break; } } @@ -1890,21 +1994,22 @@ static void ub960_init_rx_port_ub960(struct ub960_data *priv,
ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, - bc_freq_val); + bc_freq_val, NULL);
switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: /* FPD3_MODE = RAW10 Mode (DS90UB913A-Q1 / DS90UB933-Q1 compatible) */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, UB960_RR_PORT_CONFIG_FPD3_MODE_MASK, - 0x3); + 0x3, NULL);
/* * RAW10_8BIT_CTL = 0b10 : 8-bit processing using upper 8 bits */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_MASK, - 0x2 << UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_SHIFT); + 0x2 << UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_SHIFT, + NULL);
break;
@@ -1917,33 +2022,34 @@ static void ub960_init_rx_port_ub960(struct ub960_data *priv, case RXPORT_MODE_CSI2_NONSYNC: /* CSI-2 Mode (DS90UB953-Q1 compatible) */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, 0x3, - 0x0); + 0x0, NULL);
break; }
/* LV_POLARITY & FV_POLARITY */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, - rxport->lv_fv_pol); + rxport->lv_fv_pol, NULL);
/* Enable all interrupt sources from this port */ - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07); - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07, NULL); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f, NULL);
/* Enable I2C_PASS_THROUGH */ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, - UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH); + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, NULL);
/* Enable I2C communication to the serializer via the alias addr */ ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, - rxport->ser.alias << 1); + rxport->ser.alias << 1, NULL);
/* Configure EQ related settings */ ub960_rxport_config_eq(priv, nport);
/* Enable RX port */ - ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport)); + ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), + NULL); }
static void ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, @@ -1984,31 +2090,36 @@ static void ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, }
ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, - bc_freq_val); - ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, fpd_func_mode); + bc_freq_val, NULL); + ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, fpd_func_mode, + NULL);
/* set serdes_eq_mode = 1 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa8, 0x80); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa8, 0x80, + NULL);
/* enable serdes driver */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x0d, 0x7f); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x0d, 0x7f, + NULL);
/* set serdes_eq_offset=4 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04, + NULL);
/* init default serdes_eq_max in 0xa9 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa9, 0x23); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa9, 0x23, + NULL);
/* init serdes_eq_min in 0xaa */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xaa, 0); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xaa, 0, NULL);
/* serdes_driver_ctl2 control: DS90UB953-Q1/DS90UB933-Q1/DS90UB913A-Q1 */ ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, - BIT(3), BIT(3)); + BIT(3), BIT(3), NULL);
/* RX port to half-rate */ ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), - BIT(nport * 2)); + BIT(nport * 2), NULL); }
static void ub960_init_rx_port_ub9702_fpd4_aeq(struct ub960_data *priv, @@ -2021,28 +2132,37 @@ static void ub960_init_rx_port_ub9702_fpd4_aeq(struct ub960_data *priv, u8 v;
/* AEQ init */ - ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2c, &v); + ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2c, &v, + NULL);
- ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, v); - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, v + 1); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, v, + NULL); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, + v + 1, NULL);
- ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x00); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, + 0x00, NULL); }
/* enable serdes_eq_ctl2 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x9e, 0x00); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x9e, 0x00, + NULL);
/* enable serdes_eq_ctl1 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x90, 0x40); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x90, 0x40, + NULL);
/* enable serdes_eq_en */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2e, 0x40); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2e, 0x40, + NULL);
/* disable serdes_eq_override */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xf0, 0x00); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xf0, 0x00, + NULL);
/* disable serdes_gain_override */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x71, 0x00); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x71, 0x00, + NULL); }
static void ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, @@ -2077,32 +2197,38 @@ static void ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, }
ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, - bc_freq_val); + bc_freq_val, NULL);
/* FPD4 Sync Mode */ - ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, 0); + ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, 0, NULL);
/* add serdes_eq_offset of 4 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04, + NULL);
/* FPD4 serdes_start_eq in 0x27: assign default */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, 0x0); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, 0x0, NULL); /* FPD4 serdes_end_eq in 0x28: assign default */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, 0x23); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, 0x23, + NULL);
/* set serdes_driver_mode into FPD IV mode */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x04, 0x00); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x04, 0x00, + NULL); /* set FPD PBC drv into FPD IV mode */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, 0x00); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, 0x00, + NULL);
/* set serdes_system_init to 0x2f */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x21, 0x2f); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x21, 0x2f, + NULL); /* set serdes_system_rst in reset mode */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0xc1); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0xc1, + NULL);
/* RX port to 7.55G mode */ ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), - 0 << (nport * 2)); + 0 << (nport * 2), NULL);
ub960_init_rx_port_ub9702_fpd4_aeq(priv, rxport); } @@ -2124,7 +2250,7 @@ static void ub960_init_rx_port_ub9702(struct ub960_data *priv, * 0b10 : 8-bit processing using upper 8 bits */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, - 0x3 << 6, 0x2 << 6); + 0x3 << 6, 0x2 << 6, NULL);
break;
@@ -2141,27 +2267,29 @@ static void ub960_init_rx_port_ub9702(struct ub960_data *priv,
/* LV_POLARITY & FV_POLARITY */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, - rxport->lv_fv_pol); + rxport->lv_fv_pol, NULL);
/* Enable all interrupt sources from this port */ - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07); - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07, NULL); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f, NULL);
/* Enable I2C_PASS_THROUGH */ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, - UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH); + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, NULL);
/* Enable I2C communication to the serializer via the alias addr */ ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, - rxport->ser.alias << 1); + rxport->ser.alias << 1, NULL);
/* Enable RX port */ - ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport)); + ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), + NULL);
if (rxport->cdr_mode == RXPORT_CDR_FPD4) { /* unreset 960 AEQ */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0x41); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, + 0x41, NULL); } }
@@ -2196,16 +2324,16 @@ static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) /* Read interrupts (also clears most of them) */ if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, - &rx_port_sts1); + &rx_port_sts1, NULL); if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, - &rx_port_sts2); + &rx_port_sts2, NULL); if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, - &csi_rx_sts); + &csi_rx_sts, NULL); if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, - &bcc_sts); + &bcc_sts, NULL);
if (ret) return; @@ -2214,7 +2342,7 @@ static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) u16 v;
ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, - &v); + &v, NULL); if (!ret) dev_err(dev, "rx%u parity errors: %u\n", nport, v); } @@ -2273,7 +2401,8 @@ static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_LINE_LEN_CHG) { u16 v;
- ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v); + ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, + &v, NULL); if (!ret) dev_dbg(dev, "rx%u line len changed: %u\n", nport, v); } @@ -2282,7 +2411,7 @@ static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) u16 v;
ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, - &v); + &v, NULL); if (!ret) dev_dbg(dev, "rx%u line count changed: %u\n", nport, v); } @@ -2354,7 +2483,7 @@ static int ub960_enable_tx_port(struct ub960_data *priv, unsigned int nport)
return ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, UB960_TR_CSI_CTL_CSI_ENABLE, - UB960_TR_CSI_CTL_CSI_ENABLE); + UB960_TR_CSI_CTL_CSI_ENABLE, NULL); }
static void ub960_disable_tx_port(struct ub960_data *priv, unsigned int nport) @@ -2364,7 +2493,7 @@ static void ub960_disable_tx_port(struct ub960_data *priv, unsigned int nport) dev_dbg(dev, "disable TX port %u\n", nport);
ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, - UB960_TR_CSI_CTL_CSI_ENABLE, 0); + UB960_TR_CSI_CTL_CSI_ENABLE, 0, NULL); }
static int ub960_enable_rx_port(struct ub960_data *priv, unsigned int nport) @@ -2375,7 +2504,7 @@ static int ub960_enable_rx_port(struct ub960_data *priv, unsigned int nport)
/* Enable forwarding */ return ub960_update_bits(priv, UB960_SR_FWD_CTL1, - UB960_SR_FWD_CTL1_PORT_DIS(nport), 0); + UB960_SR_FWD_CTL1_PORT_DIS(nport), 0, NULL); }
static void ub960_disable_rx_port(struct ub960_data *priv, unsigned int nport) @@ -2387,7 +2516,7 @@ static void ub960_disable_rx_port(struct ub960_data *priv, unsigned int nport) /* Disable forwarding */ ub960_update_bits(priv, UB960_SR_FWD_CTL1, UB960_SR_FWD_CTL1_PORT_DIS(nport), - UB960_SR_FWD_CTL1_PORT_DIS(nport)); + UB960_SR_FWD_CTL1_PORT_DIS(nport), NULL); }
/* @@ -2528,12 +2657,13 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: ub960_rxport_write(priv, nport, UB960_RR_RAW10_ID, - rx_data[nport].pixel_dt | (vc << UB960_RR_RAW10_ID_VC_SHIFT)); + rx_data[nport].pixel_dt | (vc << UB960_RR_RAW10_ID_VC_SHIFT), + NULL);
ub960_rxport_write(priv, rxport->nport, UB960_RR_RAW_EMBED_DTYPE, (rx_data[nport].meta_lines << UB960_RR_RAW_EMBED_DTYPE_LINES_SHIFT) | - rx_data[nport].meta_dt); + rx_data[nport].meta_dt, NULL);
break;
@@ -2550,7 +2680,8 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, (vc << UB960_RR_CSI_VC_MAP_SHIFT(3)) | (vc << UB960_RR_CSI_VC_MAP_SHIFT(2)) | (vc << UB960_RR_CSI_VC_MAP_SHIFT(1)) | - (vc << UB960_RR_CSI_VC_MAP_SHIFT(0))); + (vc << UB960_RR_CSI_VC_MAP_SHIFT(0)), + NULL); } else { unsigned int i;
@@ -2558,7 +2689,8 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, for (i = 0; i < 8; i++) ub960_rxport_write(priv, nport, UB960_RR_VC_ID_MAP(i), - (nport << 4) | nport); + (nport << 4) | nport, + NULL); }
break; @@ -2570,7 +2702,7 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, fwd_ctl &= ~BIT(nport); /* forward to TX0 */ }
- ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl); + ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl, NULL);
return 0; } @@ -2986,7 +3118,7 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv,
/* Strobe */
- ret = ub960_read(priv, UB960_XR_AEQ_CTL1, &v); + ret = ub960_read(priv, UB960_XR_AEQ_CTL1, &v, NULL); if (ret) return;
@@ -2995,7 +3127,7 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv, "Manual");
if (v & UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN) { - ret = ub960_read(priv, UB960_XR_SFILTER_CFG, &v); + ret = ub960_read(priv, UB960_XR_SFILTER_CFG, &v, NULL); if (ret) return;
@@ -3012,7 +3144,7 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv,
/* EQ */
- ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v); + ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v, NULL); if (ret) return;
@@ -3021,7 +3153,8 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv, "Adaptive");
if (!(v & UB960_RR_AEQ_BYPASS_ENABLE)) { - ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_MIN_MAX, &v); + ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_MIN_MAX, &v, + NULL); if (ret) return;
@@ -3047,7 +3180,7 @@ static int ub960_log_status(struct v4l2_subdev *sd) state = v4l2_subdev_lock_and_get_active_state(sd);
for (unsigned int i = 0; i < sizeof(id); i++) - ub960_read(priv, UB960_SR_FPD3_RX_ID(i), &id[i]); + ub960_read(priv, UB960_SR_FPD3_RX_ID(i), &id[i], NULL);
dev_info(dev, "ID '%.*s'\n", (int)sizeof(id), id);
@@ -3061,20 +3194,24 @@ static int ub960_log_status(struct v4l2_subdev *sd) continue; }
- ub960_txport_read(priv, nport, UB960_TR_CSI_STS, &v); + ub960_txport_read(priv, nport, UB960_TR_CSI_STS, &v, NULL); dev_info(dev, "\tsync %u, pass %u\n", v & (u8)BIT(1), v & (u8)BIT(0));
- ub960_read16(priv, UB960_SR_CSI_FRAME_COUNT_HI(nport), &v16); + ub960_read16(priv, UB960_SR_CSI_FRAME_COUNT_HI(nport), &v16, + NULL); dev_info(dev, "\tframe counter %u\n", v16);
- ub960_read16(priv, UB960_SR_CSI_FRAME_ERR_COUNT_HI(nport), &v16); + ub960_read16(priv, UB960_SR_CSI_FRAME_ERR_COUNT_HI(nport), + &v16, NULL); dev_info(dev, "\tframe error counter %u\n", v16);
- ub960_read16(priv, UB960_SR_CSI_LINE_COUNT_HI(nport), &v16); + ub960_read16(priv, UB960_SR_CSI_LINE_COUNT_HI(nport), &v16, + NULL); dev_info(dev, "\tline counter %u\n", v16);
- ub960_read16(priv, UB960_SR_CSI_LINE_ERR_COUNT_HI(nport), &v16); + ub960_read16(priv, UB960_SR_CSI_LINE_ERR_COUNT_HI(nport), + &v16, NULL); dev_info(dev, "\tline error counter %u\n", v16); }
@@ -3088,7 +3225,8 @@ static int ub960_log_status(struct v4l2_subdev *sd) continue; }
- ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v, + NULL);
if (v & UB960_RR_RX_PORT_STS1_LOCK_STS) dev_info(dev, "\tLocked\n"); @@ -3096,22 +3234,28 @@ static int ub960_log_status(struct v4l2_subdev *sd) dev_info(dev, "\tNot locked\n");
dev_info(dev, "\trx_port_sts1 %#02x\n", v); - ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v, + NULL); dev_info(dev, "\trx_port_sts2 %#02x\n", v);
- ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v16); + ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v16, + NULL); dev_info(dev, "\tlink freq %llu Hz\n", ((u64)v16 * HZ_PER_MHZ) >> 8);
- ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v16); + ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v16, + NULL); dev_info(dev, "\tparity errors %u\n", v16);
- ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, &v16); + ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, &v16, + NULL); dev_info(dev, "\tlines per frame %u\n", v16);
- ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v16); + ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v16, + NULL); dev_info(dev, "\tbytes per line %u\n", v16);
- ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v); + ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v, + NULL); dev_info(dev, "\tcsi_err_counter %u\n", v);
if (!priv->hw_data->is_ub9702) @@ -3125,7 +3269,7 @@ static int ub960_log_status(struct v4l2_subdev *sd) ctl_reg = UB960_RR_BC_GPIO_CTL(i / 2); ctl_shift = (i % 2) * 4;
- ub960_rxport_read(priv, nport, ctl_reg, &v); + ub960_rxport_read(priv, nport, ctl_reg, &v, NULL);
dev_info(dev, "\tGPIO%u: mode %u\n", i, (v >> ctl_shift) & 0xf); @@ -3168,13 +3312,13 @@ static irqreturn_t ub960_handle_events(int irq, void *arg) u8 fwd_sts; int ret;
- ret = ub960_read(priv, UB960_SR_INTERRUPT_STS, &int_sts); + ret = ub960_read(priv, UB960_SR_INTERRUPT_STS, &int_sts, NULL); if (ret || !int_sts) return IRQ_NONE;
dev_dbg(&priv->client->dev, "INTERRUPT_STS %x\n", int_sts);
- ret = ub960_read(priv, UB960_SR_FWD_STS, &fwd_sts); + ret = ub960_read(priv, UB960_SR_FWD_STS, &fwd_sts, NULL); if (ret) return IRQ_NONE;
@@ -3804,7 +3948,7 @@ static void ub960_reset(struct ub960_data *priv, bool reset_regs) bit = reset_regs ? UB960_SR_RESET_DIGITAL_RESET1 : UB960_SR_RESET_DIGITAL_RESET0;
- ub960_write(priv, UB960_SR_RESET, bit); + ub960_write(priv, UB960_SR_RESET, bit, NULL);
mutex_lock(&priv->reg_lock);
@@ -3876,7 +4020,7 @@ static int ub960_enable_core_hw(struct ub960_data *priv) ub960_reset(priv, true);
/* Runtime check register accessibility */ - ret = ub960_read(priv, UB960_SR_REV_MASK, &rev_mask); + ret = ub960_read(priv, UB960_SR_REV_MASK, &rev_mask, NULL); if (ret) { dev_err_probe(dev, ret, "Cannot read first register, abort\n"); goto err_pd_gpio; @@ -3885,14 +4029,16 @@ static int ub960_enable_core_hw(struct ub960_data *priv) dev_dbg(dev, "Found %s (rev/mask %#04x)\n", priv->hw_data->model, rev_mask);
- ret = ub960_read(priv, UB960_SR_DEVICE_STS, &dev_sts); + ret = ub960_read(priv, UB960_SR_DEVICE_STS, &dev_sts, NULL); if (ret) goto err_pd_gpio;
if (priv->hw_data->is_ub9702) - ret = ub960_read(priv, UB9702_SR_REFCLK_FREQ, &refclk_freq); + ret = ub960_read(priv, UB9702_SR_REFCLK_FREQ, &refclk_freq, + NULL); else - ret = ub960_read(priv, UB960_XR_REFCLK_FREQ, &refclk_freq); + ret = ub960_read(priv, UB960_XR_REFCLK_FREQ, &refclk_freq, + NULL); if (ret) goto err_pd_gpio;
@@ -3901,7 +4047,7 @@ static int ub960_enable_core_hw(struct ub960_data *priv) clk_get_rate(priv->refclk) / HZ_PER_MHZ);
/* Disable all RX ports by default */ - ret = ub960_write(priv, UB960_SR_RX_PORT_CTL, 0); + ret = ub960_write(priv, UB960_SR_RX_PORT_CTL, 0, NULL); if (ret) goto err_pd_gpio;
@@ -3909,7 +4055,8 @@ static int ub960_enable_core_hw(struct ub960_data *priv) if (priv->hw_data->is_ub9702) { ret = ub960_update_bits(priv, UB960_SR_RESET, UB960_SR_RESET_GPIO_LOCK_RELEASE, - UB960_SR_RESET_GPIO_LOCK_RELEASE); + UB960_SR_RESET_GPIO_LOCK_RELEASE, + NULL); if (ret) goto err_pd_gpio; } @@ -4035,7 +4182,7 @@ static int ub960_probe(struct i2c_client *client) #ifdef UB960_DEBUG_I2C_RX_ID for (unsigned int i = 0; i < priv->hw_data->num_rxports; i++) ub960_write(priv, UB960_SR_I2C_RX_ID(i), - (UB960_DEBUG_I2C_RX_ID + i) << 1); + (UB960_DEBUG_I2C_RX_ID + i) << 1, NULL); #endif
return 0;
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
The driver is missing checks for i2c read/write errors in many places. Now that we have added the err parameter to the read/write functions in the previous patch, add error handling to all the missing places.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub960.c | 589 +++++++++++++++++++++++++++--------------- 1 file changed, 376 insertions(+), 213 deletions(-)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 09e6d820edc193f4db9c0ebf02bc89b384d75f5b..086aa8cc78fa4e4e9ccc08589cbaf1cc06104786 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -1144,6 +1144,7 @@ static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, struct ub960_rxport *rxport = priv->rxports[chan_id]; struct device *dev = &priv->client->dev; unsigned int reg_idx; + int ret = 0;
for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { if (!rxport->aliased_clients[reg_idx]) @@ -1158,9 +1159,12 @@ static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, rxport->aliased_clients[reg_idx] = client;
ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ID(reg_idx), - client->addr << 1, NULL); + client->addr << 1, &ret); ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), - alias << 1, NULL); + alias << 1, &ret); + + if (ret) + return ret;
dev_dbg(dev, "rx%u: client 0x%02x assigned alias 0x%02x at slot %u\n", rxport->nport, client->addr, alias, reg_idx); @@ -1175,6 +1179,7 @@ static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id, struct ub960_rxport *rxport = priv->rxports[chan_id]; struct device *dev = &priv->client->dev; unsigned int reg_idx; + int ret;
for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { if (rxport->aliased_clients[reg_idx] == client) @@ -1189,8 +1194,13 @@ static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id,
rxport->aliased_clients[reg_idx] = NULL;
- ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 0, - NULL); + ret = ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), + 0, NULL); + if (ret) { + dev_err(dev, "rx%u: unable to fully unmap client 0x%02x: %d\n", + rxport->nport, client->addr, ret); + return; + }
dev_dbg(dev, "rx%u: client 0x%02x released at slot %u\n", rxport->nport, client->addr, reg_idx); @@ -1285,7 +1295,7 @@ static int ub960_parse_dt_txport(struct ub960_data *priv, return ret; }
-static void ub960_csi_handle_events(struct ub960_data *priv, u8 nport) +static int ub960_csi_handle_events(struct ub960_data *priv, u8 nport) { struct device *dev = &priv->client->dev; u8 csi_tx_isr; @@ -1294,13 +1304,15 @@ static void ub960_csi_handle_events(struct ub960_data *priv, u8 nport) ret = ub960_txport_read(priv, nport, UB960_TR_CSI_TX_ISR, &csi_tx_isr, NULL); if (ret) - return; + return ret;
if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_SYNC_ERROR) dev_warn(dev, "TX%u: CSI_SYNC_ERROR\n", nport);
if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_PASS_ERROR) dev_warn(dev, "TX%u: CSI_PASS_ERROR\n", nport); + + return 0; }
/* ----------------------------------------------------------------------------- @@ -1352,28 +1364,38 @@ static void ub960_rxport_disable_vpocs(struct ub960_data *priv) } }
-static void ub960_rxport_clear_errors(struct ub960_data *priv, - unsigned int nport) +static int ub960_rxport_clear_errors(struct ub960_data *priv, + unsigned int nport) { + int ret = 0; u8 v;
- ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v, NULL); - ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v, NULL); - ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &v, NULL); - ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &v, NULL); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v, &ret); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v, &ret); + ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &v, &ret); + ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &v, &ret);
- ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v, NULL); - ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_LO, &v, NULL); + ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v, &ret); + ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_LO, &v, &ret);
- ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v, NULL); + ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v, &ret); + + return ret; }
-static void ub960_clear_rx_errors(struct ub960_data *priv) +static int ub960_clear_rx_errors(struct ub960_data *priv) { unsigned int nport;
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) - ub960_rxport_clear_errors(priv, nport); + for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { + int ret; + + ret = ub960_rxport_clear_errors(priv, nport); + if (ret) + return ret; + } + + return 0; }
static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, @@ -1383,14 +1405,18 @@ static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, u8 clk_delay, data_delay; int ret;
- ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_CLK, &v, NULL); + ret = ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB960_IR_RX_ANA_STROBE_SET_CLK, &v, NULL); + if (ret) + return ret;
clk_delay = (v & UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY) ? 0 : UB960_MANUAL_STROBE_EXTRA_DELAY;
- ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_DATA, &v, NULL); + ret = ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB960_IR_RX_ANA_STROBE_SET_DATA, &v, NULL); + if (ret) + return ret;
data_delay = (v & UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY) ? 0 : UB960_MANUAL_STROBE_EXTRA_DELAY; @@ -1412,10 +1438,11 @@ static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, return 0; }
-static void ub960_rxport_set_strobe_pos(struct ub960_data *priv, - unsigned int nport, s8 strobe_pos) +static int ub960_rxport_set_strobe_pos(struct ub960_data *priv, + unsigned int nport, s8 strobe_pos) { u8 clk_delay, data_delay; + int ret = 0;
clk_delay = UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY; data_delay = UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY; @@ -1430,23 +1457,25 @@ static void ub960_rxport_set_strobe_pos(struct ub960_data *priv, data_delay = strobe_pos | UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY;
ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_CLK, clk_delay, NULL); + UB960_IR_RX_ANA_STROBE_SET_CLK, clk_delay, &ret);
ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), - UB960_IR_RX_ANA_STROBE_SET_DATA, data_delay, NULL); + UB960_IR_RX_ANA_STROBE_SET_DATA, data_delay, &ret); + + return ret; }
-static void ub960_rxport_set_strobe_range(struct ub960_data *priv, - s8 strobe_min, s8 strobe_max) +static int ub960_rxport_set_strobe_range(struct ub960_data *priv, s8 strobe_min, + s8 strobe_max) { /* Convert the signed strobe pos to positive zero based value */ strobe_min -= UB960_MIN_AEQ_STROBE_POS; strobe_max -= UB960_MIN_AEQ_STROBE_POS;
- ub960_write(priv, UB960_XR_SFILTER_CFG, - ((u8)strobe_min << UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) | - ((u8)strobe_max << UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT), - NULL); + return ub960_write(priv, UB960_XR_SFILTER_CFG, + ((u8)strobe_min << UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) | + ((u8)strobe_max << UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT), + NULL); }
static int ub960_rxport_get_eq_level(struct ub960_data *priv, @@ -1465,11 +1494,12 @@ static int ub960_rxport_get_eq_level(struct ub960_data *priv, return 0; }
-static void ub960_rxport_set_eq_level(struct ub960_data *priv, - unsigned int nport, u8 eq_level) +static int ub960_rxport_set_eq_level(struct ub960_data *priv, + unsigned int nport, u8 eq_level) { u8 eq_stage_1_select_value, eq_stage_2_select_value; const unsigned int eq_stage_max = 7; + int ret; u8 v;
if (eq_level <= eq_stage_max) { @@ -1480,7 +1510,9 @@ static void ub960_rxport_set_eq_level(struct ub960_data *priv, eq_stage_2_select_value = eq_level - eq_stage_max; }
- ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v, NULL); + ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v, NULL); + if (ret) + return ret;
v &= ~(UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_MASK | UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_MASK); @@ -1488,68 +1520,102 @@ static void ub960_rxport_set_eq_level(struct ub960_data *priv, v |= eq_stage_2_select_value << UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_SHIFT; v |= UB960_RR_AEQ_BYPASS_ENABLE;
- ub960_rxport_write(priv, nport, UB960_RR_AEQ_BYPASS, v, NULL); + ret = ub960_rxport_write(priv, nport, UB960_RR_AEQ_BYPASS, v, NULL); + if (ret) + return ret; + + return 0; }
-static void ub960_rxport_set_eq_range(struct ub960_data *priv, - unsigned int nport, u8 eq_min, u8 eq_max) +static int ub960_rxport_set_eq_range(struct ub960_data *priv, + unsigned int nport, u8 eq_min, u8 eq_max) { + int ret = 0; + ub960_rxport_write(priv, nport, UB960_RR_AEQ_MIN_MAX, (eq_min << UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT) | (eq_max << UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT), - NULL); + &ret);
/* Enable AEQ min setting */ ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_CTL2, UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR, - UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR, NULL); + UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR, &ret); + + return ret; }
-static void ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport) +static int ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport) { struct ub960_rxport *rxport = priv->rxports[nport]; + int ret;
/* We also set common settings here. Should be moved elsewhere. */
if (priv->strobe.manual) { /* Disable AEQ_SFILTER_EN */ - ub960_update_bits(priv, UB960_XR_AEQ_CTL1, - UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, 0, NULL); + ret = ub960_update_bits(priv, UB960_XR_AEQ_CTL1, + UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, 0, + NULL); + if (ret) + return ret; } else { /* Enable SFILTER and error control */ - ub960_write(priv, UB960_XR_AEQ_CTL1, - UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_MASK | - UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, NULL); + ret = ub960_write(priv, UB960_XR_AEQ_CTL1, + UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_MASK | + UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, + NULL); + + if (ret) + return ret;
/* Set AEQ strobe range */ - ub960_rxport_set_strobe_range(priv, priv->strobe.min, - priv->strobe.max); + ret = ub960_rxport_set_strobe_range(priv, priv->strobe.min, + priv->strobe.max); + if (ret) + return ret; }
/* The rest are port specific */
if (priv->strobe.manual) - ub960_rxport_set_strobe_pos(priv, nport, rxport->eq.strobe_pos); + ret = ub960_rxport_set_strobe_pos(priv, nport, + rxport->eq.strobe_pos); else - ub960_rxport_set_strobe_pos(priv, nport, 0); + ret = ub960_rxport_set_strobe_pos(priv, nport, 0); + + if (ret) + return ret;
if (rxport->eq.manual_eq) { - ub960_rxport_set_eq_level(priv, nport, - rxport->eq.manual.eq_level); + ret = ub960_rxport_set_eq_level(priv, nport, + rxport->eq.manual.eq_level); + if (ret) + return ret;
/* Enable AEQ Bypass */ - ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, - UB960_RR_AEQ_BYPASS_ENABLE, - UB960_RR_AEQ_BYPASS_ENABLE, NULL); + ret = ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, + UB960_RR_AEQ_BYPASS_ENABLE, + UB960_RR_AEQ_BYPASS_ENABLE, + NULL); + if (ret) + return ret; } else { - ub960_rxport_set_eq_range(priv, nport, - rxport->eq.aeq.eq_level_min, - rxport->eq.aeq.eq_level_max); + ret = ub960_rxport_set_eq_range(priv, nport, + rxport->eq.aeq.eq_level_min, + rxport->eq.aeq.eq_level_max); + if (ret) + return ret;
/* Disable AEQ Bypass */ - ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, - UB960_RR_AEQ_BYPASS_ENABLE, 0, NULL); + ret = ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, + UB960_RR_AEQ_BYPASS_ENABLE, 0, + NULL); + if (ret) + return ret; } + + return 0; }
static int ub960_rxport_link_ok(struct ub960_data *priv, unsigned int nport, @@ -1697,8 +1763,11 @@ static int ub960_rxport_wait_locks(struct ub960_data *priv, continue; }
- ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v, - NULL); + ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, + &v, NULL); + + if (ret) + return ret;
if (priv->hw_data->is_ub9702) { dev_dbg(dev, "\trx%u: locked, freq %llu Hz\n", @@ -1867,8 +1936,8 @@ static void ub960_rxport_remove_serializers(struct ub960_data *priv) } }
-static void ub960_init_tx_port(struct ub960_data *priv, - struct ub960_txport *txport) +static int ub960_init_tx_port(struct ub960_data *priv, + struct ub960_txport *txport) { unsigned int nport = txport->nport; u8 csi_ctl = 0; @@ -1885,7 +1954,7 @@ static void ub960_init_tx_port(struct ub960_data *priv, if (!txport->non_continous_clk) csi_ctl |= UB960_TR_CSI_CTL_CSI_CONTS_CLOCK;
- ub960_txport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl, NULL); + return ub960_txport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl, NULL); }
static int ub960_init_tx_ports(struct ub960_data *priv) @@ -1893,6 +1962,7 @@ static int ub960_init_tx_ports(struct ub960_data *priv) unsigned int nport; u8 speed_select; u8 pll_div; + int ret = 0;
/* TX ports */
@@ -1916,51 +1986,57 @@ static int ub960_init_tx_ports(struct ub960_data *priv) break; }
- ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select, NULL); + ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select, &ret);
if (priv->hw_data->is_ub9702) { - ub960_write(priv, UB960_SR_CSI_PLL_DIV, pll_div, NULL); + ub960_write(priv, UB960_SR_CSI_PLL_DIV, pll_div, &ret);
switch (priv->tx_data_rate) { case MHZ(1600): default: ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, - 0x80, NULL); + 0x80, &ret); ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, - 0x2a, NULL); + 0x2a, &ret); break; case MHZ(800): ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, - 0x90, NULL); + 0x90, &ret); ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, - 0x2a, NULL); + 0x2a, &ret); ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, - 0x2a, NULL); + 0x2a, &ret); break; case MHZ(400): ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, - 0xa0, NULL); + 0xa0, &ret); break; } }
+ if (ret) + return ret; + for (nport = 0; nport < priv->hw_data->num_txports; nport++) { struct ub960_txport *txport = priv->txports[nport];
if (!txport) continue;
- ub960_init_tx_port(priv, txport); + ret = ub960_init_tx_port(priv, txport); + if (ret) + return ret; }
return 0; }
-static void ub960_init_rx_port_ub960(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_init_rx_port_ub960(struct ub960_data *priv, + struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; u32 bc_freq_val; + int ret = 0;
/* * Back channel frequency select. @@ -1989,19 +2065,19 @@ static void ub960_init_rx_port_ub960(struct ub960_data *priv, break;
default: - return; + return -EINVAL; }
ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, - bc_freq_val, NULL); + bc_freq_val, &ret);
switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: /* FPD3_MODE = RAW10 Mode (DS90UB913A-Q1 / DS90UB933-Q1 compatible) */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, UB960_RR_PORT_CONFIG_FPD3_MODE_MASK, - 0x3, NULL); + 0x3, &ret);
/* * RAW10_8BIT_CTL = 0b10 : 8-bit processing using upper 8 bits @@ -2009,55 +2085,58 @@ static void ub960_init_rx_port_ub960(struct ub960_data *priv, ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_MASK, 0x2 << UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_SHIFT, - NULL); + &ret);
break;
case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: /* Not implemented */ - return; + return -EINVAL;
case RXPORT_MODE_CSI2_SYNC: case RXPORT_MODE_CSI2_NONSYNC: /* CSI-2 Mode (DS90UB953-Q1 compatible) */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, 0x3, - 0x0, NULL); + 0x0, &ret);
break; }
/* LV_POLARITY & FV_POLARITY */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, - rxport->lv_fv_pol, NULL); + rxport->lv_fv_pol, &ret);
/* Enable all interrupt sources from this port */ - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07, NULL); - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f, NULL); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07, &ret); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f, &ret);
/* Enable I2C_PASS_THROUGH */ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, - UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, NULL); + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, &ret);
/* Enable I2C communication to the serializer via the alias addr */ ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, - rxport->ser.alias << 1, NULL); + rxport->ser.alias << 1, &ret);
/* Configure EQ related settings */ ub960_rxport_config_eq(priv, nport);
/* Enable RX port */ ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), - NULL); + &ret); + + return ret; }
-static void ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, + struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; u8 bc_freq_val; u8 fpd_func_mode; + int ret = 0;
switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: @@ -2086,90 +2165,96 @@ static void ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, break;
default: - return; + return -EINVAL; }
ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, - bc_freq_val, NULL); + bc_freq_val, &ret); ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, fpd_func_mode, - NULL); + &ret);
/* set serdes_eq_mode = 1 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa8, 0x80, - NULL); + &ret);
/* enable serdes driver */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x0d, 0x7f, - NULL); + &ret);
/* set serdes_eq_offset=4 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04, - NULL); + &ret);
/* init default serdes_eq_max in 0xa9 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa9, 0x23, - NULL); + &ret);
/* init serdes_eq_min in 0xaa */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xaa, 0, NULL); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xaa, 0, &ret);
/* serdes_driver_ctl2 control: DS90UB953-Q1/DS90UB933-Q1/DS90UB913A-Q1 */ ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, - BIT(3), BIT(3), NULL); + BIT(3), BIT(3), &ret);
/* RX port to half-rate */ ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), - BIT(nport * 2), NULL); + BIT(nport * 2), &ret); + + return ret; }
-static void ub960_init_rx_port_ub9702_fpd4_aeq(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_init_rx_port_ub9702_fpd4_aeq(struct ub960_data *priv, + struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; bool first_time_power_up = true; + int ret = 0;
if (first_time_power_up) { u8 v;
/* AEQ init */ ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2c, &v, - NULL); + &ret);
ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, v, - NULL); + &ret); ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, - v + 1, NULL); + v + 1, &ret);
ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, - 0x00, NULL); + 0x00, &ret); }
/* enable serdes_eq_ctl2 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x9e, 0x00, - NULL); + &ret);
/* enable serdes_eq_ctl1 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x90, 0x40, - NULL); + &ret);
/* enable serdes_eq_en */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2e, 0x40, - NULL); + &ret);
/* disable serdes_eq_override */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xf0, 0x00, - NULL); + &ret);
/* disable serdes_gain_override */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x71, 0x00, - NULL); + &ret); + + return ret; }
-static void ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, + struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; u8 bc_freq_val; + int ret = 0;
switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: @@ -2193,55 +2278,66 @@ static void ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, break;
default: - return; + return -EINVAL; }
ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, - bc_freq_val, NULL); + bc_freq_val, &ret);
/* FPD4 Sync Mode */ - ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, 0, NULL); + ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, 0, &ret);
/* add serdes_eq_offset of 4 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04, - NULL); + &ret);
/* FPD4 serdes_start_eq in 0x27: assign default */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, 0x0, NULL); + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, 0x0, &ret); /* FPD4 serdes_end_eq in 0x28: assign default */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, 0x23, - NULL); + &ret);
/* set serdes_driver_mode into FPD IV mode */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x04, 0x00, - NULL); + &ret); /* set FPD PBC drv into FPD IV mode */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, 0x00, - NULL); + &ret);
/* set serdes_system_init to 0x2f */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x21, 0x2f, - NULL); + &ret); /* set serdes_system_rst in reset mode */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0xc1, - NULL); + &ret);
/* RX port to 7.55G mode */ ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), - 0 << (nport * 2), NULL); + 0 << (nport * 2), &ret); + + if (ret) + return ret;
- ub960_init_rx_port_ub9702_fpd4_aeq(priv, rxport); + ret = ub960_init_rx_port_ub9702_fpd4_aeq(priv, rxport); + if (ret) + return ret; + + return 0; }
-static void ub960_init_rx_port_ub9702(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_init_rx_port_ub9702(struct ub960_data *priv, + struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; + int ret;
if (rxport->cdr_mode == RXPORT_CDR_FPD3) - ub960_init_rx_port_ub9702_fpd3(priv, rxport); + ret = ub960_init_rx_port_ub9702_fpd3(priv, rxport); else /* RXPORT_CDR_FPD4 */ - ub960_init_rx_port_ub9702_fpd4(priv, rxport); + ret = ub960_init_rx_port_ub9702_fpd4(priv, rxport); + + if (ret) + return ret;
switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: @@ -2250,14 +2346,14 @@ static void ub960_init_rx_port_ub9702(struct ub960_data *priv, * 0b10 : 8-bit processing using upper 8 bits */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, - 0x3 << 6, 0x2 << 6, NULL); + 0x3 << 6, 0x2 << 6, &ret);
break;
case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: /* Not implemented */ - return; + return -EINVAL;
case RXPORT_MODE_CSI2_SYNC: case RXPORT_MODE_CSI2_NONSYNC: @@ -2267,30 +2363,32 @@ static void ub960_init_rx_port_ub9702(struct ub960_data *priv,
/* LV_POLARITY & FV_POLARITY */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, - rxport->lv_fv_pol, NULL); + rxport->lv_fv_pol, &ret);
/* Enable all interrupt sources from this port */ - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07, NULL); - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f, NULL); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07, &ret); + ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f, &ret);
/* Enable I2C_PASS_THROUGH */ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, - UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, NULL); + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, &ret);
/* Enable I2C communication to the serializer via the alias addr */ ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, - rxport->ser.alias << 1, NULL); + rxport->ser.alias << 1, &ret);
/* Enable RX port */ ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), - NULL); + &ret);
if (rxport->cdr_mode == RXPORT_CDR_FPD4) { /* unreset 960 AEQ */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, - 0x41, NULL); + 0x41, &ret); } + + return ret; }
static int ub960_init_rx_ports(struct ub960_data *priv) @@ -2299,20 +2397,24 @@ static int ub960_init_rx_ports(struct ub960_data *priv)
for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; + int ret;
if (!rxport) continue;
if (priv->hw_data->is_ub9702) - ub960_init_rx_port_ub9702(priv, rxport); + ret = ub960_init_rx_port_ub9702(priv, rxport); else - ub960_init_rx_port_ub960(priv, rxport); + ret = ub960_init_rx_port_ub960(priv, rxport); + + if (ret) + return ret; }
return 0; }
-static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) +static int ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) { struct device *dev = &priv->client->dev; u8 rx_port_sts1; @@ -2322,21 +2424,15 @@ static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) int ret = 0;
/* Read interrupts (also clears most of them) */ - if (!ret) - ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, - &rx_port_sts1, NULL); - if (!ret) - ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, - &rx_port_sts2, NULL); - if (!ret) - ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, - &csi_rx_sts, NULL); - if (!ret) - ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, - &bcc_sts, NULL); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &rx_port_sts1, + &ret); + ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &rx_port_sts2, + &ret); + ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &csi_rx_sts, &ret); + ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &bcc_sts, &ret);
if (ret) - return; + return ret;
if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_PARITY_ERROR) { u16 v; @@ -2431,6 +2527,8 @@ static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) "stable freq" : "unstable freq"); } + + return 0; }
/* ----------------------------------------------------------------------------- @@ -2486,14 +2584,14 @@ static int ub960_enable_tx_port(struct ub960_data *priv, unsigned int nport) UB960_TR_CSI_CTL_CSI_ENABLE, NULL); }
-static void ub960_disable_tx_port(struct ub960_data *priv, unsigned int nport) +static int ub960_disable_tx_port(struct ub960_data *priv, unsigned int nport) { struct device *dev = &priv->client->dev;
dev_dbg(dev, "disable TX port %u\n", nport);
- ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, - UB960_TR_CSI_CTL_CSI_ENABLE, 0, NULL); + return ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, + UB960_TR_CSI_CTL_CSI_ENABLE, 0, NULL); }
static int ub960_enable_rx_port(struct ub960_data *priv, unsigned int nport) @@ -2507,16 +2605,16 @@ static int ub960_enable_rx_port(struct ub960_data *priv, unsigned int nport) UB960_SR_FWD_CTL1_PORT_DIS(nport), 0, NULL); }
-static void ub960_disable_rx_port(struct ub960_data *priv, unsigned int nport) +static int ub960_disable_rx_port(struct ub960_data *priv, unsigned int nport) { struct device *dev = &priv->client->dev;
dev_dbg(dev, "disable RX port %u\n", nport);
/* Disable forwarding */ - ub960_update_bits(priv, UB960_SR_FWD_CTL1, - UB960_SR_FWD_CTL1_PORT_DIS(nport), - UB960_SR_FWD_CTL1_PORT_DIS(nport), NULL); + return ub960_update_bits(priv, UB960_SR_FWD_CTL1, + UB960_SR_FWD_CTL1_PORT_DIS(nport), + UB960_SR_FWD_CTL1_PORT_DIS(nport), NULL); }
/* @@ -2658,12 +2756,12 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, case RXPORT_MODE_RAW10: ub960_rxport_write(priv, nport, UB960_RR_RAW10_ID, rx_data[nport].pixel_dt | (vc << UB960_RR_RAW10_ID_VC_SHIFT), - NULL); + &ret);
ub960_rxport_write(priv, rxport->nport, UB960_RR_RAW_EMBED_DTYPE, (rx_data[nport].meta_lines << UB960_RR_RAW_EMBED_DTYPE_LINES_SHIFT) | - rx_data[nport].meta_dt, NULL); + rx_data[nport].meta_dt, &ret);
break;
@@ -2681,7 +2779,7 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, (vc << UB960_RR_CSI_VC_MAP_SHIFT(2)) | (vc << UB960_RR_CSI_VC_MAP_SHIFT(1)) | (vc << UB960_RR_CSI_VC_MAP_SHIFT(0)), - NULL); + &ret); } else { unsigned int i;
@@ -2690,7 +2788,7 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, ub960_rxport_write(priv, nport, UB960_RR_VC_ID_MAP(i), (nport << 4) | nport, - NULL); + &ret); }
break; @@ -2702,9 +2800,9 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, fwd_ctl &= ~BIT(nport); /* forward to TX0 */ }
- ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl, NULL); + ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl, &ret);
- return 0; + return ret; }
static void ub960_update_streaming_status(struct ub960_data *priv) @@ -3107,8 +3205,8 @@ static const struct v4l2_subdev_pad_ops ub960_pad_ops = { .set_fmt = ub960_set_fmt, };
-static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv, - unsigned int nport) +static int ub960_log_status_ub960_sp_eq(struct ub960_data *priv, + unsigned int nport) { struct device *dev = &priv->client->dev; u8 eq_level; @@ -3120,7 +3218,7 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv,
ret = ub960_read(priv, UB960_XR_AEQ_CTL1, &v, NULL); if (ret) - return; + return ret;
dev_info(dev, "\t%s strobe\n", (v & UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN) ? "Adaptive" : @@ -3129,7 +3227,7 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv, if (v & UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN) { ret = ub960_read(priv, UB960_XR_SFILTER_CFG, &v, NULL); if (ret) - return; + return ret;
dev_info(dev, "\tStrobe range [%d, %d]\n", ((v >> UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) & 0xf) - 7, @@ -3138,7 +3236,7 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv,
ret = ub960_rxport_get_strobe_pos(priv, nport, &strobe_pos); if (ret) - return; + return ret;
dev_info(dev, "\tStrobe pos %d\n", strobe_pos);
@@ -3146,7 +3244,7 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv,
ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v, NULL); if (ret) - return; + return ret;
dev_info(dev, "\t%s EQ\n", (v & UB960_RR_AEQ_BYPASS_ENABLE) ? "Manual" : @@ -3156,15 +3254,20 @@ static void ub960_log_status_ub960_sp_eq(struct ub960_data *priv, ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_MIN_MAX, &v, NULL); if (ret) - return; + return ret;
dev_info(dev, "\tEQ range [%u, %u]\n", (v >> UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT) & 0xf, (v >> UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT) & 0xf); }
- if (ub960_rxport_get_eq_level(priv, nport, &eq_level) == 0) - dev_info(dev, "\tEQ level %u\n", eq_level); + ret = ub960_rxport_get_eq_level(priv, nport, &eq_level); + if (ret) + return ret; + + dev_info(dev, "\tEQ level %u\n", eq_level); + + return 0; }
static int ub960_log_status(struct v4l2_subdev *sd) @@ -3176,11 +3279,15 @@ static int ub960_log_status(struct v4l2_subdev *sd) u16 v16 = 0; u8 v = 0; u8 id[UB960_SR_FPD3_RX_ID_LEN]; + int ret = 0;
state = v4l2_subdev_lock_and_get_active_state(sd);
- for (unsigned int i = 0; i < sizeof(id); i++) - ub960_read(priv, UB960_SR_FPD3_RX_ID(i), &id[i], NULL); + for (unsigned int i = 0; i < sizeof(id); i++) { + ret = ub960_read(priv, UB960_SR_FPD3_RX_ID(i), &id[i], NULL); + if (ret) + return ret; + }
dev_info(dev, "ID '%.*s'\n", (int)sizeof(id), id);
@@ -3194,24 +3301,39 @@ static int ub960_log_status(struct v4l2_subdev *sd) continue; }
- ub960_txport_read(priv, nport, UB960_TR_CSI_STS, &v, NULL); + ret = ub960_txport_read(priv, nport, UB960_TR_CSI_STS, &v, NULL); + if (ret) + return ret; + dev_info(dev, "\tsync %u, pass %u\n", v & (u8)BIT(1), v & (u8)BIT(0));
- ub960_read16(priv, UB960_SR_CSI_FRAME_COUNT_HI(nport), &v16, - NULL); + ret = ub960_read16(priv, UB960_SR_CSI_FRAME_COUNT_HI(nport), + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tframe counter %u\n", v16);
- ub960_read16(priv, UB960_SR_CSI_FRAME_ERR_COUNT_HI(nport), - &v16, NULL); + ret = ub960_read16(priv, UB960_SR_CSI_FRAME_ERR_COUNT_HI(nport), + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tframe error counter %u\n", v16);
- ub960_read16(priv, UB960_SR_CSI_LINE_COUNT_HI(nport), &v16, - NULL); + ret = ub960_read16(priv, UB960_SR_CSI_LINE_COUNT_HI(nport), + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tline counter %u\n", v16);
- ub960_read16(priv, UB960_SR_CSI_LINE_ERR_COUNT_HI(nport), - &v16, NULL); + ret = ub960_read16(priv, UB960_SR_CSI_LINE_ERR_COUNT_HI(nport), + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tline error counter %u\n", v16); }
@@ -3225,8 +3347,10 @@ static int ub960_log_status(struct v4l2_subdev *sd) continue; }
- ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v, - NULL); + ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v, + NULL); + if (ret) + return ret;
if (v & UB960_RR_RX_PORT_STS1_LOCK_STS) dev_info(dev, "\tLocked\n"); @@ -3234,32 +3358,53 @@ static int ub960_log_status(struct v4l2_subdev *sd) dev_info(dev, "\tNot locked\n");
dev_info(dev, "\trx_port_sts1 %#02x\n", v); - ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v, - NULL); + ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v, + NULL); + if (ret) + return ret; + dev_info(dev, "\trx_port_sts2 %#02x\n", v);
- ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v16, - NULL); + ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tlink freq %llu Hz\n", ((u64)v16 * HZ_PER_MHZ) >> 8);
- ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v16, - NULL); + ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tparity errors %u\n", v16);
- ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, &v16, - NULL); + ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tlines per frame %u\n", v16);
- ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v16, - NULL); + ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, + &v16, NULL); + if (ret) + return ret; + dev_info(dev, "\tbytes per line %u\n", v16);
- ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v, - NULL); + ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, + &v, NULL); + if (ret) + return ret; + dev_info(dev, "\tcsi_err_counter %u\n", v);
- if (!priv->hw_data->is_ub9702) - ub960_log_status_ub960_sp_eq(priv, nport); + if (!priv->hw_data->is_ub9702) { + ret = ub960_log_status_ub960_sp_eq(priv, nport); + if (ret) + return ret; + }
/* GPIOs */ for (unsigned int i = 0; i < UB960_NUM_BC_GPIOS; i++) { @@ -3269,7 +3414,9 @@ static int ub960_log_status(struct v4l2_subdev *sd) ctl_reg = UB960_RR_BC_GPIO_CTL(i / 2); ctl_shift = (i % 2) * 4;
- ub960_rxport_read(priv, nport, ctl_reg, &v, NULL); + ret = ub960_rxport_read(priv, nport, ctl_reg, &v, NULL); + if (ret) + return ret;
dev_info(dev, "\tGPIO%u: mode %u\n", i, (v >> ctl_shift) & 0xf); @@ -3325,16 +3472,22 @@ static irqreturn_t ub960_handle_events(int irq, void *arg) dev_dbg(&priv->client->dev, "FWD_STS %#02x\n", fwd_sts);
for (i = 0; i < priv->hw_data->num_txports; i++) { - if (int_sts & UB960_SR_INTERRUPT_STS_IS_CSI_TX(i)) - ub960_csi_handle_events(priv, i); + if (int_sts & UB960_SR_INTERRUPT_STS_IS_CSI_TX(i)) { + ret = ub960_csi_handle_events(priv, i); + if (ret) + return IRQ_NONE; + } }
for (i = 0; i < priv->hw_data->num_rxports; i++) { if (!priv->rxports[i]) continue;
- if (int_sts & UB960_SR_INTERRUPT_STS_IS_RX(i)) - ub960_rxport_handle_events(priv, i); + if (int_sts & UB960_SR_INTERRUPT_STS_IS_RX(i)) { + ret = ub960_rxport_handle_events(priv, i); + if (ret) + return IRQ_NONE; + } }
return IRQ_HANDLED; @@ -3938,7 +4091,7 @@ static const struct regmap_config ub960_regmap_config = { .disable_locking = true, };
-static void ub960_reset(struct ub960_data *priv, bool reset_regs) +static int ub960_reset(struct ub960_data *priv, bool reset_regs) { struct device *dev = &priv->client->dev; unsigned int v; @@ -3948,7 +4101,9 @@ static void ub960_reset(struct ub960_data *priv, bool reset_regs) bit = reset_regs ? UB960_SR_RESET_DIGITAL_RESET1 : UB960_SR_RESET_DIGITAL_RESET0;
- ub960_write(priv, UB960_SR_RESET, bit, NULL); + ret = ub960_write(priv, UB960_SR_RESET, bit, NULL); + if (ret) + return ret;
mutex_lock(&priv->reg_lock);
@@ -3959,6 +4114,8 @@ static void ub960_reset(struct ub960_data *priv, bool reset_regs)
if (ret) dev_err(dev, "reset failed: %d\n", ret); + + return ret; }
static int ub960_get_hw_resources(struct ub960_data *priv) @@ -4017,7 +4174,9 @@ static int ub960_enable_core_hw(struct ub960_data *priv) fsleep(2000); }
- ub960_reset(priv, true); + ret = ub960_reset(priv, true); + if (ret) + goto err_pd_gpio;
/* Runtime check register accessibility */ ret = ub960_read(priv, UB960_SR_REV_MASK, &rev_mask, NULL); @@ -4132,7 +4291,9 @@ static int ub960_probe(struct i2c_client *client) if (ret) goto err_disable_vpocs;
- ub960_reset(priv, false); + ret = ub960_reset(priv, false); + if (ret) + goto err_disable_vpocs;
port_mask = 0;
@@ -4159,7 +4320,9 @@ static int ub960_probe(struct i2c_client *client) * Clear any errors caused by switching the RX port settings while * probing. */ - ub960_clear_rx_errors(priv); + ret = ub960_clear_rx_errors(priv); + if (ret) + goto err_disable_vpocs;
ret = ub960_init_atr(priv); if (ret)
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Add error handling to ub953_log_status().
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub953.c | 80 +++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 22 deletions(-)
diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index fbd977760c6b1ccdec90b90bced4dc29932f3893..a08aad3f7fe09f7b396da9c720ed9993d392410c 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -633,23 +633,33 @@ static int ub953_log_status(struct v4l2_subdev *sd) { struct ub953_data *priv = sd_to_ub953(sd); struct device *dev = &priv->client->dev; - u8 v = 0, v1 = 0, v2 = 0; - unsigned int i; char id[UB953_REG_FPD3_RX_ID_LEN]; - u8 gpio_local_data = 0; - u8 gpio_input_ctrl = 0; - u8 gpio_pin_sts = 0; + u8 gpio_local_data; + u8 gpio_input_ctrl; + u8 gpio_pin_sts; + unsigned int i; + u8 v, v1, v2; + int ret;
- for (i = 0; i < sizeof(id); i++) - ub953_read(priv, UB953_REG_FPD3_RX_ID(i), &id[i], NULL); + for (i = 0; i < sizeof(id); i++) { + ret = ub953_read(priv, UB953_REG_FPD3_RX_ID(i), &id[i], NULL); + if (ret) + return ret; + }
dev_info(dev, "ID '%.*s'\n", (int)sizeof(id), id);
- ub953_read(priv, UB953_REG_GENERAL_STATUS, &v, NULL); + ret = ub953_read(priv, UB953_REG_GENERAL_STATUS, &v, NULL); + if (ret) + return ret; + dev_info(dev, "GENERAL_STATUS %#02x\n", v);
- ub953_read(priv, UB953_REG_CRC_ERR_CNT1, &v1, NULL); - ub953_read(priv, UB953_REG_CRC_ERR_CNT2, &v2, NULL); + ub953_read(priv, UB953_REG_CRC_ERR_CNT1, &v1, &ret); + ub953_read(priv, UB953_REG_CRC_ERR_CNT2, &v2, &ret); + if (ret) + return ret; + dev_info(dev, "CRC error count %u\n", v1 | (v2 << 8));
/* Clear CRC error counter */ @@ -658,34 +668,60 @@ static int ub953_log_status(struct v4l2_subdev *sd) UB953_REG_BC_CTRL_CRC_ERR_CLR, UB953_REG_BC_CTRL_CRC_ERR_CLR);
- ub953_read(priv, UB953_REG_CSI_ERR_CNT, &v, NULL); + ret = ub953_read(priv, UB953_REG_CSI_ERR_CNT, &v, NULL); + if (ret) + return ret; + dev_info(dev, "CSI error count %u\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_STATUS, &v, NULL); + ret = ub953_read(priv, UB953_REG_CSI_ERR_STATUS, &v, NULL); + if (ret) + return ret; + dev_info(dev, "CSI_ERR_STATUS %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_DLANE01, &v, NULL); + ret = ub953_read(priv, UB953_REG_CSI_ERR_DLANE01, &v, NULL); + if (ret) + return ret; + dev_info(dev, "CSI_ERR_DLANE01 %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_DLANE23, &v, NULL); + ret = ub953_read(priv, UB953_REG_CSI_ERR_DLANE23, &v, NULL); + if (ret) + return ret; + dev_info(dev, "CSI_ERR_DLANE23 %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_ERR_CLK_LANE, &v, NULL); + ret = ub953_read(priv, UB953_REG_CSI_ERR_CLK_LANE, &v, NULL); + if (ret) + return ret; + dev_info(dev, "CSI_ERR_CLK_LANE %#02x\n", v);
- ub953_read(priv, UB953_REG_CSI_PKT_HDR_VC_ID, &v, NULL); + ret = ub953_read(priv, UB953_REG_CSI_PKT_HDR_VC_ID, &v, NULL); + if (ret) + return ret; + dev_info(dev, "CSI packet header VC %u ID %u\n", v >> 6, v & 0x3f);
- ub953_read(priv, UB953_REG_PKT_HDR_WC_LSB, &v1, NULL); - ub953_read(priv, UB953_REG_PKT_HDR_WC_MSB, &v2, NULL); + ub953_read(priv, UB953_REG_PKT_HDR_WC_LSB, &v1, &ret); + ub953_read(priv, UB953_REG_PKT_HDR_WC_MSB, &v2, &ret); + if (ret) + return ret; + dev_info(dev, "CSI packet header WC %u\n", (v2 << 8) | v1);
- ub953_read(priv, UB953_REG_CSI_ECC, &v, NULL); + ret = ub953_read(priv, UB953_REG_CSI_ECC, &v, NULL); + if (ret) + return ret; + dev_info(dev, "CSI ECC %#02x\n", v);
- ub953_read(priv, UB953_REG_LOCAL_GPIO_DATA, &gpio_local_data, NULL); - ub953_read(priv, UB953_REG_GPIO_INPUT_CTRL, &gpio_input_ctrl, NULL); - ub953_read(priv, UB953_REG_GPIO_PIN_STS, &gpio_pin_sts, NULL); + ub953_read(priv, UB953_REG_LOCAL_GPIO_DATA, &gpio_local_data, &ret); + ub953_read(priv, UB953_REG_GPIO_INPUT_CTRL, &gpio_input_ctrl, &ret); + ub953_read(priv, UB953_REG_GPIO_PIN_STS, &gpio_pin_sts, &ret); + if (ret) + return ret;
for (i = 0; i < UB953_NUM_GPIOS; i++) { dev_info(dev,
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Add error handling to ub913_log_status().
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub913.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index f38421d34d204fa9ab898d10c6b69942858bced2..401cc2a10c3c9855b1875b2ff200d5109e80b2e0 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -504,25 +504,41 @@ static int ub913_log_status(struct v4l2_subdev *sd) { struct ub913_data *priv = sd_to_ub913(sd); struct device *dev = &priv->client->dev; - u8 v = 0, v1 = 0, v2 = 0; + u8 v, v1, v2; + int ret; + + ret = ub913_read(priv, UB913_REG_MODE_SEL, &v, NULL); + if (ret) + return ret;
- ub913_read(priv, UB913_REG_MODE_SEL, &v, NULL); dev_info(dev, "MODE_SEL %#02x\n", v);
- ub913_read(priv, UB913_REG_CRC_ERRORS_LSB, &v1, NULL); - ub913_read(priv, UB913_REG_CRC_ERRORS_MSB, &v2, NULL); + ub913_read(priv, UB913_REG_CRC_ERRORS_LSB, &v1, &ret); + ub913_read(priv, UB913_REG_CRC_ERRORS_MSB, &v2, &ret); + if (ret) + return ret; + dev_info(dev, "CRC errors %u\n", v1 | (v2 << 8));
/* clear CRC errors */ - ub913_read(priv, UB913_REG_GENERAL_CFG, &v, NULL); + ub913_read(priv, UB913_REG_GENERAL_CFG, &v, &ret); ub913_write(priv, UB913_REG_GENERAL_CFG, - v | UB913_REG_GENERAL_CFG_CRC_ERR_RESET, NULL); - ub913_write(priv, UB913_REG_GENERAL_CFG, v, NULL); + v | UB913_REG_GENERAL_CFG_CRC_ERR_RESET, &ret); + ub913_write(priv, UB913_REG_GENERAL_CFG, v, &ret); + + if (ret) + return ret; + + ret = ub913_read(priv, UB913_REG_GENERAL_STATUS, &v, NULL); + if (ret) + return ret;
- ub913_read(priv, UB913_REG_GENERAL_STATUS, &v, NULL); dev_info(dev, "GENERAL_STATUS %#02x\n", v);
- ub913_read(priv, UB913_REG_PLL_OVR, &v, NULL); + ret = ub913_read(priv, UB913_REG_PLL_OVR, &v, NULL); + if (ret) + return ret; + dev_info(dev, "PLL_OVR %#02x\n", v);
return 0;
On the I2C bus for remote clients (sensors), by default the watchdog timer expires in 1s. To allow for a quicker system bring-up time, TI recommends to speed it up to 50us [1].
[1]: Section 7.3.1.1 - https://www.ti.com/lit/gpn/ds90ub953-q1
Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- Changes from v2: - Use unsigned value for left shifting - Re-introduce temp variable v that was dropped as it makes it easier to read IMHO - Remove redundancies like initializing v = 0 and if (ret) return ret at the end of the function --- drivers/media/i2c/ds90ub953.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index a08aad3f7fe09f7b396da9c720ed9993d392410c..a5c23e94f4eab5896a2114cfdf2e5f68cde77568 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -54,6 +54,10 @@ #define UB953_REG_CLKOUT_CTRL0 0x06 #define UB953_REG_CLKOUT_CTRL1 0x07
+#define UB953_REG_I2C_CONTROL2 0x0a +#define UB953_REG_I2C_CONTROL2_SDA_OUTPUT_SETUP_SHIFT 4 +#define UB953_REG_I2C_CONTROL2_BUS_SPEEDUP BIT(1) + #define UB953_REG_SCL_HIGH_TIME 0x0b #define UB953_REG_SCL_LOW_TIME 0x0c
@@ -1320,7 +1324,12 @@ static int ub953_hw_init(struct ub953_data *priv) if (ret) return ret;
- return 0; + v = 1U << UB953_REG_I2C_CONTROL2_SDA_OUTPUT_SETUP_SHIFT; + v |= UB953_REG_I2C_CONTROL2_BUS_SPEEDUP; + + ret = ub953_write(priv, UB953_REG_I2C_CONTROL2, v, NULL); + + return ret; }
static int ub953_subdev_init(struct ub953_data *priv)
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
The driver supports both UB960 and UB9702. While devices work in similar ways and have a lot of identical registers, there are also plenty of differences.
To clarify the situation a bit, move the UB9702 registers to a separate section and prefix them with UB9702.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub960.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 086aa8cc78fa4e4e9ccc08589cbaf1cc06104786..f9af6d643ac86de22286b2107d747341c7d6f9b0 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -307,8 +307,6 @@
#define UB960_XR_REFCLK_FREQ 0xa5 /* UB960 */
-#define UB960_RR_VC_ID_MAP(x) (0xa0 + (x)) /* UB9702 */ - #define UB960_SR_IND_ACC_CTL 0xb0 #define UB960_SR_IND_ACC_CTL_IA_AUTO_INC BIT(1)
@@ -321,9 +319,6 @@ #define UB960_SR_FV_MIN_TIME 0xbc #define UB960_SR_GPIO_PD_CTL 0xbe
-#define UB960_SR_FPD_RATE_CFG 0xc2 /* UB9702 */ -#define UB960_SR_CSI_PLL_DIV 0xc9 /* UB9702 */ - #define UB960_RR_PORT_DEBUG 0xd0 #define UB960_RR_AEQ_CTL2 0xd2 #define UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR BIT(2) @@ -354,15 +349,12 @@ #define UB960_RR_SEN_INT_RISE_STS 0xde #define UB960_RR_SEN_INT_FALL_STS 0xdf
-#define UB960_RR_CHANNEL_MODE 0xe4 /* UB9702 */
#define UB960_SR_FPD3_RX_ID(n) (0xf0 + (n)) #define UB960_SR_FPD3_RX_ID_LEN 6
#define UB960_SR_I2C_RX_ID(n) (0xf8 + (n))
-#define UB9702_SR_REFCLK_FREQ 0x3d - /* Indirect register blocks */ #define UB960_IND_TARGET_PAT_GEN 0x00 #define UB960_IND_TARGET_RX_ANA(n) (0x01 + (n)) @@ -397,6 +389,14 @@ #define UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY BIT(3) #define UB960_IR_RX_ANA_STROBE_SET_DATA_DELAY_MASK GENMASK(2, 0)
+/* UB9702 Registers */ + +#define UB9702_SR_REFCLK_FREQ 0x3d +#define UB9702_RR_VC_ID_MAP(x) (0xa0 + (x)) +#define UB9702_SR_FPD_RATE_CFG 0xc2 +#define UB9702_SR_CSI_PLL_DIV 0xc9 +#define UB9702_RR_CHANNEL_MODE 0xe4 + /* EQ related */
#define UB960_MIN_AEQ_STROBE_POS -7 @@ -1989,7 +1989,7 @@ static int ub960_init_tx_ports(struct ub960_data *priv) ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select, &ret);
if (priv->hw_data->is_ub9702) { - ub960_write(priv, UB960_SR_CSI_PLL_DIV, pll_div, &ret); + ub960_write(priv, UB9702_SR_CSI_PLL_DIV, pll_div, &ret);
switch (priv->tx_data_rate) { case MHZ(1600): @@ -2170,7 +2170,7 @@ static int ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv,
ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, bc_freq_val, &ret); - ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, fpd_func_mode, + ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, fpd_func_mode, &ret);
/* set serdes_eq_mode = 1 */ @@ -2197,7 +2197,7 @@ static int ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, BIT(3), BIT(3), &ret);
/* RX port to half-rate */ - ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), + ub960_update_bits(priv, UB9702_SR_FPD_RATE_CFG, 0x3 << (nport * 2), BIT(nport * 2), &ret);
return ret; @@ -2285,7 +2285,7 @@ static int ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, bc_freq_val, &ret);
/* FPD4 Sync Mode */ - ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, 0, &ret); + ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, 0, &ret);
/* add serdes_eq_offset of 4 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04, @@ -2312,7 +2312,7 @@ static int ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, &ret);
/* RX port to 7.55G mode */ - ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), + ub960_update_bits(priv, UB9702_SR_FPD_RATE_CFG, 0x3 << (nport * 2), 0 << (nport * 2), &ret);
if (ret) @@ -2786,7 +2786,7 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, /* Map all VCs from this port to VC(nport) */ for (i = 0; i < 8; i++) ub960_rxport_write(priv, nport, - UB960_RR_VC_ID_MAP(i), + UB9702_RR_VC_ID_MAP(i), (nport << 4) | nport, &ret); }
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Add UB9702 specific registers which will be used in the following patches.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub960.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index f9af6d643ac86de22286b2107d747341c7d6f9b0..c56398aa895f05029879fb336bc52c932fee494d 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -391,12 +391,47 @@
/* UB9702 Registers */
+#define UB9702_SR_CSI_EXCLUSIVE_FWD2 0x3c #define UB9702_SR_REFCLK_FREQ 0x3d +#define UB9702_RR_RX_CTL_1 0x80 +#define UB9702_RR_RX_CTL_2 0x87 #define UB9702_RR_VC_ID_MAP(x) (0xa0 + (x)) #define UB9702_SR_FPD_RATE_CFG 0xc2 #define UB9702_SR_CSI_PLL_DIV 0xc9 +#define UB9702_RR_RX_SM_SEL_2 0xd4 #define UB9702_RR_CHANNEL_MODE 0xe4
+#define UB9702_IND_TARGET_SAR_ADC 0x0a + +#define UB9702_IR_RX_ANA_FPD_BC_CTL0 0x04 +#define UB9702_IR_RX_ANA_FPD_BC_CTL1 0x0d +#define UB9702_IR_RX_ANA_FPD_BC_CTL2 0x1b +#define UB9702_IR_RX_ANA_SYSTEM_INIT_REG0 0x21 +#define UB9702_IR_RX_ANA_AEQ_ALP_SEL6 0x27 +#define UB9702_IR_RX_ANA_AEQ_ALP_SEL7 0x28 +#define UB9702_IR_RX_ANA_AEQ_ALP_SEL10 0x2b +#define UB9702_IR_RX_ANA_AEQ_ALP_SEL11 0x2c +#define UB9702_IR_RX_ANA_EQ_ADAPT_CTRL 0x2e +#define UB9702_IR_RX_ANA_AEQ_CFG_1 0x34 +#define UB9702_IR_RX_ANA_AEQ_CFG_2 0x4d +#define UB9702_IR_RX_ANA_GAIN_CTRL_0 0x71 +#define UB9702_IR_RX_ANA_GAIN_CTRL_0 0x71 +#define UB9702_IR_RX_ANA_VGA_CTRL_SEL_1 0x72 +#define UB9702_IR_RX_ANA_VGA_CTRL_SEL_2 0x73 +#define UB9702_IR_RX_ANA_VGA_CTRL_SEL_3 0x74 +#define UB9702_IR_RX_ANA_VGA_CTRL_SEL_6 0x77 +#define UB9702_IR_RX_ANA_AEQ_CFG_3 0x79 +#define UB9702_IR_RX_ANA_AEQ_CFG_4 0x85 +#define UB9702_IR_RX_ANA_EQ_CTRL_SEL_15 0x87 +#define UB9702_IR_RX_ANA_EQ_CTRL_SEL_24 0x90 +#define UB9702_IR_RX_ANA_EQ_CTRL_SEL_38 0x9e +#define UB9702_IR_RX_ANA_FPD3_CDR_CTRL_SEL_5 0xa5 +#define UB9702_IR_RX_ANA_FPD3_AEQ_CTRL_SEL_1 0xa8 +#define UB9702_IR_RX_ANA_EQ_OVERRIDE_CTRL 0xf0 +#define UB9702_IR_RX_ANA_VGA_CTRL_SEL_8 0xf1 + +#define UB9702_IR_CSI_ANA_CSIPLL_REG_1 0x92 + /* EQ related */
#define UB960_MIN_AEQ_STROBE_POS -7
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Split ub960_init_tx_ports() to a UB960 and a UB9702 versions to make it easier to update the UB9702 version in the following patch.
No funcional changes.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub960.c | 105 +++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 37 deletions(-)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index c56398aa895f05029879fb336bc52c932fee494d..579ca570a543a9ee8be8f9d4432a2da8fa09e54d 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -1992,67 +1992,98 @@ static int ub960_init_tx_port(struct ub960_data *priv, return ub960_txport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl, NULL); }
-static int ub960_init_tx_ports(struct ub960_data *priv) +static int ub960_init_tx_ports_ub960(struct ub960_data *priv) { - unsigned int nport; u8 speed_select; - u8 pll_div; - int ret = 0; - - /* TX ports */
switch (priv->tx_data_rate) { + case MHZ(400): + speed_select = 3; + break; + case MHZ(800): + speed_select = 2; + break; + case MHZ(1200): + speed_select = 1; + break; case MHZ(1600): default: speed_select = 0; - pll_div = 0x10; break; - case MHZ(1200): - speed_select = 1; - pll_div = 0x18; + } + + return ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select, NULL); +} + +static int ub960_init_tx_ports_ub9702(struct ub960_data *priv) +{ + u8 speed_select; + u8 pll_div; + int ret = 0; + + switch (priv->tx_data_rate) { + case MHZ(400): + speed_select = 3; + pll_div = 0x10; break; case MHZ(800): speed_select = 2; pll_div = 0x10; break; - case MHZ(400): - speed_select = 3; + case MHZ(1200): + speed_select = 1; + pll_div = 0x18; + break; + case MHZ(1600): + default: + speed_select = 0; pll_div = 0x10; break; }
ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select, &ret);
- if (priv->hw_data->is_ub9702) { - ub960_write(priv, UB9702_SR_CSI_PLL_DIV, pll_div, &ret); - - switch (priv->tx_data_rate) { - case MHZ(1600): - default: - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, - 0x80, &ret); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, - 0x2a, &ret); - break; - case MHZ(800): - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, - 0x90, &ret); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, - 0x2a, &ret); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, - 0x2a, &ret); - break; - case MHZ(400): - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, - 0xa0, &ret); - break; - } + ub960_write(priv, UB9702_SR_CSI_PLL_DIV, pll_div, &ret); + + switch (priv->tx_data_rate) { + case MHZ(1600): + default: + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x80, + &ret); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a, + &ret); + break; + case MHZ(800): + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x90, + &ret); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, 0x2a, + &ret); + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a, + &ret); + break; + case MHZ(400): + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0xa0, + &ret); + break; }
+ return ret; +} + +static int ub960_init_tx_ports(struct ub960_data *priv) +{ + int ret; + + if (priv->hw_data->is_ub9702) + ret = ub960_init_tx_ports_ub9702(priv); + else + ret = ub960_init_tx_ports_ub960(priv); + if (ret) return ret;
- for (nport = 0; nport < priv->hw_data->num_txports; nport++) { + for (unsigned int nport = 0; nport < priv->hw_data->num_txports; + nport++) { struct ub960_txport *txport = priv->txports[nport];
if (!txport)
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Refresh the ub960_init_tx_ports_ub9702() using the latest version of the (non-public) hardware documentation.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub960.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 579ca570a543a9ee8be8f9d4432a2da8fa09e54d..ed49508d2b79283a95f2f3315b53f21d4301b089 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -2018,6 +2018,7 @@ static int ub960_init_tx_ports_ub960(struct ub960_data *priv) static int ub960_init_tx_ports_ub9702(struct ub960_data *priv) { u8 speed_select; + u8 ana_pll_div; u8 pll_div; int ret = 0;
@@ -2025,47 +2026,40 @@ static int ub960_init_tx_ports_ub9702(struct ub960_data *priv) case MHZ(400): speed_select = 3; pll_div = 0x10; + ana_pll_div = 0xa2; break; case MHZ(800): speed_select = 2; pll_div = 0x10; + ana_pll_div = 0x92; break; case MHZ(1200): speed_select = 1; pll_div = 0x18; + ana_pll_div = 0x90; + break; + case MHZ(1500): + speed_select = 0; + pll_div = 0x0f; + ana_pll_div = 0x82; break; case MHZ(1600): default: speed_select = 0; pll_div = 0x10; + ana_pll_div = 0x82; + break; + case MHZ(2500): + speed_select = 0x10; + pll_div = 0x19; + ana_pll_div = 0x80; break; }
ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select, &ret); - ub960_write(priv, UB9702_SR_CSI_PLL_DIV, pll_div, &ret); - - switch (priv->tx_data_rate) { - case MHZ(1600): - default: - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x80, - &ret); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a, - &ret); - break; - case MHZ(800): - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x90, - &ret); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, 0x2a, - &ret); - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a, - &ret); - break; - case MHZ(400): - ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0xa0, - &ret); - break; - } + ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, + UB9702_IR_CSI_ANA_CSIPLL_REG_1, ana_pll_div, &ret);
return ret; }
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
The driver does a lot of iteration over the RX ports with for loops. In most cases the driver will skip unused RX ports. Also, in the future patches the FPD-Link IV support will be refreshed with TI's latest init sequences which involves a lot of additional iterations over the RX ports, often only for FPD-Link IV ports.
To make the iteration simpler and to make it clearer what we're iterating over (all or only-active, all or only-fpd4), add macros and support functions for iterating the RX ports. Use the macros in the driver, replacing the for loops.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub960.c | 260 ++++++++++++++++++++++-------------------- 1 file changed, 135 insertions(+), 125 deletions(-)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index ed49508d2b79283a95f2f3315b53f21d4301b089..af7ba1c824b12893bd31bed7a88a6e3bf8a62f7e 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -649,6 +649,63 @@ static const struct ub960_format_info *ub960_find_format(u32 code) return NULL; }
+struct ub960_rxport_iter { + unsigned int nport; + struct ub960_rxport *rxport; +}; + +enum ub960_iter_flags { + UB960_ITER_ACTIVE_ONLY = BIT(0), + UB960_ITER_FPD4_ONLY = BIT(1), +}; + +static struct ub960_rxport_iter ub960_iter_rxport(struct ub960_data *priv, + struct ub960_rxport_iter it, + enum ub960_iter_flags flags) +{ + for (; it.nport < priv->hw_data->num_rxports; it.nport++) { + it.rxport = priv->rxports[it.nport]; + + if ((flags & UB960_ITER_ACTIVE_ONLY) && !it.rxport) + continue; + + if ((flags & UB960_ITER_FPD4_ONLY) && + it.rxport->cdr_mode != RXPORT_CDR_FPD4) + continue; + + return it; + } + + it.rxport = NULL; + + return it; +} + +#define for_each_rxport(priv, it) \ + for (struct ub960_rxport_iter it = \ + ub960_iter_rxport(priv, (struct ub960_rxport_iter){ 0 }, \ + 0); \ + it.nport < (priv)->hw_data->num_rxports; \ + it.nport++, it = ub960_iter_rxport(priv, it, 0)) + +#define for_each_active_rxport(priv, it) \ + for (struct ub960_rxport_iter it = \ + ub960_iter_rxport(priv, (struct ub960_rxport_iter){ 0 }, \ + UB960_ITER_ACTIVE_ONLY); \ + it.nport < (priv)->hw_data->num_rxports; \ + it.nport++, it = ub960_iter_rxport(priv, it, \ + UB960_ITER_ACTIVE_ONLY)) + +#define for_each_active_rxport_fpd4(priv, it) \ + for (struct ub960_rxport_iter it = \ + ub960_iter_rxport(priv, (struct ub960_rxport_iter){ 0 }, \ + UB960_ITER_ACTIVE_ONLY | \ + UB960_ITER_FPD4_ONLY); \ + it.nport < (priv)->hw_data->num_rxports; \ + it.nport++, it = ub960_iter_rxport(priv, it, \ + UB960_ITER_ACTIVE_ONLY | \ + UB960_ITER_FPD4_ONLY)) + /* ----------------------------------------------------------------------------- * Basic device access */ @@ -1356,25 +1413,25 @@ static int ub960_csi_handle_events(struct ub960_data *priv, u8 nport)
static int ub960_rxport_enable_vpocs(struct ub960_data *priv) { - unsigned int nport; + unsigned int failed_nport; int ret;
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; - - if (!rxport || !rxport->vpoc) + for_each_active_rxport(priv, it) { + if (!it.rxport->vpoc) continue;
- ret = regulator_enable(rxport->vpoc); - if (ret) + ret = regulator_enable(it.rxport->vpoc); + if (ret) { + failed_nport = it.nport; goto err_disable_vpocs; + } }
return 0;
err_disable_vpocs: - while (nport--) { - struct ub960_rxport *rxport = priv->rxports[nport]; + while (failed_nport--) { + struct ub960_rxport *rxport = priv->rxports[failed_nport];
if (!rxport || !rxport->vpoc) continue; @@ -1387,15 +1444,11 @@ static int ub960_rxport_enable_vpocs(struct ub960_data *priv)
static void ub960_rxport_disable_vpocs(struct ub960_data *priv) { - unsigned int nport; - - for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; - - if (!rxport || !rxport->vpoc) + for_each_active_rxport(priv, it) { + if (!it.rxport->vpoc) continue;
- regulator_disable(rxport->vpoc); + regulator_disable(it.rxport->vpoc); } }
@@ -1420,12 +1473,10 @@ static int ub960_rxport_clear_errors(struct ub960_data *priv,
static int ub960_clear_rx_errors(struct ub960_data *priv) { - unsigned int nport; - - for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - int ret; + int ret;
- ret = ub960_rxport_clear_errors(priv, nport); + for_each_rxport(priv, it) { + ret = ub960_rxport_clear_errors(priv, it.nport); if (ret) return ret; } @@ -1928,30 +1979,27 @@ static void ub960_rxport_remove_serializer(struct ub960_data *priv, u8 nport) /* Add serializer i2c devices for all initialized ports */ static int ub960_rxport_add_serializers(struct ub960_data *priv) { - unsigned int nport; + unsigned int failed_nport; int ret;
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; - - if (!rxport) - continue; - - ret = ub960_rxport_add_serializer(priv, nport); - if (ret) + for_each_active_rxport(priv, it) { + ret = ub960_rxport_add_serializer(priv, it.nport); + if (ret) { + failed_nport = it.nport; goto err_remove_sers; + } }
return 0;
err_remove_sers: - while (nport--) { - struct ub960_rxport *rxport = priv->rxports[nport]; + while (failed_nport--) { + struct ub960_rxport *rxport = priv->rxports[failed_nport];
if (!rxport) continue;
- ub960_rxport_remove_serializer(priv, nport); + ub960_rxport_remove_serializer(priv, failed_nport); }
return ret; @@ -1959,16 +2007,8 @@ static int ub960_rxport_add_serializers(struct ub960_data *priv)
static void ub960_rxport_remove_serializers(struct ub960_data *priv) { - unsigned int nport; - - for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; - - if (!rxport) - continue; - - ub960_rxport_remove_serializer(priv, nport); - } + for_each_active_rxport(priv, it) + ub960_rxport_remove_serializer(priv, it.nport); }
static int ub960_init_tx_port(struct ub960_data *priv, @@ -2453,19 +2493,13 @@ static int ub960_init_rx_port_ub9702(struct ub960_data *priv,
static int ub960_init_rx_ports(struct ub960_data *priv) { - unsigned int nport; - - for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; + for_each_active_rxport(priv, it) { int ret;
- if (!rxport) - continue; - if (priv->hw_data->is_ub9702) - ret = ub960_init_rx_port_ub9702(priv, rxport); + ret = ub960_init_rx_port_ub9702(priv, it.rxport); else - ret = ub960_init_rx_port_ub960(priv, rxport); + ret = ub960_init_rx_port_ub960(priv, it.rxport);
if (ret) return ret; @@ -2683,20 +2717,14 @@ static int ub960_disable_rx_port(struct ub960_data *priv, unsigned int nport) */ static int ub960_validate_stream_vcs(struct ub960_data *priv) { - unsigned int nport; - unsigned int i; - - for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; + for_each_active_rxport(priv, it) { struct v4l2_mbus_frame_desc desc; int ret; u8 vc;
- if (!rxport) - continue; - - ret = v4l2_subdev_call(rxport->source.sd, pad, get_frame_desc, - rxport->source.pad, &desc); + ret = v4l2_subdev_call(it.rxport->source.sd, pad, + get_frame_desc, it.rxport->source.pad, + &desc); if (ret) return ret;
@@ -2708,13 +2736,13 @@ static int ub960_validate_stream_vcs(struct ub960_data *priv)
vc = desc.entry[0].bus.csi2.vc;
- for (i = 1; i < desc.num_entries; i++) { + for (unsigned int i = 1; i < desc.num_entries; i++) { if (vc == desc.entry[i].bus.csi2.vc) continue;
dev_err(&priv->client->dev, "rx%u: source with multiple virtual-channels is not supported\n", - nport); + it.nport); return -ENODEV; } } @@ -2804,21 +2832,21 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv, */ fwd_ctl = GENMASK(7, 4);
- for (unsigned int nport = 0; nport < priv->hw_data->num_rxports; - nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; + for_each_active_rxport(priv, it) { + unsigned long nport = it.nport; + u8 vc = vc_map[nport];
if (rx_data[nport].num_streams == 0) continue;
- switch (rxport->rx_mode) { + switch (it.rxport->rx_mode) { case RXPORT_MODE_RAW10: ub960_rxport_write(priv, nport, UB960_RR_RAW10_ID, rx_data[nport].pixel_dt | (vc << UB960_RR_RAW10_ID_VC_SHIFT), &ret);
- ub960_rxport_write(priv, rxport->nport, + ub960_rxport_write(priv, nport, UB960_RR_RAW_EMBED_DTYPE, (rx_data[nport].meta_lines << UB960_RR_RAW_EMBED_DTYPE_LINES_SHIFT) | rx_data[nport].meta_dt, &ret); @@ -2886,7 +2914,6 @@ static int ub960_enable_streams(struct v4l2_subdev *sd, u64 sink_streams[UB960_MAX_RX_NPORTS] = {}; struct v4l2_subdev_route *route; unsigned int failed_port; - unsigned int nport; int ret;
if (!priv->streaming) { @@ -2908,6 +2935,8 @@ static int ub960_enable_streams(struct v4l2_subdev *sd,
/* Collect sink streams per pad which we need to enable */ for_each_active_route(&state->routing, route) { + unsigned int nport; + if (route->source_pad != source_pad) continue;
@@ -2919,7 +2948,9 @@ static int ub960_enable_streams(struct v4l2_subdev *sd, sink_streams[nport] |= BIT_ULL(route->sink_stream); }
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { + for_each_rxport(priv, it) { + unsigned int nport = it.nport; + if (!sink_streams[nport]) continue;
@@ -2957,7 +2988,7 @@ static int ub960_enable_streams(struct v4l2_subdev *sd, return 0;
err: - for (nport = 0; nport < failed_port; nport++) { + for (unsigned int nport = 0; nport < failed_port; nport++) { if (!sink_streams[nport]) continue;
@@ -2997,11 +3028,12 @@ static int ub960_disable_streams(struct v4l2_subdev *sd, struct device *dev = &priv->client->dev; u64 sink_streams[UB960_MAX_RX_NPORTS] = {}; struct v4l2_subdev_route *route; - unsigned int nport; int ret;
/* Collect sink streams per pad which we need to disable */ for_each_active_route(&state->routing, route) { + unsigned int nport; + if (route->source_pad != source_pad) continue;
@@ -3013,7 +3045,9 @@ static int ub960_disable_streams(struct v4l2_subdev *sd, sink_streams[nport] |= BIT_ULL(route->sink_stream); }
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { + for_each_rxport(priv, it) { + unsigned int nport = it.nport; + if (!sink_streams[nport]) continue;
@@ -3335,7 +3369,6 @@ static int ub960_log_status(struct v4l2_subdev *sd) struct ub960_data *priv = sd_to_ub960(sd); struct device *dev = &priv->client->dev; struct v4l2_subdev_state *state; - unsigned int nport; u16 v16 = 0; u8 v = 0; u8 id[UB960_SR_FPD3_RX_ID_LEN]; @@ -3351,7 +3384,8 @@ static int ub960_log_status(struct v4l2_subdev *sd)
dev_info(dev, "ID '%.*s'\n", (int)sizeof(id), id);
- for (nport = 0; nport < priv->hw_data->num_txports; nport++) { + for (unsigned int nport = 0; nport < priv->hw_data->num_txports; + nport++) { struct ub960_txport *txport = priv->txports[nport];
dev_info(dev, "TX %u\n", nport); @@ -3397,12 +3431,12 @@ static int ub960_log_status(struct v4l2_subdev *sd) dev_info(dev, "\tline error counter %u\n", v16); }
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; + for_each_rxport(priv, it) { + unsigned int nport = it.nport;
dev_info(dev, "RX %u\n", nport);
- if (!rxport) { + if (!it.rxport) { dev_info(dev, "\tNot initialized\n"); continue; } @@ -3514,7 +3548,6 @@ static const struct media_entity_operations ub960_entity_ops = { static irqreturn_t ub960_handle_events(int irq, void *arg) { struct ub960_data *priv = arg; - unsigned int i; u8 int_sts; u8 fwd_sts; int ret; @@ -3531,7 +3564,7 @@ static irqreturn_t ub960_handle_events(int irq, void *arg)
dev_dbg(&priv->client->dev, "FWD_STS %#02x\n", fwd_sts);
- for (i = 0; i < priv->hw_data->num_txports; i++) { + for (unsigned int i = 0; i < priv->hw_data->num_txports; i++) { if (int_sts & UB960_SR_INTERRUPT_STS_IS_CSI_TX(i)) { ret = ub960_csi_handle_events(priv, i); if (ret) @@ -3539,12 +3572,9 @@ static irqreturn_t ub960_handle_events(int irq, void *arg) } }
- for (i = 0; i < priv->hw_data->num_rxports; i++) { - if (!priv->rxports[i]) - continue; - - if (int_sts & UB960_SR_INTERRUPT_STS_IS_RX(i)) { - ret = ub960_rxport_handle_events(priv, i); + for_each_active_rxport(priv, it) { + if (int_sts & UB960_SR_INTERRUPT_STS_IS_RX(it.nport)) { + ret = ub960_rxport_handle_events(priv, it.nport); if (ret) return IRQ_NONE; } @@ -3582,19 +3612,12 @@ static void ub960_txport_free_ports(struct ub960_data *priv)
static void ub960_rxport_free_ports(struct ub960_data *priv) { - unsigned int nport; - - for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; - - if (!rxport) - continue; - - fwnode_handle_put(rxport->source.ep_fwnode); - fwnode_handle_put(rxport->ser.fwnode); + for_each_active_rxport(priv, it) { + fwnode_handle_put(it.rxport->source.ep_fwnode); + fwnode_handle_put(it.rxport->ser.fwnode);
- kfree(rxport); - priv->rxports[nport] = NULL; + kfree(it.rxport); + priv->rxports[it.nport] = NULL; } }
@@ -3853,7 +3876,6 @@ static int ub960_parse_dt_rxports(struct ub960_data *priv) { struct device *dev = &priv->client->dev; struct fwnode_handle *links_fwnode; - unsigned int nport; int ret;
links_fwnode = fwnode_get_named_child_node(dev_fwnode(dev), "links"); @@ -3868,9 +3890,10 @@ static int ub960_parse_dt_rxports(struct ub960_data *priv)
priv->strobe.manual = fwnode_property_read_bool(links_fwnode, "ti,manual-strobe");
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { + for_each_rxport(priv, it) { struct fwnode_handle *link_fwnode; struct fwnode_handle *ep_fwnode; + unsigned int nport = it.nport;
link_fwnode = ub960_fwnode_get_link_by_regs(links_fwnode, nport); if (!link_fwnode) @@ -3959,7 +3982,6 @@ static int ub960_notify_bound(struct v4l2_async_notifier *notifier, struct ub960_rxport *rxport = to_ub960_asd(asd)->rxport; struct device *dev = &priv->client->dev; u8 nport = rxport->nport; - unsigned int i; int ret;
ret = media_entity_get_fwnode_pad(&subdev->entity, @@ -3984,8 +4006,8 @@ static int ub960_notify_bound(struct v4l2_async_notifier *notifier, return ret; }
- for (i = 0; i < priv->hw_data->num_rxports; i++) { - if (priv->rxports[i] && !priv->rxports[i]->source.sd) { + for_each_active_rxport(priv, it) { + if (!it.rxport->source.sd) { dev_dbg(dev, "Waiting for more subdevs to be bound\n"); return 0; } @@ -4011,29 +4033,24 @@ static const struct v4l2_async_notifier_operations ub960_notify_ops = { static int ub960_v4l2_notifier_register(struct ub960_data *priv) { struct device *dev = &priv->client->dev; - unsigned int i; int ret;
v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
- for (i = 0; i < priv->hw_data->num_rxports; i++) { - struct ub960_rxport *rxport = priv->rxports[i]; + for_each_active_rxport(priv, it) { struct ub960_asd *asd;
- if (!rxport) - continue; - asd = v4l2_async_nf_add_fwnode(&priv->notifier, - rxport->source.ep_fwnode, + it.rxport->source.ep_fwnode, struct ub960_asd); if (IS_ERR(asd)) { dev_err(dev, "Failed to add subdev for source %u: %pe", - i, asd); + it.nport, asd); v4l2_async_nf_cleanup(&priv->notifier); return PTR_ERR(asd); }
- asd->rxport = rxport; + asd->rxport = it.rxport; }
priv->notifier.ops = &ub960_notify_ops; @@ -4304,7 +4321,6 @@ static int ub960_probe(struct i2c_client *client) struct ub960_data *priv; unsigned int port_lock_mask; unsigned int port_mask; - unsigned int nport; int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -4357,14 +4373,8 @@ static int ub960_probe(struct i2c_client *client)
port_mask = 0;
- for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { - struct ub960_rxport *rxport = priv->rxports[nport]; - - if (!rxport) - continue; - - port_mask |= BIT(nport); - } + for_each_active_rxport(priv, it) + port_mask |= BIT(it.nport);
ret = ub960_rxport_wait_locks(priv, port_mask, &port_lock_mask); if (ret) @@ -4403,9 +4413,9 @@ static int ub960_probe(struct i2c_client *client) msecs_to_jiffies(UB960_POLL_TIME_MS));
#ifdef UB960_DEBUG_I2C_RX_ID - for (unsigned int i = 0; i < priv->hw_data->num_rxports; i++) - ub960_write(priv, UB960_SR_I2C_RX_ID(i), - (UB960_DEBUG_I2C_RX_ID + i) << 1, NULL); + for_each_rxport(priv, it) + ub960_write(priv, UB960_SR_I2C_RX_ID(it.nport), + (UB960_DEBUG_I2C_RX_ID + it.nport) << 1, NULL); #endif
return 0;
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
We have some code in probe() which is related to RX port initialization, and should be in ub960_init_rx_ports(). Move the code there.
We also move ub960_reset() so that it is accessible from ub960_init_rx_ports().
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub960.c | 115 ++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 56 deletions(-)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index af7ba1c824b12893bd31bed7a88a6e3bf8a62f7e..130bf4cc0a7485e997dd979954a9b6d28b693a5a 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -1225,6 +1225,33 @@ static int ub960_ind_update_bits(struct ub960_data *priv, u8 block, u8 reg, return ret; }
+static int ub960_reset(struct ub960_data *priv, bool reset_regs) +{ + struct device *dev = &priv->client->dev; + unsigned int v; + int ret; + u8 bit; + + bit = reset_regs ? UB960_SR_RESET_DIGITAL_RESET1 : + UB960_SR_RESET_DIGITAL_RESET0; + + ret = ub960_write(priv, UB960_SR_RESET, bit, NULL); + if (ret) + return ret; + + mutex_lock(&priv->reg_lock); + + ret = regmap_read_poll_timeout(priv->regmap, UB960_SR_RESET, v, + (v & bit) == 0, 2000, 100000); + + mutex_unlock(&priv->reg_lock); + + if (ret) + dev_err(dev, "reset failed: %d\n", ret); + + return ret; +} + /* ----------------------------------------------------------------------------- * I2C-ATR (address translator) */ @@ -2493,6 +2520,11 @@ static int ub960_init_rx_port_ub9702(struct ub960_data *priv,
static int ub960_init_rx_ports(struct ub960_data *priv) { + struct device *dev = &priv->client->dev; + unsigned int port_lock_mask; + unsigned int port_mask; + int ret; + for_each_active_rxport(priv, it) { int ret;
@@ -2505,6 +2537,33 @@ static int ub960_init_rx_ports(struct ub960_data *priv) return ret; }
+ ret = ub960_reset(priv, false); + if (ret) + return ret; + + port_mask = 0; + + for_each_active_rxport(priv, it) + port_mask |= BIT(it.nport); + + ret = ub960_rxport_wait_locks(priv, port_mask, &port_lock_mask); + if (ret) + return ret; + + if (port_mask != port_lock_mask) { + ret = -EIO; + dev_err_probe(dev, ret, "Failed to lock all RX ports\n"); + return ret; + } + + /* + * Clear any errors caused by switching the RX port settings while + * probing. + */ + ret = ub960_clear_rx_errors(priv); + if (ret) + return ret; + return 0; }
@@ -4168,33 +4227,6 @@ static const struct regmap_config ub960_regmap_config = { .disable_locking = true, };
-static int ub960_reset(struct ub960_data *priv, bool reset_regs) -{ - struct device *dev = &priv->client->dev; - unsigned int v; - int ret; - u8 bit; - - bit = reset_regs ? UB960_SR_RESET_DIGITAL_RESET1 : - UB960_SR_RESET_DIGITAL_RESET0; - - ret = ub960_write(priv, UB960_SR_RESET, bit, NULL); - if (ret) - return ret; - - mutex_lock(&priv->reg_lock); - - ret = regmap_read_poll_timeout(priv->regmap, UB960_SR_RESET, v, - (v & bit) == 0, 2000, 100000); - - mutex_unlock(&priv->reg_lock); - - if (ret) - dev_err(dev, "reset failed: %d\n", ret); - - return ret; -} - static int ub960_get_hw_resources(struct ub960_data *priv) { struct device *dev = &priv->client->dev; @@ -4319,8 +4351,6 @@ static int ub960_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ub960_data *priv; - unsigned int port_lock_mask; - unsigned int port_mask; int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -4367,33 +4397,6 @@ static int ub960_probe(struct i2c_client *client) if (ret) goto err_disable_vpocs;
- ret = ub960_reset(priv, false); - if (ret) - goto err_disable_vpocs; - - port_mask = 0; - - for_each_active_rxport(priv, it) - port_mask |= BIT(it.nport); - - ret = ub960_rxport_wait_locks(priv, port_mask, &port_lock_mask); - if (ret) - goto err_disable_vpocs; - - if (port_mask != port_lock_mask) { - ret = -EIO; - dev_err_probe(dev, ret, "Failed to lock all RX ports\n"); - goto err_disable_vpocs; - } - - /* - * Clear any errors caused by switching the RX port settings while - * probing. - */ - ret = ub960_clear_rx_errors(priv); - if (ret) - goto err_disable_vpocs; - ret = ub960_init_atr(priv); if (ret) goto err_disable_vpocs;
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Update ub9702 RX port init sequence according to TI's latest (non-public) documentation. The sequence is based on a Python script provided by TI.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- Changes from v2: - This patch was previously split for easier review, squash it now. --- drivers/media/i2c/ds90ub960.c | 848 ++++++++++++++++++++++++++++++++---------- 1 file changed, 658 insertions(+), 190 deletions(-)
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 130bf4cc0a7485e997dd979954a9b6d28b693a5a..56b1a88c1c29fbefecae60f4c9976e8ede554447 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -243,6 +243,7 @@ #define UB960_RR_BIST_ERR_COUNT 0x57
#define UB960_RR_BCC_CONFIG 0x58 +#define UB960_RR_BCC_CONFIG_BC_ALWAYS_ON BIT(4) #define UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH BIT(6) #define UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK GENMASK(2, 0)
@@ -1788,6 +1789,23 @@ static int ub960_rxport_link_ok(struct ub960_data *priv, unsigned int nport, return 0; }
+static int ub960_rxport_lockup_wa_ub9702(struct ub960_data *priv) +{ + int ret; + + /* Toggle PI_MODE to avoid possible FPD RX lockup */ + + ret = ub960_update_bits(priv, UB9702_RR_CHANNEL_MODE, GENMASK(4, 3), + 2 << 3, NULL); + if (ret) + return ret; + + usleep_range(1000, 5000); + + return ub960_update_bits(priv, UB9702_RR_CHANNEL_MODE, GENMASK(4, 3), + 0, NULL); +} + /* * Wait for the RX ports to lock, have no errors and have stable strobe position * and EQ level. @@ -1818,6 +1836,7 @@ static int ub960_rxport_wait_locks(struct ub960_data *priv, link_ok_mask = 0;
while (time_before(jiffies, timeout)) { + bool fpd4_wa = false; missing = 0;
for_each_set_bit(nport, &port_mask, @@ -1832,6 +1851,9 @@ static int ub960_rxport_wait_locks(struct ub960_data *priv, if (ret) return ret;
+ if (!ok && rxport->cdr_mode == RXPORT_CDR_FPD4) + fpd4_wa = true; + /* * We want the link to be ok for two consecutive loops, * as a link could get established just before our test @@ -1851,6 +1873,12 @@ static int ub960_rxport_wait_locks(struct ub960_data *priv, if (missing == 0) break;
+ if (fpd4_wa) { + ret = ub960_rxport_lockup_wa_ub9702(priv); + if (ret) + return ret; + } + /* * The sleep time of 10 ms was found by testing to give a lock * with a few iterations. It can be decreased if on some setups @@ -2257,294 +2285,691 @@ static int ub960_init_rx_port_ub960(struct ub960_data *priv, return ret; }
-static int ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_init_rx_ports_ub960(struct ub960_data *priv) { - unsigned int nport = rxport->nport; - u8 bc_freq_val; - u8 fpd_func_mode; - int ret = 0; + struct device *dev = &priv->client->dev; + unsigned int port_lock_mask; + unsigned int port_mask; + int ret;
- switch (rxport->rx_mode) { - case RXPORT_MODE_RAW10: - bc_freq_val = 0; - fpd_func_mode = 5; - break; + for_each_active_rxport(priv, it) { + ret = ub960_init_rx_port_ub960(priv, it.rxport); + if (ret) + return ret; + }
- case RXPORT_MODE_RAW12_HF: - bc_freq_val = 0; - fpd_func_mode = 4; - break; + ret = ub960_reset(priv, false); + if (ret) + return ret;
- case RXPORT_MODE_RAW12_LF: - bc_freq_val = 0; - fpd_func_mode = 6; - break; + port_mask = 0;
- case RXPORT_MODE_CSI2_SYNC: - bc_freq_val = 6; - fpd_func_mode = 2; - break; + for_each_active_rxport(priv, it) + port_mask |= BIT(it.nport);
- case RXPORT_MODE_CSI2_NONSYNC: - bc_freq_val = 2; - fpd_func_mode = 2; - break; + ret = ub960_rxport_wait_locks(priv, port_mask, &port_lock_mask); + if (ret) + return ret;
- default: - return -EINVAL; + if (port_mask != port_lock_mask) { + ret = -EIO; + dev_err_probe(dev, ret, "Failed to lock all RX ports\n"); + return ret; }
- ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, - bc_freq_val, &ret); - ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, fpd_func_mode, - &ret); + /* + * Clear any errors caused by switching the RX port settings while + * probing. + */ + ret = ub960_clear_rx_errors(priv); + if (ret) + return ret;
- /* set serdes_eq_mode = 1 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa8, 0x80, - &ret); + return 0; +}
- /* enable serdes driver */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x0d, 0x7f, - &ret); +/* + * UB9702 specific initial RX port configuration + */
- /* set serdes_eq_offset=4 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04, - &ret); +static int ub960_turn_off_rxport_ub9702(struct ub960_data *priv, + unsigned int nport) +{ + int ret = 0;
- /* init default serdes_eq_max in 0xa9 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa9, 0x23, - &ret); + /* Disable RX port */ + ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), 0, &ret); + + /* Disable FPD Rx and FPD BC CMR */ + ub960_rxport_write(priv, nport, UB9702_RR_RX_CTL_2, 0x1b, &ret); + + /* Disable FPD BC Tx */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, BIT(4), 0, + &ret); + + /* Disable internal RX blocks */ + ub960_rxport_write(priv, nport, UB9702_RR_RX_CTL_1, 0x15, &ret); + + /* Disable AEQ */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_CFG_2, 0x03, &ret);
- /* init serdes_eq_min in 0xaa */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xaa, 0, &ret); + /* PI disabled and oDAC disabled */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_CFG_4, 0x09, &ret);
- /* serdes_driver_ctl2 control: DS90UB953-Q1/DS90UB933-Q1/DS90UB913A-Q1 */ - ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, - BIT(3), BIT(3), &ret); + /* AEQ configured for disabled link */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_CFG_1, 0x20, &ret);
- /* RX port to half-rate */ - ub960_update_bits(priv, UB9702_SR_FPD_RATE_CFG, 0x3 << (nport * 2), - BIT(nport * 2), &ret); + /* disable AEQ clock and DFE */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_CFG_3, 0x45, &ret); + + /* Powerdown FPD3 CDR */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_FPD3_CDR_CTRL_SEL_5, 0x82, &ret);
return ret; }
-static int ub960_init_rx_port_ub9702_fpd4_aeq(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_set_bc_drv_config_ub9702(struct ub960_data *priv, + unsigned int nport) { - unsigned int nport = rxport->nport; - bool first_time_power_up = true; + u8 fpd_bc_ctl0; + u8 fpd_bc_ctl1; + u8 fpd_bc_ctl2; int ret = 0;
- if (first_time_power_up) { - u8 v; - - /* AEQ init */ - ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2c, &v, - &ret); + if (priv->rxports[nport]->cdr_mode == RXPORT_CDR_FPD4) { + /* Set FPD PBC drv into FPD IV mode */
- ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, v, - &ret); - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, - v + 1, &ret); + fpd_bc_ctl0 = 0; + fpd_bc_ctl1 = 0; + fpd_bc_ctl2 = 0; + } else { + /* Set FPD PBC drv into FPD III mode */
- ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, - 0x00, &ret); + fpd_bc_ctl0 = 2; + fpd_bc_ctl1 = 1; + fpd_bc_ctl2 = 5; }
- /* enable serdes_eq_ctl2 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x9e, 0x00, - &ret); + ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_FPD_BC_CTL0, GENMASK(7, 5), + fpd_bc_ctl0 << 5, &ret);
- /* enable serdes_eq_ctl1 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x90, 0x40, - &ret); + ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_FPD_BC_CTL1, BIT(6), + fpd_bc_ctl1 << 6, &ret);
- /* enable serdes_eq_en */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2e, 0x40, - &ret); + ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_FPD_BC_CTL2, GENMASK(6, 3), + fpd_bc_ctl2 << 3, &ret);
- /* disable serdes_eq_override */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xf0, 0x00, - &ret); + return ret; +}
- /* disable serdes_gain_override */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x71, 0x00, - &ret); +static int ub960_set_fpd4_sync_mode_ub9702(struct ub960_data *priv, + unsigned int nport) +{ + int ret = 0; + + /* FPD4 Sync Mode */ + ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, 0x0, &ret); + + /* BC_FREQ_SELECT = (PLL_FREQ/3200) Mbps */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, 6, &ret); + + if (ret) + return ret; + + ret = ub960_set_bc_drv_config_ub9702(priv, nport); + if (ret) + return ret; + + /* Set AEQ timer to 400us/step */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_SYSTEM_INIT_REG0, 0x2f, &ret); + + /* Disable FPD4 Auto Recovery */ + ub960_update_bits(priv, UB9702_SR_CSI_EXCLUSIVE_FWD2, GENMASK(5, 4), 0, + &ret); + + /* Enable RX port */ + ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), + &ret); + + /* Enable FPD4 Auto Recovery */ + ub960_update_bits(priv, UB9702_SR_CSI_EXCLUSIVE_FWD2, GENMASK(5, 4), + BIT(4), &ret);
return ret; }
-static int ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_set_fpd4_async_mode_ub9702(struct ub960_data *priv, + unsigned int nport) { - unsigned int nport = rxport->nport; - u8 bc_freq_val; int ret = 0;
- switch (rxport->rx_mode) { - case RXPORT_MODE_RAW10: - bc_freq_val = 0; - break; + /* FPD4 ASync Mode */ + ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, 0x1, &ret);
- case RXPORT_MODE_RAW12_HF: - bc_freq_val = 0; - break; + /* 10Mbps w/ BC enabled */ + /* BC_FREQ_SELECT=(PLL_FREQ/3200) Mbps */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, 2, &ret);
- case RXPORT_MODE_RAW12_LF: - bc_freq_val = 0; - break; + if (ret) + return ret;
- case RXPORT_MODE_CSI2_SYNC: - bc_freq_val = 6; - break; + ret = ub960_set_bc_drv_config_ub9702(priv, nport); + if (ret) + return ret;
- case RXPORT_MODE_CSI2_NONSYNC: - bc_freq_val = 2; - break; + /* Set AEQ timer to 400us/step */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_SYSTEM_INIT_REG0, 0x2f, &ret);
- default: - return -EINVAL; - } + /* Disable FPD4 Auto Recover */ + ub960_update_bits(priv, UB9702_SR_CSI_EXCLUSIVE_FWD2, GENMASK(5, 4), 0, + &ret);
- ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, - bc_freq_val, &ret); + /* Enable RX port */ + ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), + &ret);
- /* FPD4 Sync Mode */ - ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, 0, &ret); + /* Enable FPD4 Auto Recovery */ + ub960_update_bits(priv, UB9702_SR_CSI_EXCLUSIVE_FWD2, GENMASK(5, 4), + BIT(4), &ret);
- /* add serdes_eq_offset of 4 */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04, - &ret); + return ret; +}
- /* FPD4 serdes_start_eq in 0x27: assign default */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, 0x0, &ret); - /* FPD4 serdes_end_eq in 0x28: assign default */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, 0x23, - &ret); +static int ub960_set_fpd3_sync_mode_ub9702(struct ub960_data *priv, + unsigned int nport) +{ + int ret = 0;
- /* set serdes_driver_mode into FPD IV mode */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x04, 0x00, - &ret); - /* set FPD PBC drv into FPD IV mode */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, 0x00, - &ret); + /* FPD3 Sync Mode */ + ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, 0x2, &ret);
- /* set serdes_system_init to 0x2f */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x21, 0x2f, - &ret); - /* set serdes_system_rst in reset mode */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0xc1, - &ret); + /* BC_FREQ_SELECT=(PLL_FREQ/3200) Mbps */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, 6, &ret);
- /* RX port to 7.55G mode */ - ub960_update_bits(priv, UB9702_SR_FPD_RATE_CFG, 0x3 << (nport * 2), - 0 << (nport * 2), &ret); + /* Set AEQ_LOCK_MODE = 1 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_FPD3_AEQ_CTRL_SEL_1, BIT(7), &ret);
if (ret) return ret;
- ret = ub960_init_rx_port_ub9702_fpd4_aeq(priv, rxport); + ret = ub960_set_bc_drv_config_ub9702(priv, nport); if (ret) return ret;
- return 0; + /* Enable RX port */ + ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), + &ret); + + return ret; }
-static int ub960_init_rx_port_ub9702(struct ub960_data *priv, - struct ub960_rxport *rxport) +static int ub960_set_raw10_dvp_mode_ub9702(struct ub960_data *priv, + unsigned int nport) { - unsigned int nport = rxport->nport; - int ret; + int ret = 0;
- if (rxport->cdr_mode == RXPORT_CDR_FPD3) - ret = ub960_init_rx_port_ub9702_fpd3(priv, rxport); - else /* RXPORT_CDR_FPD4 */ - ret = ub960_init_rx_port_ub9702_fpd4(priv, rxport); + /* FPD3 RAW10 Mode */ + ub960_rxport_write(priv, nport, UB9702_RR_CHANNEL_MODE, 0x5, &ret); + + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, 0, &ret); + + /* Set AEQ_LOCK_MODE = 1 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_FPD3_AEQ_CTRL_SEL_1, BIT(7), &ret); + + /* + * RAW10_8BIT_CTL = 0b11 : 8-bit processing using lower 8 bits + * 0b10 : 8-bit processing using upper 8 bits + */ + ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3 << 6, + 0x2 << 6, &ret); + + /* LV_POLARITY & FV_POLARITY */ + ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, + priv->rxports[nport]->lv_fv_pol, &ret);
if (ret) return ret;
- switch (rxport->rx_mode) { - case RXPORT_MODE_RAW10: - /* - * RAW10_8BIT_CTL = 0b11 : 8-bit processing using lower 8 bits - * 0b10 : 8-bit processing using upper 8 bits - */ - ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, - 0x3 << 6, 0x2 << 6, &ret); + ret = ub960_set_bc_drv_config_ub9702(priv, nport); + if (ret) + return ret; + + /* Enable RX port */ + ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), + &ret); + + return ret; +} + +static int ub960_configure_rx_port_ub9702(struct ub960_data *priv, + unsigned int nport) +{ + struct device *dev = &priv->client->dev; + struct ub960_rxport *rxport = priv->rxports[nport]; + int ret; + + if (!rxport) { + ret = ub960_turn_off_rxport_ub9702(priv, nport); + if (ret) + return ret;
+ dev_dbg(dev, "rx%u: disabled\n", nport); + return 0; + } + + switch (rxport->cdr_mode) { + case RXPORT_CDR_FPD4: + switch (rxport->rx_mode) { + case RXPORT_MODE_CSI2_SYNC: + ret = ub960_set_fpd4_sync_mode_ub9702(priv, nport); + if (ret) + return ret; + + dev_dbg(dev, "rx%u: FPD-Link IV SYNC mode\n", nport); + break; + case RXPORT_MODE_CSI2_NONSYNC: + ret = ub960_set_fpd4_async_mode_ub9702(priv, nport); + if (ret) + return ret; + + dev_dbg(dev, "rx%u: FPD-Link IV ASYNC mode\n", nport); + break; + default: + dev_err(dev, "rx%u: unsupported FPD4 mode %u\n", nport, + rxport->rx_mode); + return -EINVAL; + } break;
- case RXPORT_MODE_RAW12_HF: - case RXPORT_MODE_RAW12_LF: - /* Not implemented */ - return -EINVAL; + case RXPORT_CDR_FPD3: + switch (rxport->rx_mode) { + case RXPORT_MODE_CSI2_SYNC: + ret = ub960_set_fpd3_sync_mode_ub9702(priv, nport); + if (ret) + return ret;
- case RXPORT_MODE_CSI2_SYNC: - case RXPORT_MODE_CSI2_NONSYNC: + dev_dbg(dev, "rx%u: FPD-Link III SYNC mode\n", nport); + break; + case RXPORT_MODE_RAW10: + ret = ub960_set_raw10_dvp_mode_ub9702(priv, nport); + if (ret) + return ret;
+ dev_dbg(dev, "rx%u: FPD-Link III RAW10 DVP mode\n", + nport); + break; + default: + dev_err(&priv->client->dev, + "rx%u: unsupported FPD3 mode %u\n", nport, + rxport->rx_mode); + return -EINVAL; + } break; + + default: + dev_err(&priv->client->dev, "rx%u: unsupported CDR mode %u\n", + nport, rxport->cdr_mode); + return -EINVAL; }
- /* LV_POLARITY & FV_POLARITY */ - ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, - rxport->lv_fv_pol, &ret); + return 0; +}
- /* Enable all interrupt sources from this port */ - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07, &ret); - ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f, &ret); +static int ub960_lock_recovery_ub9702(struct ub960_data *priv, + unsigned int nport) +{ + struct device *dev = &priv->client->dev; + /* Assumption that max AEQ should be under 16 */ + const u8 rx_aeq_limit = 16; + u8 prev_aeq = 0xff; + bool rx_lock; + + for (unsigned int retry = 0; retry < 3; ++retry) { + u8 port_sts1; + u8 rx_aeq; + int ret;
- /* Enable I2C_PASS_THROUGH */ - ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, - UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, - UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, &ret); + ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, + &port_sts1, NULL); + if (ret) + return ret;
- /* Enable I2C communication to the serializer via the alias addr */ - ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, - rxport->ser.alias << 1, &ret); + rx_lock = port_sts1 & UB960_RR_RX_PORT_STS1_PORT_PASS;
- /* Enable RX port */ - ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport), - &ret); + if (!rx_lock) { + ret = ub960_rxport_lockup_wa_ub9702(priv); + if (ret) + return ret; + + /* Restart AEQ by changing max to 0 --> 0x23 */ + ret = ub960_write_ind(priv, + UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL7, 0, + NULL); + if (ret) + return ret; + + msleep(20); + + /* AEQ Restart */ + ret = ub960_write_ind(priv, + UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL7, + 0x23, NULL); + + if (ret) + return ret;
- if (rxport->cdr_mode == RXPORT_CDR_FPD4) { - /* unreset 960 AEQ */ - ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, - 0x41, &ret); + msleep(20); + dev_dbg(dev, "rx%u: no lock, retry = %u\n", nport, + retry); + + continue; + } + + ret = ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL11, &rx_aeq, + NULL); + if (ret) + return ret; + + if (rx_aeq < rx_aeq_limit) { + dev_dbg(dev, + "rx%u: locked and AEQ normal before setting AEQ window\n", + nport); + return 0; + } + + if (rx_aeq != prev_aeq) { + ret = ub960_rxport_lockup_wa_ub9702(priv); + if (ret) + return ret; + + /* Restart AEQ by changing max to 0 --> 0x23 */ + ret = ub960_write_ind(priv, + UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL7, + 0, NULL); + if (ret) + return ret; + + msleep(20); + + /* AEQ Restart */ + ret = ub960_write_ind(priv, + UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL7, + 0x23, NULL); + if (ret) + return ret; + + msleep(20); + + dev_dbg(dev, + "rx%u: high AEQ at initial check recovery loop, retry=%u\n", + nport, retry); + + prev_aeq = rx_aeq; + } else { + dev_dbg(dev, + "rx%u: lossy cable detected, RX_AEQ %#x, RX_AEQ_LIMIT %#x, retry %u\n", + nport, rx_aeq, rx_aeq_limit, retry); + dev_dbg(dev, + "rx%u: will continue with initiation sequence but high AEQ\n", + nport); + return 0; + } }
- return ret; + dev_err(dev, "rx%u: max number of retries: %s\n", nport, + rx_lock ? "unstable AEQ" : "no lock"); + + return -EIO; }
-static int ub960_init_rx_ports(struct ub960_data *priv) +static int ub960_enable_aeq_lms_ub9702(struct ub960_data *priv, + unsigned int nport) +{ + struct device *dev = &priv->client->dev; + u8 read_aeq_init; + int ret; + + ret = ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL11, &read_aeq_init, + NULL); + if (ret) + return ret; + + dev_dbg(dev, "rx%u: initial AEQ = %#x\n", nport, read_aeq_init); + + /* Set AEQ Min */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL6, read_aeq_init, &ret); + /* Set AEQ Max */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL7, read_aeq_init + 1, &ret); + /* Set AEQ offset to 0 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL10, 0x0, &ret); + + /* Enable AEQ tap2 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_EQ_CTRL_SEL_38, 0x00, &ret); + /* Set VGA Gain 1 Gain 2 override to 0 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_VGA_CTRL_SEL_8, 0x00, &ret); + /* Set VGA Initial Sweep Gain to 0 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_VGA_CTRL_SEL_6, 0x80, &ret); + /* Set VGA_Adapt (VGA Gain) override to 0 (thermometer encoded) */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_VGA_CTRL_SEL_3, 0x00, &ret); + /* Enable VGA_SWEEP */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_EQ_ADAPT_CTRL, 0x40, &ret); + /* Disable VGA_SWEEP_GAIN_OV, disable VGA_TUNE_OV */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_EQ_OVERRIDE_CTRL, 0x00, &ret); + + /* Set VGA HIGH Threshold to 43 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_VGA_CTRL_SEL_1, 0x2b, &ret); + /* Set VGA LOW Threshold to 18 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_VGA_CTRL_SEL_2, 0x12, &ret); + /* Set vga_sweep_th to 32 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_EQ_CTRL_SEL_15, 0x20, &ret); + /* Set AEQ timer to 400us/step and parity threshold to 7 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_SYSTEM_INIT_REG0, 0xef, &ret); + + if (ret) + return ret; + + dev_dbg(dev, "rx%u: enable FPD-Link IV AEQ LMS\n", nport); + + return 0; +} + +static int ub960_enable_dfe_lms_ub9702(struct ub960_data *priv, + unsigned int nport) +{ + struct device *dev = &priv->client->dev; + int ret = 0; + + /* Enable DFE LMS */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_EQ_CTRL_SEL_24, 0x40, &ret); + /* Disable VGA Gain1 override */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_GAIN_CTRL_0, 0x20, &ret); + + if (ret) + return ret; + + usleep_range(1000, 5000); + + /* Disable VGA Gain2 override */ + ret = ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), + UB9702_IR_RX_ANA_GAIN_CTRL_0, 0x00, NULL); + if (ret) + return ret; + + dev_dbg(dev, "rx%u: enabled FPD-Link IV DFE LMS", nport); + + return 0; +} + +static int ub960_init_rx_ports_ub9702(struct ub960_data *priv) { struct device *dev = &priv->client->dev; unsigned int port_lock_mask; - unsigned int port_mask; + unsigned int port_mask = 0; + bool have_fpd4 = false; int ret;
for_each_active_rxport(priv, it) { - int ret; + ret = ub960_rxport_update_bits(priv, it.nport, + UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_BC_ALWAYS_ON, + UB960_RR_BCC_CONFIG_BC_ALWAYS_ON, + NULL); + if (ret) + return ret; + }
- if (priv->hw_data->is_ub9702) - ret = ub960_init_rx_port_ub9702(priv, it.rxport); - else - ret = ub960_init_rx_port_ub960(priv, it.rxport); + /* Disable FPD4 Auto Recovery */ + ret = ub960_write(priv, UB9702_SR_CSI_EXCLUSIVE_FWD2, 0x0f, NULL); + if (ret) + return ret; + + for_each_active_rxport_fpd4(priv, it) { + /* Hold state machine in reset */ + ub960_rxport_write(priv, it.nport, UB9702_RR_RX_SM_SEL_2, 0x10, + &ret); + + /* Set AEQ max to 0 */ + ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(it.nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL7, 0, &ret);
if (ret) return ret; + + dev_dbg(dev, + "rx%u: holding state machine and adjusting AEQ max to 0", + it.nport); + } + + for_each_active_rxport(priv, it) { + port_mask |= BIT(it.nport); + + if (it.rxport->cdr_mode == RXPORT_CDR_FPD4) + have_fpd4 = true; + } + + for_each_rxport(priv, it) { + ret = ub960_configure_rx_port_ub9702(priv, it.nport); + if (ret) + return ret; }
ret = ub960_reset(priv, false); if (ret) return ret;
- port_mask = 0; + if (have_fpd4) { + for_each_active_rxport_fpd4(priv, it) { + /* Release state machine */ + ret = ub960_rxport_write(priv, it.nport, + UB9702_RR_RX_SM_SEL_2, 0x0, + NULL); + if (ret) + return ret;
- for_each_active_rxport(priv, it) - port_mask |= BIT(it.nport); + dev_dbg(dev, "rx%u: state machine released\n", + it.nport); + } + + /* Wait for SM to resume */ + fsleep(5000); + + for_each_active_rxport_fpd4(priv, it) { + ret = ub960_write_ind(priv, + UB960_IND_TARGET_RX_ANA(it.nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL7, + 0x23, NULL); + if (ret) + return ret; + + dev_dbg(dev, "rx%u: AEQ restart\n", it.nport); + } + + /* Wait for lock */ + fsleep(20000); + + for_each_active_rxport_fpd4(priv, it) { + ret = ub960_lock_recovery_ub9702(priv, it.nport); + if (ret) + return ret; + } + + for_each_active_rxport_fpd4(priv, it) { + ret = ub960_enable_aeq_lms_ub9702(priv, it.nport); + if (ret) + return ret; + } + + for_each_active_rxport_fpd4(priv, it) { + /* Hold state machine in reset */ + ret = ub960_rxport_write(priv, it.nport, + UB9702_RR_RX_SM_SEL_2, 0x10, + NULL); + if (ret) + return ret; + } + + ret = ub960_reset(priv, false); + if (ret) + return ret; + + for_each_active_rxport_fpd4(priv, it) { + /* Release state machine */ + ret = ub960_rxport_write(priv, it.nport, + UB9702_RR_RX_SM_SEL_2, 0, + NULL); + if (ret) + return ret; + } + } + + /* Wait time for stable lock */ + fsleep(15000); + + for_each_active_rxport_fpd4(priv, it) { + ret = ub960_enable_dfe_lms_ub9702(priv, it.nport); + if (ret) + return ret; + } + + /* Wait for DFE and LMS to adapt */ + fsleep(5000);
ret = ub960_rxport_wait_locks(priv, port_mask, &port_lock_mask); if (ret) @@ -2556,10 +2981,49 @@ static int ub960_init_rx_ports(struct ub960_data *priv) return ret; }
+ for_each_active_rxport(priv, it) { + /* Enable all interrupt sources from this port */ + ub960_rxport_write(priv, it.nport, UB960_RR_PORT_ICR_HI, 0x07, + &ret); + ub960_rxport_write(priv, it.nport, UB960_RR_PORT_ICR_LO, 0x7f, + &ret); + + /* Enable I2C_PASS_THROUGH */ + ub960_rxport_update_bits(priv, it.nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, + &ret); + + /* Enable I2C communication to the serializer via the alias */ + ub960_rxport_write(priv, it.nport, UB960_RR_SER_ALIAS_ID, + it.rxport->ser.alias << 1, &ret); + + if (ret) + return ret; + } + + /* Enable FPD4 Auto Recovery, Recovery loop active */ + ret = ub960_write(priv, UB9702_SR_CSI_EXCLUSIVE_FWD2, 0x18, NULL); + if (ret) + return ret; + + for_each_active_rxport_fpd4(priv, it) { + u8 final_aeq; + + ret = ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(it.nport), + UB9702_IR_RX_ANA_AEQ_ALP_SEL11, &final_aeq, + NULL); + if (ret) + return ret; + + dev_dbg(dev, "rx%u: final AEQ = %#x\n", it.nport, final_aeq); + } + /* * Clear any errors caused by switching the RX port settings while * probing. */ + ret = ub960_clear_rx_errors(priv); if (ret) return ret; @@ -4393,7 +4857,11 @@ static int ub960_probe(struct i2c_client *client) if (ret) goto err_free_ports;
- ret = ub960_init_rx_ports(priv); + if (priv->hw_data->is_ub9702) + ret = ub960_init_rx_ports_ub9702(priv); + else + ret = ub960_init_rx_ports_ub960(priv); + if (ret) goto err_disable_vpocs;
The serializer's I2C address on the FPD-Link bus is usually communicated to the deserializer once the forward-channel is established. But in some cases it might be necessary to program the serializer (over the back-channel) before the forward-channel is established.
This can be used e.g. to correct serializer configuration which otherwise would prevent the FC to be enabled. To be able to communicate to the serializer before the forward-channel is up, the deserializer driver neds to know the default i2c address of the serializer.
Allow setting the serializer i2c address using the 'reg' property. This is optional, and usually not needed.
Reviewed-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- Cc: devicetree@vger.kernel.org Cc: Rob Herring robh@kernel.org Cc: Krzysztof Kozlowski krzk+dt@kernel.org Cc: Conor Dooley conor+dt@kernel.org --- .../bindings/media/i2c/ti,ds90ub953.yaml | 77 +++++++++++++--------- .../bindings/media/i2c/ti,ds90ub960.yaml | 16 ++++- 2 files changed, 58 insertions(+), 35 deletions(-)
diff --git a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml index 2030366994d18b695328194da1a7d95607de4371..2e129bf573b79e0ca8f25b4ec5fc6ea76c50abd7 100644 --- a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml @@ -38,6 +38,13 @@ properties: '#clock-cells': const: 0
+ reg: + maxItems: 1 + description: + The strap I2C address of the serializer. Can be used by the deserializer + to communicate over back-channel when the forward-channel is not yet + active. + ports: $ref: /schemas/graph.yaml#/properties/ports
@@ -81,51 +88,57 @@ examples: - | #include <dt-bindings/gpio/gpio.h>
- serializer { - compatible = "ti,ds90ub953-q1"; + link { + #address-cells = <1>; + #size-cells = <0>; + + serializer@18 { + compatible = "ti,ds90ub953-q1"; + reg = <0x18>;
- gpio-controller; - #gpio-cells = <2>; + gpio-controller; + #gpio-cells = <2>;
- #clock-cells = <0>; + #clock-cells = <0>;
- ports { - #address-cells = <1>; - #size-cells = <0>; + ports { + #address-cells = <1>; + #size-cells = <0>;
- port@0 { - reg = <0>; - ub953_in: endpoint { - clock-lanes = <0>; - data-lanes = <1 2 3 4>; - remote-endpoint = <&sensor_out>; + port@0 { + reg = <0>; + ub953_in: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_out>; + }; }; - };
- port@1 { - reg = <1>; - endpoint { - remote-endpoint = <&deser_fpd_in>; + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&deser_fpd_in>; + }; }; }; - };
- i2c { - #address-cells = <1>; - #size-cells = <0>; + i2c { + #address-cells = <1>; + #size-cells = <0>;
- sensor@1a { - compatible = "sony,imx274"; - reg = <0x1a>; + sensor@1a { + compatible = "sony,imx274"; + reg = <0x1a>;
- reset-gpios = <&serializer 0 GPIO_ACTIVE_LOW>; + reset-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
- clocks = <&serializer>; - clock-names = "inck"; + clocks = <&serializer>; + clock-names = "inck";
- port { - sensor_out: endpoint { - remote-endpoint = <&ub953_in>; + port { + sensor_out: endpoint { + remote-endpoint = <&ub953_in>; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml index 0b71e6f911a8835eb70ccf832888964288a6cac6..4dcbd2b039a58edfc57c5cc0bedceefdf158bf0c 100644 --- a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml @@ -68,6 +68,12 @@ properties: description: The link number maxItems: 1
+ '#address-cells': + const: 1 + + '#size-cells': + const: 0 + i2c-alias: $ref: /schemas/types.yaml#/definitions/uint32 description: @@ -107,7 +113,8 @@ properties: maximum: 14 description: Manual EQ level
- serializer: + patternProperties: + '^serializer(@[0-9a-f]+)*$': type: object description: FPD-Link Serializer node
@@ -115,7 +122,6 @@ properties: - reg - i2c-alias - ti,rx-mode - - serializer
ports: $ref: /schemas/graph.yaml#/properties/ports @@ -309,13 +315,17 @@ examples: /* Link 0 has DS90UB953 serializer and IMX274 sensor */
link@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; i2c-alias = <0x44>;
ti,rx-mode = <3>;
- serializer1: serializer { + serializer1: serializer@30 { compatible = "ti,ds90ub953-q1"; + reg = <0x30>;
gpio-controller; #gpio-cells = <2>;
From: Tomi Valkeinen tomi.valkeinen@ideasonboard.com
Move UB953 register defines to a header file. This is done so that the deserializer driver can access the defines, and do some early serializer configuration.
Signed-off-by: Tomi Valkeinen tomi.valkeinen@ideasonboard.com Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub953.c | 89 +--------------------------------------- drivers/media/i2c/ds90ub953.h | 95 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 87 deletions(-)
diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index a5c23e94f4eab5896a2114cfdf2e5f68cde77568..c305b4e03e07798b6526ff2423811f3f7d5bdac8 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -28,6 +28,8 @@ #include <media/v4l2-mediabus.h> #include <media/v4l2-subdev.h>
+#include "ds90ub953.h" + #define UB953_PAD_SINK 0 #define UB953_PAD_SOURCE 1
@@ -35,93 +37,6 @@
#define UB953_DEFAULT_CLKOUT_RATE 25000000UL
-#define UB953_REG_RESET_CTL 0x01 -#define UB953_REG_RESET_CTL_DIGITAL_RESET_1 BIT(1) -#define UB953_REG_RESET_CTL_DIGITAL_RESET_0 BIT(0) - -#define UB953_REG_GENERAL_CFG 0x02 -#define UB953_REG_GENERAL_CFG_CONT_CLK BIT(6) -#define UB953_REG_GENERAL_CFG_CSI_LANE_SEL_SHIFT 4 -#define UB953_REG_GENERAL_CFG_CSI_LANE_SEL_MASK GENMASK(5, 4) -#define UB953_REG_GENERAL_CFG_CRC_TX_GEN_ENABLE BIT(1) -#define UB953_REG_GENERAL_CFG_I2C_STRAP_MODE BIT(0) - -#define UB953_REG_MODE_SEL 0x03 -#define UB953_REG_MODE_SEL_MODE_DONE BIT(3) -#define UB953_REG_MODE_SEL_MODE_OVERRIDE BIT(4) -#define UB953_REG_MODE_SEL_MODE_MASK GENMASK(2, 0) - -#define UB953_REG_CLKOUT_CTRL0 0x06 -#define UB953_REG_CLKOUT_CTRL1 0x07 - -#define UB953_REG_I2C_CONTROL2 0x0a -#define UB953_REG_I2C_CONTROL2_SDA_OUTPUT_SETUP_SHIFT 4 -#define UB953_REG_I2C_CONTROL2_BUS_SPEEDUP BIT(1) - -#define UB953_REG_SCL_HIGH_TIME 0x0b -#define UB953_REG_SCL_LOW_TIME 0x0c - -#define UB953_REG_LOCAL_GPIO_DATA 0x0d -#define UB953_REG_LOCAL_GPIO_DATA_GPIO_RMTEN(n) BIT(4 + (n)) -#define UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(n) BIT(0 + (n)) - -#define UB953_REG_GPIO_INPUT_CTRL 0x0e -#define UB953_REG_GPIO_INPUT_CTRL_OUT_EN(n) BIT(4 + (n)) -#define UB953_REG_GPIO_INPUT_CTRL_INPUT_EN(n) BIT(0 + (n)) - -#define UB953_REG_BC_CTRL 0x49 -#define UB953_REG_BC_CTRL_CRC_ERR_CLR BIT(3) - -#define UB953_REG_REV_MASK_ID 0x50 -#define UB953_REG_GENERAL_STATUS 0x52 - -#define UB953_REG_GPIO_PIN_STS 0x53 -#define UB953_REG_GPIO_PIN_STS_GPIO_STS(n) BIT(0 + (n)) - -#define UB953_REG_BIST_ERR_CNT 0x54 -#define UB953_REG_CRC_ERR_CNT1 0x55 -#define UB953_REG_CRC_ERR_CNT2 0x56 - -#define UB953_REG_CSI_ERR_CNT 0x5c -#define UB953_REG_CSI_ERR_STATUS 0x5d -#define UB953_REG_CSI_ERR_DLANE01 0x5e -#define UB953_REG_CSI_ERR_DLANE23 0x5f -#define UB953_REG_CSI_ERR_CLK_LANE 0x60 -#define UB953_REG_CSI_PKT_HDR_VC_ID 0x61 -#define UB953_REG_PKT_HDR_WC_LSB 0x62 -#define UB953_REG_PKT_HDR_WC_MSB 0x63 -#define UB953_REG_CSI_ECC 0x64 - -#define UB953_REG_IND_ACC_CTL 0xb0 -#define UB953_REG_IND_ACC_ADDR 0xb1 -#define UB953_REG_IND_ACC_DATA 0xb2 - -#define UB953_REG_FPD3_RX_ID(n) (0xf0 + (n)) -#define UB953_REG_FPD3_RX_ID_LEN 6 - -/* Indirect register blocks */ -#define UB953_IND_TARGET_PAT_GEN 0x00 -#define UB953_IND_TARGET_FPD3_TX 0x01 -#define UB953_IND_TARGET_DIE_ID 0x02 - -#define UB953_IND_PGEN_CTL 0x01 -#define UB953_IND_PGEN_CTL_PGEN_ENABLE BIT(0) -#define UB953_IND_PGEN_CFG 0x02 -#define UB953_IND_PGEN_CSI_DI 0x03 -#define UB953_IND_PGEN_LINE_SIZE1 0x04 -#define UB953_IND_PGEN_LINE_SIZE0 0x05 -#define UB953_IND_PGEN_BAR_SIZE1 0x06 -#define UB953_IND_PGEN_BAR_SIZE0 0x07 -#define UB953_IND_PGEN_ACT_LPF1 0x08 -#define UB953_IND_PGEN_ACT_LPF0 0x09 -#define UB953_IND_PGEN_TOT_LPF1 0x0a -#define UB953_IND_PGEN_TOT_LPF0 0x0b -#define UB953_IND_PGEN_LINE_PD1 0x0c -#define UB953_IND_PGEN_LINE_PD0 0x0d -#define UB953_IND_PGEN_VBP 0x0e -#define UB953_IND_PGEN_VFP 0x0f -#define UB953_IND_PGEN_COLOR(n) (0x10 + (n)) /* n <= 15 */ - /* Note: Only sync mode supported for now */ enum ub953_mode { /* FPD-Link III CSI-2 synchronous mode */ diff --git a/drivers/media/i2c/ds90ub953.h b/drivers/media/i2c/ds90ub953.h new file mode 100644 index 0000000000000000000000000000000000000000..8bb28f0daee96044a7bf838a680e506af4f70f10 --- /dev/null +++ b/drivers/media/i2c/ds90ub953.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __MEDIA_I2C_DS90UB953_H__ +#define __MEDIA_I2C_DS90UB953_H__ + +#include <linux/types.h> + +#define UB953_REG_RESET_CTL 0x01 +#define UB953_REG_RESET_CTL_DIGITAL_RESET_1 BIT(1) +#define UB953_REG_RESET_CTL_DIGITAL_RESET_0 BIT(0) + +#define UB953_REG_GENERAL_CFG 0x02 +#define UB953_REG_GENERAL_CFG_CONT_CLK BIT(6) +#define UB953_REG_GENERAL_CFG_CSI_LANE_SEL_SHIFT 4 +#define UB953_REG_GENERAL_CFG_CSI_LANE_SEL_MASK GENMASK(5, 4) +#define UB953_REG_GENERAL_CFG_CRC_TX_GEN_ENABLE BIT(1) +#define UB953_REG_GENERAL_CFG_I2C_STRAP_MODE BIT(0) + +#define UB953_REG_MODE_SEL 0x03 +#define UB953_REG_MODE_SEL_MODE_DONE BIT(3) +#define UB953_REG_MODE_SEL_MODE_OVERRIDE BIT(4) +#define UB953_REG_MODE_SEL_MODE_MASK GENMASK(2, 0) + +#define UB953_REG_CLKOUT_CTRL0 0x06 +#define UB953_REG_CLKOUT_CTRL1 0x07 + +#define UB953_REG_I2C_CONTROL2 0x0a +#define UB953_REG_I2C_CONTROL2_SDA_OUTPUT_SETUP_SHIFT 4 +#define UB953_REG_I2C_CONTROL2_BUS_SPEEDUP BIT(1) + +#define UB953_REG_SCL_HIGH_TIME 0x0b +#define UB953_REG_SCL_LOW_TIME 0x0c + +#define UB953_REG_LOCAL_GPIO_DATA 0x0d +#define UB953_REG_LOCAL_GPIO_DATA_GPIO_RMTEN(n) BIT(4 + (n)) +#define UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(n) BIT(0 + (n)) + +#define UB953_REG_GPIO_INPUT_CTRL 0x0e +#define UB953_REG_GPIO_INPUT_CTRL_OUT_EN(n) BIT(4 + (n)) +#define UB953_REG_GPIO_INPUT_CTRL_INPUT_EN(n) BIT(0 + (n)) + +#define UB953_REG_BC_CTRL 0x49 +#define UB953_REG_BC_CTRL_CRC_ERR_CLR BIT(3) + +#define UB953_REG_REV_MASK_ID 0x50 +#define UB953_REG_GENERAL_STATUS 0x52 + +#define UB953_REG_GPIO_PIN_STS 0x53 +#define UB953_REG_GPIO_PIN_STS_GPIO_STS(n) BIT(0 + (n)) + +#define UB953_REG_BIST_ERR_CNT 0x54 +#define UB953_REG_CRC_ERR_CNT1 0x55 +#define UB953_REG_CRC_ERR_CNT2 0x56 + +#define UB953_REG_CSI_ERR_CNT 0x5c +#define UB953_REG_CSI_ERR_STATUS 0x5d +#define UB953_REG_CSI_ERR_DLANE01 0x5e +#define UB953_REG_CSI_ERR_DLANE23 0x5f +#define UB953_REG_CSI_ERR_CLK_LANE 0x60 +#define UB953_REG_CSI_PKT_HDR_VC_ID 0x61 +#define UB953_REG_PKT_HDR_WC_LSB 0x62 +#define UB953_REG_PKT_HDR_WC_MSB 0x63 +#define UB953_REG_CSI_ECC 0x64 + +#define UB953_REG_IND_ACC_CTL 0xb0 +#define UB953_REG_IND_ACC_ADDR 0xb1 +#define UB953_REG_IND_ACC_DATA 0xb2 + +#define UB953_REG_FPD3_RX_ID(n) (0xf0 + (n)) +#define UB953_REG_FPD3_RX_ID_LEN 6 + +/* Indirect register blocks */ +#define UB953_IND_TARGET_PAT_GEN 0x00 +#define UB953_IND_TARGET_FPD3_TX 0x01 +#define UB953_IND_TARGET_DIE_ID 0x02 + +#define UB953_IND_PGEN_CTL 0x01 +#define UB953_IND_PGEN_CTL_PGEN_ENABLE BIT(0) +#define UB953_IND_PGEN_CFG 0x02 +#define UB953_IND_PGEN_CSI_DI 0x03 +#define UB953_IND_PGEN_LINE_SIZE1 0x04 +#define UB953_IND_PGEN_LINE_SIZE0 0x05 +#define UB953_IND_PGEN_BAR_SIZE1 0x06 +#define UB953_IND_PGEN_BAR_SIZE0 0x07 +#define UB953_IND_PGEN_ACT_LPF1 0x08 +#define UB953_IND_PGEN_ACT_LPF0 0x09 +#define UB953_IND_PGEN_TOT_LPF1 0x0a +#define UB953_IND_PGEN_TOT_LPF0 0x0b +#define UB953_IND_PGEN_LINE_PD1 0x0c +#define UB953_IND_PGEN_LINE_PD0 0x0d +#define UB953_IND_PGEN_VBP 0x0e +#define UB953_IND_PGEN_VFP 0x0f +#define UB953_IND_PGEN_COLOR(n) (0x10 + (n)) /* n <= 15 */ + +#endif /* __MEDIA_I2C_DS90UB953_H__ */
For DS90UB9702-Q1, it is recommended to configure some serializer settings over the back-channel before the forward-channel is active.
This can only be done if the serializer's I2C address on the FPD-Link bus is populated in the device tree node.
Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub953.h | 4 ++ drivers/media/i2c/ds90ub960.c | 126 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 4 deletions(-)
diff --git a/drivers/media/i2c/ds90ub953.h b/drivers/media/i2c/ds90ub953.h index 8bb28f0daee96044a7bf838a680e506af4f70f10..de606474493f8d95a412e5564b0fac21885e581d 100644 --- a/drivers/media/i2c/ds90ub953.h +++ b/drivers/media/i2c/ds90ub953.h @@ -92,4 +92,8 @@ #define UB953_IND_PGEN_VFP 0x0f #define UB953_IND_PGEN_COLOR(n) (0x10 + (n)) /* n <= 15 */
+/* UB971 Registers */ + +#define UB971_ENH_BC_CHK 0x4b + #endif /* __MEDIA_I2C_DS90UB953_H__ */ diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index 56b1a88c1c29fbefecae60f4c9976e8ede554447..cad25dcbca11bf6597d00eede6dfa9110f445886 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -52,6 +52,8 @@ #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h>
+#include "ds90ub953.h" + #define MHZ(v) ((u32)((v) * HZ_PER_MHZ))
/* @@ -244,13 +246,16 @@
#define UB960_RR_BCC_CONFIG 0x58 #define UB960_RR_BCC_CONFIG_BC_ALWAYS_ON BIT(4) +#define UB960_RR_BCC_CONFIG_AUTO_ACK_ALL BIT(5) #define UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH BIT(6) #define UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK GENMASK(2, 0)
#define UB960_RR_DATAPATH_CTL1 0x59 #define UB960_RR_DATAPATH_CTL2 0x5a #define UB960_RR_SER_ID 0x5b +#define UB960_RR_SER_ID_FREEZE_DEVICE_ID BIT(0) #define UB960_RR_SER_ALIAS_ID 0x5c +#define UB960_RR_SER_ALIAS_ID_AUTO_ACK BIT(0)
/* For these two register sets: n < UB960_MAX_PORT_ALIASES */ #define UB960_RR_SLAVE_ID(n) (0x5d + (n)) @@ -486,7 +491,9 @@ struct ub960_rxport { struct fwnode_handle *fwnode; struct i2c_client *client; unsigned short alias; /* I2C alias (lower 7 bits) */ + short addr; /* Local I2C address (lower 7 bits) */ struct ds90ub9xx_platform_data pdata; + struct regmap *regmap; } ser;
enum ub960_rxport_mode rx_mode; @@ -1984,6 +1991,78 @@ static unsigned long ub960_calc_bc_clk_rate_ub9702(struct ub960_data *priv, } }
+static int ub960_rxport_serializer_write(struct ub960_rxport *rxport, u8 reg, + u8 val, int *err) +{ + struct ub960_data *priv = rxport->priv; + struct device *dev = &priv->client->dev; + union i2c_smbus_data data; + int ret; + + if (err && *err) + return *err; + + data.byte = val; + + ret = i2c_smbus_xfer(priv->client->adapter, rxport->ser.alias, 0, + I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data); + if (ret) + dev_err(dev, + "rx%u: cannot write serializer register 0x%02x (%d)!\n", + rxport->nport, reg, ret); + + if (ret && err) + *err = ret; + + return ret; +} + +static int ub960_rxport_bc_ser_config(struct ub960_rxport *rxport) +{ + struct ub960_data *priv = rxport->priv; + struct device *dev = &priv->client->dev; + u8 nport = rxport->nport; + int ret; + + /* Skip port if serializer's address is not known */ + if (rxport->ser.addr < 0) { + dev_dbg(dev, + "rx%u: serializer address missing, skip configuration\n", + nport); + return 0; + } + + /* + * Note: the code here probably only works for CSI-2 serializers in + * sync mode. To support other serializers the BC related configuration + * should be done before calling this function. + */ + + /* Enable I2C passthrough and auto-ack on BC */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH | + UB960_RR_BCC_CONFIG_AUTO_ACK_ALL, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH | + UB960_RR_BCC_CONFIG_AUTO_ACK_ALL, + &ret); + + if (ret) + return ret; + + /* Disable BC alternate mode auto detect */ + ub960_rxport_serializer_write(rxport, UB971_ENH_BC_CHK, 0x02, &ret); + /* Decrease link detect timer */ + ub960_rxport_serializer_write(rxport, UB953_REG_BC_CTRL, 0x06, &ret); + + /* Disable I2C passthrough and auto-ack on BC */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH | + UB960_RR_BCC_CONFIG_AUTO_ACK_ALL, + 0x0, &ret); + + return ret; +} + static int ub960_rxport_add_serializer(struct ub960_data *priv, u8 nport) { struct ub960_rxport *rxport = priv->rxports[nport]; @@ -2860,6 +2939,36 @@ static int ub960_init_rx_ports_ub9702(struct ub960_data *priv) if (ret) return ret;
+ for_each_active_rxport(priv, it) { + if (it.rxport->ser.addr >= 0) { + /* + * Set serializer's I2C address if set in the dts file, + * and freeze it to prevent updates from the FC. + */ + ub960_rxport_write(priv, it.nport, UB960_RR_SER_ID, + it.rxport->ser.addr << 1 | + UB960_RR_SER_ID_FREEZE_DEVICE_ID, + &ret); + } + + /* Set serializer I2C alias with auto-ack */ + ub960_rxport_write(priv, it.nport, UB960_RR_SER_ALIAS_ID, + it.rxport->ser.alias << 1 | + UB960_RR_SER_ALIAS_ID_AUTO_ACK, &ret); + + if (ret) + return ret; + } + + for_each_active_rxport(priv, it) { + if (fwnode_device_is_compatible(it.rxport->ser.fwnode, + "ti,ds90ub971-q1")) { + ret = ub960_rxport_bc_ser_config(it.rxport); + if (ret) + return ret; + } + } + for_each_active_rxport_fpd4(priv, it) { /* Hold state machine in reset */ ub960_rxport_write(priv, it.nport, UB9702_RR_RX_SM_SEL_2, 0x10, @@ -2988,16 +3097,17 @@ static int ub960_init_rx_ports_ub9702(struct ub960_data *priv) ub960_rxport_write(priv, it.nport, UB960_RR_PORT_ICR_LO, 0x7f, &ret);
+ /* Clear serializer I2C alias auto-ack */ + ub960_rxport_update_bits(priv, it.nport, UB960_RR_SER_ALIAS_ID, + UB960_RR_SER_ALIAS_ID_AUTO_ACK, 0, + &ret); + /* Enable I2C_PASS_THROUGH */ ub960_rxport_update_bits(priv, it.nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, &ret);
- /* Enable I2C communication to the serializer via the alias */ - ub960_rxport_write(priv, it.nport, UB960_RR_SER_ALIAS_ID, - it.rxport->ser.alias << 1, &ret); - if (ret) return ret; } @@ -4156,6 +4266,7 @@ ub960_parse_dt_rxport_link_properties(struct ub960_data *priv, s32 strobe_pos; u32 eq_level; u32 ser_i2c_alias; + u32 ser_i2c_addr; int ret;
cdr_mode = RXPORT_CDR_FPD3; @@ -4267,6 +4378,13 @@ ub960_parse_dt_rxport_link_properties(struct ub960_data *priv, return -EINVAL; }
+ ret = fwnode_property_read_u32(rxport->ser.fwnode, "reg", + &ser_i2c_addr); + if (ret) + rxport->ser.addr = -EINVAL; + else + rxport->ser.addr = ser_i2c_addr; + return 0; }
For continuous PLL lock, it is recommended to extend the temperature ramp down range of the DS90UB953-Q1 serializer based on the device's initial temperature [1].
The serializer's die temperature is reported only to the deserializer through the sensor status registers, and for UB9702, it is recommended to set the temperature ramp during the link setup sequence, i.e. before we even probe the ub953 driver.
Add support to the deserializer driver to configure ub953's temperature ramp.
[1]: Section 7.3.1.1 - https://www.ti.com/lit/gpn/ds90ub953-q1
Signed-off-by: Jai Luthra jai.luthra@ideasonboard.com --- drivers/media/i2c/ds90ub953.h | 7 ++- drivers/media/i2c/ds90ub960.c | 125 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/drivers/media/i2c/ds90ub953.h b/drivers/media/i2c/ds90ub953.h index de606474493f8d95a412e5564b0fac21885e581d..97a6b3af326eb96af20653ed13b89798e18646bd 100644 --- a/drivers/media/i2c/ds90ub953.h +++ b/drivers/media/i2c/ds90ub953.h @@ -71,7 +71,7 @@
/* Indirect register blocks */ #define UB953_IND_TARGET_PAT_GEN 0x00 -#define UB953_IND_TARGET_FPD3_TX 0x01 +#define UB953_IND_TARGET_ANALOG 0x01 #define UB953_IND_TARGET_DIE_ID 0x02
#define UB953_IND_PGEN_CTL 0x01 @@ -92,6 +92,11 @@ #define UB953_IND_PGEN_VFP 0x0f #define UB953_IND_PGEN_COLOR(n) (0x10 + (n)) /* n <= 15 */
+#define UB953_IND_ANA_TEMP_DYNAMIC_CFG 0x4b +#define UB953_IND_ANA_TEMP_DYNAMIC_CFG_OV BIT(5) +#define UB953_IND_ANA_TEMP_STATIC_CFG 0x4c +#define UB953_IND_ANA_TEMP_STATIC_CFG_MASK GENMASK(6, 4) + /* UB971 Registers */
#define UB971_ENH_BC_CHK 0x4b diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index cad25dcbca11bf6597d00eede6dfa9110f445886..1877eb735cc7d865a68e315446a24b536b387d2a 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -2017,6 +2017,110 @@ static int ub960_rxport_serializer_write(struct ub960_rxport *rxport, u8 reg, return ret; }
+static int ub960_rxport_serializer_read(struct ub960_rxport *rxport, u8 reg, + u8 *val, int *err) +{ + struct ub960_data *priv = rxport->priv; + struct device *dev = &priv->client->dev; + union i2c_smbus_data data = { 0 }; + int ret; + + if (err && *err) + return *err; + + ret = i2c_smbus_xfer(priv->client->adapter, rxport->ser.alias, + priv->client->flags, I2C_SMBUS_READ, reg, + I2C_SMBUS_BYTE_DATA, &data); + if (ret) + dev_err(dev, + "rx%u: cannot read serializer register 0x%02x (%d)!\n", + rxport->nport, reg, ret); + else + *val = data.byte; + + if (ret && err) + *err = ret; + + return ret; +} + +static int ub960_serializer_temp_ramp(struct ub960_rxport *rxport) +{ + struct ub960_data *priv = rxport->priv; + short temp_dynamic_offset[] = {-1, -1, 0, 0, 1, 1, 1, 3}; + u8 temp_dynamic_cfg; + u8 nport = rxport->nport; + u8 ser_temp_code; + int ret; + + /* Configure temp ramp only on UB953 */ + if (!fwnode_device_is_compatible(rxport->ser.fwnode, "ti,ds90ub953-q1")) + return 0; + + /* Read current serializer die temperature */ + ub960_rxport_read(priv, nport, UB960_RR_SENSOR_STS_2, &ser_temp_code, + &ret); + + /* Enable I2C passthrough on back channel */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, &ret); + + if (ret) + return ret; + + /* Select indirect page for analog regs on the serializer */ + ub960_rxport_serializer_write(rxport, UB953_REG_IND_ACC_CTL, + UB953_IND_TARGET_ANALOG << 2, &ret); + + /* Set temperature ramp dynamic and static config */ + ub960_rxport_serializer_write(rxport, UB953_REG_IND_ACC_ADDR, + UB953_IND_ANA_TEMP_DYNAMIC_CFG, &ret); + ub960_rxport_serializer_read(rxport, UB953_REG_IND_ACC_DATA, + &temp_dynamic_cfg, &ret); + + if (ret) + return ret; + + temp_dynamic_cfg |= UB953_IND_ANA_TEMP_DYNAMIC_CFG_OV; + temp_dynamic_cfg += temp_dynamic_offset[ser_temp_code]; + + /* Update temp static config */ + ub960_rxport_serializer_write(rxport, UB953_REG_IND_ACC_ADDR, + UB953_IND_ANA_TEMP_STATIC_CFG, &ret); + ub960_rxport_serializer_write(rxport, UB953_REG_IND_ACC_DATA, + UB953_IND_ANA_TEMP_STATIC_CFG_MASK, &ret); + + /* Update temperature ramp dynamic config */ + ub960_rxport_serializer_write(rxport, UB953_REG_IND_ACC_ADDR, + UB953_IND_ANA_TEMP_DYNAMIC_CFG, &ret); + + /* Enable I2C auto ack on BC before we set dynamic cfg and reset */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_AUTO_ACK_ALL, + UB960_RR_BCC_CONFIG_AUTO_ACK_ALL, &ret); + + ub960_rxport_serializer_write(rxport, UB953_REG_IND_ACC_DATA, + temp_dynamic_cfg, &ret); + + if (ret) + return ret; + + /* Soft reset to apply PLL updates */ + ub960_rxport_serializer_write(rxport, UB953_REG_RESET_CTL, + UB953_REG_RESET_CTL_DIGITAL_RESET_0, + &ret); + msleep(20); + + /* Disable I2C passthrough and auto-ack on BC */ + ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH | + UB960_RR_BCC_CONFIG_AUTO_ACK_ALL, + 0x0, &ret); + + return ret; +} + static int ub960_rxport_bc_ser_config(struct ub960_rxport *rxport) { struct ub960_data *priv = rxport->priv; @@ -2396,6 +2500,20 @@ static int ub960_init_rx_ports_ub960(struct ub960_data *priv) return ret; }
+ /* Set temperature ramp on serializer */ + for_each_active_rxport(priv, it) { + ret = ub960_serializer_temp_ramp(it.rxport); + if (ret) + return ret; + + ub960_rxport_update_bits(priv, it.nport, UB960_RR_BCC_CONFIG, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, + UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, + &ret); + if (ret) + return ret; + } + /* * Clear any errors caused by switching the RX port settings while * probing. @@ -3071,6 +3189,13 @@ static int ub960_init_rx_ports_ub9702(struct ub960_data *priv) /* Wait time for stable lock */ fsleep(15000);
+ /* Set temperature ramp on serializer */ + for_each_active_rxport(priv, it) { + ret = ub960_serializer_temp_ramp(it.rxport); + if (ret) + return ret; + } + for_each_active_rxport_fpd4(priv, it) { ret = ub960_enable_dfe_lms_ub9702(priv, it.nport); if (ret)
linux-stable-mirror@lists.linaro.org