@@ -1662,7 +1662,7 @@ config VIDEO_DS90UB960
select V4L2_FWNODE
select VIDEO_V4L2_SUBDEV_API
help
- Device driver for the Texas Instruments DS90UB960
+ Device driver for the Texas Instruments DS90UB954/DS90UB960
FPD-Link III Deserializer and DS90UB9702 FPD-Link IV Deserializer.
config VIDEO_MAX96714
@@ -460,6 +460,7 @@ struct ub960_hw_data {
u8 num_txports;
bool is_ub9702;
bool is_fpdlink4;
+ bool is_ub954;
};
enum ub960_rxport_mode {
@@ -982,6 +983,10 @@ static int ub960_txport_select(struct ub960_data *priv, u8 nport)
lockdep_assert_held(&priv->reg_lock);
+ /* TX port registers are shared for UB954*/
+ if (priv->hw_data->is_ub954)
+ return 0;
+
if (priv->reg_current.txport == nport)
return 0;
@@ -1415,6 +1420,13 @@ static int ub960_parse_dt_txport(struct ub960_data *priv,
goto err_free_vep;
}
+ /* UB954 does not support 1.2 Gbps */
+ if (priv->tx_data_rate == MHZ(1200) && priv->hw_data->is_ub954) {
+ dev_err(dev, "tx%u: invalid 'link-frequencies' value\n", nport);
+ ret = -EINVAL;
+ goto err_free_vep;
+ }
+
v4l2_fwnode_endpoint_free(&vep);
priv->txports[nport] = txport;
@@ -1572,6 +1584,10 @@ static int ub960_rxport_set_strobe_pos(struct ub960_data *priv,
u8 clk_delay, data_delay;
int ret = 0;
+ /* FIXME: After writing to this area the UB954 chip no longer responds */
+ if (priv->hw_data->is_ub954)
+ return 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;
@@ -5021,6 +5037,27 @@ static int ub960_enable_core_hw(struct ub960_data *priv)
if (priv->hw_data->is_ub9702)
ret = ub960_read(priv, UB9702_SR_REFCLK_FREQ, &refclk_freq,
NULL);
+ else if (priv->hw_data->is_ub954) {
+ /* From DS90UB954-Q1 datasheet:
+ * "REFCLK_FREQ measurement is not synchronized. Value in this
+ * register should read twice and only considered valid if
+ * REFCLK_FREQ is unchanged between reads."
+ */
+ unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+ do {
+ u8 refclk_new;
+
+ ret = ub960_read(priv, UB960_XR_REFCLK_FREQ, &refclk_new,
+ NULL);
+ if (ret)
+ goto err_pd_gpio;
+
+ if (refclk_new == refclk_freq)
+ break;
+ refclk_freq = refclk_new;
+ } while (time_before(jiffies, timeout));
+ }
else
ret = ub960_read(priv, UB960_XR_REFCLK_FREQ, &refclk_freq,
NULL);
@@ -5177,6 +5214,13 @@ static void ub960_remove(struct i2c_client *client)
mutex_destroy(&priv->reg_lock);
}
+static const struct ub960_hw_data ds90ub954_hw = {
+ .model = "ub954",
+ .num_rxports = 2,
+ .num_txports = 1,
+ .is_ub954 = true,
+};
+
static const struct ub960_hw_data ds90ub960_hw = {
.model = "ub960",
.num_rxports = 4,
@@ -5192,6 +5236,7 @@ static const struct ub960_hw_data ds90ub9702_hw = {
};
static const struct i2c_device_id ub960_id[] = {
+ { "ds90ub954-q1", (kernel_ulong_t)&ds90ub954_hw },
{ "ds90ub960-q1", (kernel_ulong_t)&ds90ub960_hw },
{ "ds90ub9702-q1", (kernel_ulong_t)&ds90ub9702_hw },
{}
@@ -5199,6 +5244,7 @@ static const struct i2c_device_id ub960_id[] = {
MODULE_DEVICE_TABLE(i2c, ub960_id);
static const struct of_device_id ub960_dt_ids[] = {
+ { .compatible = "ti,ds90ub954-q1", .data = &ds90ub954_hw },
{ .compatible = "ti,ds90ub960-q1", .data = &ds90ub960_hw },
{ .compatible = "ti,ds90ub9702-q1", .data = &ds90ub9702_hw },
{}
DS90UB954-Q1 is an FPDLink-III deserializer that is mostly register compatible with DS90UB960-Q1. The main difference is that it supports half of the RX and TX ports, i.e. 2x FPDLink RX ports and 1x CSI TX port. Some other registers are marked as reserved in the datasheet as well, notably around CSI-TX frame and line-count monitoring and some other status registers. The datasheet also does not mention anything about setting strobe position, and fails to lock the RX ports if we forcefully set it, so disable it through the hw_data. Link: https://www.ti.com/lit/gpn/ds90ub954-q1 Signed-off-by: Yemike Abhilash Chandra <y-abhilashchandra@ti.com> --- drivers/media/i2c/Kconfig | 2 +- drivers/media/i2c/ds90ub960.c | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-)