MLK-17650-1: drm/bridge: adv7511: Add support for programmable i2c addresses
authorRobert Chiras <robert.chiras@nxp.com>
Fri, 2 Mar 2018 09:31:50 +0000 (11:31 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
The DSI-HDMI converter, ADV7535, driver uses four i2c memory maps: MAIN,
DSI-CEC, EDID and PACKET.
While the MAIN address is hard-coded in the ROM chip, the other three
can be programmed into the MAIN memory map.
Currently, the three memory maps addresses, that can be programmed, are
hard-coded into the code.
In order to avoid conflicts with other i2c clients on the bus, update
the driver to use configurable addresses specified in DTS file.

Signed-off-by: Robert Chiras <robert.chiras@nxp.com>
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
drivers/gpu/drm/bridge/adv7511/adv7511.h
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
drivers/gpu/drm/bridge/adv7511/adv7533.c

index 9df1e0e..0c0b12e 100644 (file)
@@ -82,6 +82,12 @@ Optional properties:
        Possible maps names are : "main", "edid", "cec", "packet"
 - adi,dsi-channel: Only for ADV7533 and ADV7535. DSI channel number to be used
   when communicating with the DSI peripheral. It should be one of 0, 1, 2 or 3.
+- adi,addr-cec: Only for ADV7533 and ADV7535. The I2C DSI-CEC register map
+  address to be programmed into the MAIN register map.
+- adi,addr-edid: Only for ADV7533 and ADV7535. The I2C EDID register map
+  to be programmed into the MAIN register map.
+- adi,addr-pkt: Only for ADV7533 and ADV7535. The I2C PACKET register map
+  to be programmed into the MAIN register map.
 
 Required nodes:
 
index 17d828c..1b9a4f9 100644 (file)
@@ -330,6 +330,10 @@ struct adv7511 {
        struct i2c_client *i2c_packet;
        struct i2c_client *i2c_cec;
 
+       u32 addr_cec;
+       u32 addr_edid;
+       u32 addr_pkt;
+
        struct regmap *regmap;
        struct regmap *regmap_cec;
        enum drm_connector_status status;
index 82d3f78..b1dafbe 100644 (file)
@@ -999,7 +999,7 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
        int ret;
 
        adv->i2c_cec = i2c_new_secondary_device(adv->i2c_main, "cec",
-                                               ADV7511_CEC_I2C_ADDR_DEFAULT);
+                                               adv->addr_cec);
        if (!adv->i2c_cec)
                return -EINVAL;
        i2c_set_clientdata(adv->i2c_cec, adv);
@@ -1011,7 +1011,7 @@ static int adv7511_init_cec_regmap(struct adv7511 *adv)
                goto err;
        }
 
-       if (adv->type == ADV7533) {
+       if (adv->type == ADV7533 || adv->type == ADV7535) {
                ret = adv7533_patch_cec_registers(adv);
                if (ret)
                        goto err;
@@ -1116,6 +1116,10 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
        struct of_changeset ocs;
        struct property *prop;
 #endif
+       unsigned int main_i2c_addr = i2c->addr << 1;
+       unsigned int edid_i2c_addr = main_i2c_addr + 4;
+       unsigned int cec_i2c_addr = main_i2c_addr - 2;
+       unsigned int pkt_i2c_addr = main_i2c_addr - 0xa;
        unsigned int val;
        int ret;
 
@@ -1150,6 +1154,21 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
                return ret;
        }
 
+       if (adv7511->addr_cec != 0)
+               cec_i2c_addr = adv7511->addr_cec << 1;
+       else
+               adv7511->addr_cec = cec_i2c_addr >> 1;
+
+       if (adv7511->addr_edid != 0)
+               edid_i2c_addr = adv7511->addr_edid << 1;
+       else
+               adv7511->addr_edid = edid_i2c_addr >> 1;
+
+       if (adv7511->addr_pkt != 0)
+               pkt_i2c_addr = adv7511->addr_pkt << 1;
+       else
+               adv7511->addr_pkt = pkt_i2c_addr >> 1;
+
        /*
         * The power down GPIO is optional. If present, toggle it from active to
         * inactive to wake up the encoder.
@@ -1187,33 +1206,33 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 
        adv7511_packet_disable(adv7511, 0xffff);
 
+       regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
+                       edid_i2c_addr);
+
        adv7511->i2c_edid = i2c_new_secondary_device(i2c, "edid",
-                                       ADV7511_EDID_I2C_ADDR_DEFAULT);
+                                       adv7511->addr_edid);
        if (!adv7511->i2c_edid) {
                ret = -EINVAL;
                goto uninit_regulators;
        }
 
-       regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
-                    adv7511->i2c_edid->addr << 1);
+       regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
+                       pkt_i2c_addr);
 
        adv7511->i2c_packet = i2c_new_secondary_device(i2c, "packet",
-                                       ADV7511_PACKET_I2C_ADDR_DEFAULT);
+                                       adv7511->addr_pkt);
        if (!adv7511->i2c_packet) {
                ret = -EINVAL;
                goto err_i2c_unregister_edid;
        }
 
-       regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
-                    adv7511->i2c_packet->addr << 1);
+       regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
+                       cec_i2c_addr);
 
        ret = adv7511_init_cec_regmap(adv7511);
        if (ret)
                goto err_i2c_unregister_packet;
 
-       regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
-                    adv7511->i2c_cec->addr << 1);
-
        INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
 
        if (i2c->irq) {
@@ -1302,7 +1321,7 @@ static int adv7511_remove(struct i2c_client *i2c)
 {
        struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
 
-       if (adv7511->type == ADV7533 || adv7511->type == ADV7535) {
+       if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
                adv7533_detach_dsi(adv7511);
        i2c_unregister_device(adv7511->i2c_cec);
        if (adv7511->cec_clk)
index 3fc7b21..eb0e9b9 100644 (file)
@@ -225,6 +225,10 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
        adv->use_timing_gen = !of_property_read_bool(np,
                                                "adi,disable-timing-generator");
 
+       of_property_read_u32(np, "adi,addr-cec", &adv->addr_cec);
+       of_property_read_u32(np, "adi,addr-edid", &adv->addr_edid);
+       of_property_read_u32(np, "adi,addr-pkt", &adv->addr_pkt);
+
        /* TODO: Check if these need to be parsed by DT or not */
        adv->rgb = true;
        adv->embedded_sync = false;