Some board designs connect only DSI port B, or both DSI ports A and B,
to the LT9611C. Add support for a 'lontium,port-select' DT property that
allows the board DTS to specify which DSI port(s) the chip should use:

  0 = PORT_SELECT_A  (default, single DSI port A)
  1 = PORT_SELECT_B  (single DSI port B)
  2 = PORT_SELECT_AB (dual DSI ports A+B)

When the property is absent the driver defaults to PORT_SELECT_A (0),
preserving backward compatibility with existing DTS files.

The selected port is programmed into the chip via lt9611c_select_port()
during probe, after the chip ID has been verified.

Signed-off-by: Mohit Dsor <[email protected]>
---
 drivers/gpu/drm/bridge/lontium-lt9611c.c | 44 ++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/gpu/drm/bridge/lontium-lt9611c.c 
b/drivers/gpu/drm/bridge/lontium-lt9611c.c
index fe51f4978546..5d67bb7391fb 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611c.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611c.c
@@ -41,6 +41,12 @@ enum lt9611_chip_type {
        CHIP_LT9611UXD,
 };
 
+enum lt9611c_PORT_SELECT {
+       PORT_SELECT_A  = 0,
+       PORT_SELECT_B  = 1,
+       PORT_SELECT_AB = 2,
+};
+
 struct lt9611c {
        struct device *dev;
        struct i2c_client *client;
@@ -60,6 +66,8 @@ struct lt9611c {
        enum lt9611_chip_type chip_type;
         /* HDMI cable connection status */
        bool hdmi_connected;
+       /* Selected DSI port configuration */
+       int selected_port;
 };
 
 DECLARE_CRC8_TABLE(lt9611c_crc8_table);
@@ -115,6 +123,34 @@ static int lt9611c_read_write_flow(struct lt9611c 
*lt9611c, u8 *params,
                                return_count);
 }
 
+static int lt9611c_select_port(struct lt9611c *lt9611c, int port_select)
+{
+       int ret;
+       u8 set_port_select_cmd[6] = {0x57, 0x4d, 0x31, 0x3a, 0x01, 0xc0};
+       u8 set_port_select_ret[5];
+
+       if (port_select == PORT_SELECT_B) {
+               set_port_select_cmd[5] = 0x40;
+       } else if (port_select == PORT_SELECT_AB) {
+               set_port_select_cmd[4] = 0x02;
+               set_port_select_cmd[5] = 0xd0;
+       } else if (port_select != PORT_SELECT_A) {
+               return -EINVAL;
+       }
+
+       /* MCU must be running (0xe0ee=0x00) for lt9611c_read_write_flow */
+       guard(mutex)(&lt9611c->ocm_lock);
+
+       ret = lt9611c_read_write_flow(lt9611c, set_port_select_cmd,
+                       ARRAY_SIZE(set_port_select_cmd),
+                       set_port_select_ret,
+                       ARRAY_SIZE(set_port_select_ret));
+       if (ret < 0 || set_port_select_ret[4] == 0)
+               return ret < 0 ? ret : -EIO;
+
+       return 0;
+}
+
 static void lt9611c_config_parameters(struct lt9611c *lt9611c)
 {
        const struct reg_sequence seq_write_paras[] = {
@@ -924,6 +960,10 @@ static int lt9611c_parse_dt(struct device *dev,
 
        lt9611c->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1);
 
+       if (of_property_read_u32(dev->of_node, "lontium,port-select",
+                                &lt9611c->selected_port))
+               lt9611c->selected_port = 0;
+
        return drm_of_find_panel_or_bridge(dev->of_node, 2, -1, NULL, 
&lt9611c->bridge.next_bridge);
 }
 
@@ -1070,6 +1110,10 @@ static int lt9611c_probe(struct i2c_client *client)
 
        lt9611c_reset(lt9611c);
 
+       ret = lt9611c_select_port(lt9611c, lt9611c->selected_port);
+       if (ret < 0)
+               dev_err(lt9611c->dev, "failed to select port %d\n", 
lt9611c->selected_port);
+
        lt9611c_lock(lt9611c);
 
        ret = lt9611c_read_chipid(lt9611c);

-- 
2.34.1

Reply via email to