diff options
Diffstat (limited to 'drivers/media/i2c/max9286.c')
-rw-r--r-- | drivers/media/i2c/max9286.c | 74 |
1 files changed, 54 insertions, 20 deletions
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index c82c1493e099..6fd4d59fcc72 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -163,6 +163,8 @@ struct max9286_priv { unsigned int mux_channel; bool mux_open; + u32 reverse_channel_mv; + struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *pixelrate; @@ -336,6 +338,31 @@ static void max9286_configure_i2c(struct max9286_priv *priv, bool localack) usleep_range(3000, 5000); } +static void max9286_reverse_channel_setup(struct max9286_priv *priv, + unsigned int chan_amplitude) +{ + /* Reverse channel transmission time: default to 1. */ + u8 chan_config = MAX9286_REV_TRF(1); + + /* + * Reverse channel setup. + * + * - Enable custom reverse channel configuration (through register 0x3f) + * and set the first pulse length to 35 clock cycles. + * - Adjust reverse channel amplitude: values > 130 are programmed + * using the additional +100mV REV_AMP_X boost flag + */ + max9286_write(priv, 0x3f, MAX9286_EN_REV_CFG | MAX9286_REV_FLEN(35)); + + if (chan_amplitude > 100) { + /* It is not possible to express values (100 < x < 130) */ + chan_amplitude = max(30U, chan_amplitude - 100); + chan_config |= MAX9286_REV_AMP_X; + } + max9286_write(priv, 0x3b, chan_config | MAX9286_REV_AMP(chan_amplitude)); + usleep_range(2000, 2500); +} + /* * max9286_check_video_links() - Make sure video links are detected and locked * @@ -531,10 +558,14 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier, * All enabled sources have probed and enabled their reverse control * channels: * + * - Increase the reverse channel amplitude to compensate for the + * remote ends high threshold, if not done already * - Verify all configuration links are properly detected * - Disable auto-ack as communication on the control channel are now * stable. */ + if (priv->reverse_channel_mv < 170) + max9286_reverse_channel_setup(priv, 170); max9286_check_config_link(priv, priv->source_mask); /* @@ -576,19 +607,19 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv) for_each_source(priv, source) { unsigned int i = to_index(priv, source); - struct v4l2_async_subdev *asd; + struct max9286_asd *mas; - asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, + mas = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, source->fwnode, - sizeof(*asd)); - if (IS_ERR(asd)) { + struct max9286_asd); + if (IS_ERR(mas)) { dev_err(dev, "Failed to add subdev for source %u: %ld", - i, PTR_ERR(asd)); + i, PTR_ERR(mas)); v4l2_async_notifier_cleanup(&priv->notifier); - return PTR_ERR(asd); + return PTR_ERR(mas); } - to_max9286_asd(asd)->source = source; + mas->source = source; } priv->notifier.ops = &max9286_notify_ops; @@ -941,19 +972,7 @@ static int max9286_setup(struct max9286_priv *priv) * only. This should be disabled after the mux is initialised. */ max9286_configure_i2c(priv, true); - - /* - * Reverse channel setup. - * - * - Enable custom reverse channel configuration (through register 0x3f) - * and set the first pulse length to 35 clock cycles. - * - Increase the reverse channel amplitude to 170mV to accommodate the - * high threshold enabled by the serializer driver. - */ - max9286_write(priv, 0x3f, MAX9286_EN_REV_CFG | MAX9286_REV_FLEN(35)); - max9286_write(priv, 0x3b, MAX9286_REV_TRF(1) | MAX9286_REV_AMP(70) | - MAX9286_REV_AMP_X); - usleep_range(2000, 2500); + max9286_reverse_channel_setup(priv, priv->reverse_channel_mv); /* * Enable GMSL links, mask unused ones and autodetect link @@ -1117,6 +1136,7 @@ static int max9286_parse_dt(struct max9286_priv *priv) struct device_node *i2c_mux; struct device_node *node = NULL; unsigned int i2c_mux_mask = 0; + u32 reverse_channel_microvolt; /* Balance the of_node_put() performed by of_find_node_by_name(). */ of_node_get(dev->of_node); @@ -1207,6 +1227,20 @@ static int max9286_parse_dt(struct max9286_priv *priv) } of_node_put(node); + /* + * Parse the initial value of the reverse channel amplitude from + * the firmware interface and convert it to millivolts. + * + * Default it to 170mV for backward compatibility with DTBs that do not + * provide the property. + */ + if (of_property_read_u32(dev->of_node, + "maxim,reverse-channel-microvolt", + &reverse_channel_microvolt)) + priv->reverse_channel_mv = 170; + else + priv->reverse_channel_mv = reverse_channel_microvolt / 1000U; + priv->route_mask = priv->source_mask; return 0; |