anx6345
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
err = drm_dp_dpcd_readb(&anx6345->aux, DP_MAX_LINK_RATE, &dp_bw);
err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
err = drm_dp_dpcd_read(&anx6345->aux, DP_DPCD_REV,
&anx6345->dpcd, DP_RECEIVER_CAP_SIZE);
err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
drm_dp_link_power_up(&anx6345->aux, anx6345->dpcd[DP_DPCD_REV]);
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
if (anx6345->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) {
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL,
err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL, 0);
if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
dpcd[1] = drm_dp_max_lane_count(anx6345->dpcd);
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
err = drm_dp_dpcd_write(&anx6345->aux, DP_LINK_BW_SET, dpcd,
err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_LT_CTRL_REG,
return regmap_read_poll_timeout(anx6345->map[I2C_IDX_DPTX],
static int anx6345_tx_initialization(struct anx6345 *anx6345)
err = regmap_write(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL2_REG,
err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_PLL_CTRL_REG, 0);
err = regmap_write(anx6345->map[I2C_IDX_TXCOM],
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM],
return anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
static void anx6345_poweron(struct anx6345 *anx6345)
gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
err = regulator_enable(anx6345->dvdd12);
err = regulator_enable(anx6345->dvdd25);
gpiod_set_value_cansleep(anx6345->gpiod_reset, 0);
anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
if (anx6345->panel)
drm_panel_prepare(anx6345->panel);
anx6345->powered = true;
static void anx6345_poweroff(struct anx6345 *anx6345)
gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
if (anx6345->panel)
drm_panel_unprepare(anx6345->panel);
err = regulator_disable(anx6345->dvdd25);
err = regulator_disable(anx6345->dvdd12);
anx6345->powered = false;
static int anx6345_start(struct anx6345 *anx6345)
if (!anx6345->powered)
anx6345_poweron(anx6345);
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
err = anx6345_tx_initialization(anx6345);
anx6345_poweroff(anx6345);
err = anx6345_dp_link_training(anx6345);
anx6345_poweroff(anx6345);
static int anx6345_config_dp_output(struct anx6345 *anx6345)
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
return anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
static int anx6345_get_downstream_info(struct anx6345 *anx6345)
err = drm_dp_dpcd_readb(&anx6345->aux, DP_SINK_COUNT, &value);
struct anx6345 *anx6345 = connector_to_anx6345(connector);
mutex_lock(&anx6345->lock);
if (!anx6345->drm_edid) {
if (!anx6345->powered) {
anx6345_poweron(anx6345);
err = anx6345_get_downstream_info(anx6345);
anx6345->drm_edid = drm_edid_read_ddc(connector, &anx6345->aux.ddc);
if (!anx6345->drm_edid)
err = drm_edid_connector_update(connector, anx6345->drm_edid);
anx6345_poweroff(anx6345);
mutex_unlock(&anx6345->lock);
if (!num_modes && anx6345->panel)
num_modes += drm_panel_get_modes(anx6345->panel, connector);
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
anx6345->aux.name = "DP-AUX";
anx6345->aux.dev = &anx6345->client->dev;
anx6345->aux.drm_dev = bridge->dev;
anx6345->aux.transfer = anx6345_aux_transfer;
err = drm_dp_aux_register(&anx6345->aux);
err = drm_connector_init(bridge->dev, &anx6345->connector,
drm_connector_helper_add(&anx6345->connector,
anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD;
err = drm_connector_attach_encoder(&anx6345->connector,
err = drm_connector_register(&anx6345->connector);
drm_connector_cleanup(&anx6345->connector);
drm_dp_aux_unregister(&anx6345->aux);
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
if (anx6345->panel)
drm_panel_disable(anx6345->panel);
if (anx6345->powered)
anx6345_poweroff(anx6345);
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
if (anx6345->panel)
drm_panel_enable(anx6345->panel);
err = anx6345_start(anx6345);
err = anx6345_config_dp_output(anx6345);
static void unregister_i2c_dummy_clients(struct anx6345 *anx6345)
for (i = 1; i < ARRAY_SIZE(anx6345->i2c_clients); i++)
if (anx6345->i2c_clients[i] &&
anx6345->i2c_clients[i]->addr != anx6345->client->addr)
i2c_unregister_device(anx6345->i2c_clients[i]);
static bool anx6345_get_chip_id(struct anx6345 *anx6345)
if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDL_REG, &idl))
if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDH_REG, &idh))
anx6345->chipid = (u8)idl | ((u8)idh << 8);
if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_VERSION_REG,
if (anx6345->chipid == anx6345_chipid_list[i]) {
anx6345->chipid, version);
anx6345->chipid, version);
struct anx6345 *anx6345;
anx6345 = devm_drm_bridge_alloc(&client->dev, struct anx6345, bridge,
if (IS_ERR(anx6345))
return PTR_ERR(anx6345);
mutex_init(&anx6345->lock);
anx6345->bridge.of_node = client->dev.of_node;
anx6345->client = client;
i2c_set_clientdata(client, anx6345);
dev = &anx6345->client->dev;
static inline struct anx6345 *connector_to_anx6345(struct drm_connector *c)
&anx6345->panel, NULL);
anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12");
if (IS_ERR(anx6345->dvdd12)) {
if (PTR_ERR(anx6345->dvdd12) != -EPROBE_DEFER)
PTR_ERR(anx6345->dvdd12));
return PTR_ERR(anx6345->dvdd12);
anx6345->dvdd25 = devm_regulator_get(dev, "dvdd25");
return container_of(c, struct anx6345, connector);
if (IS_ERR(anx6345->dvdd25)) {
if (PTR_ERR(anx6345->dvdd25) != -EPROBE_DEFER)
PTR_ERR(anx6345->dvdd25));
return PTR_ERR(anx6345->dvdd25);
anx6345->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(anx6345->gpiod_reset)) {
return PTR_ERR(anx6345->gpiod_reset);
anx6345->i2c_clients[i] = i2c_new_dummy_device(client->adapter,
anx6345->i2c_clients[i] = client;
if (IS_ERR(anx6345->i2c_clients[i])) {
err = PTR_ERR(anx6345->i2c_clients[i]);
anx6345->map[i] = devm_regmap_init_i2c(anx6345->i2c_clients[i],
static inline struct anx6345 *bridge_to_anx6345(struct drm_bridge *bridge)
if (IS_ERR(anx6345->map[i])) {
err = PTR_ERR(anx6345->map[i]);
anx6345_poweron(anx6345);
if (anx6345_get_chip_id(anx6345)) {
drm_bridge_add(&anx6345->bridge);
anx6345_poweroff(anx6345);
return container_of(bridge, struct anx6345, bridge);
unregister_i2c_dummy_clients(anx6345);
struct anx6345 *anx6345 = i2c_get_clientdata(client);
drm_bridge_remove(&anx6345->bridge);
unregister_i2c_dummy_clients(anx6345);
drm_edid_free(anx6345->drm_edid);
mutex_destroy(&anx6345->lock);
struct anx6345 *anx6345 = container_of(aux, struct anx6345, aux);
return anx_dp_aux_transfer(anx6345->map[I2C_IDX_DPTX], msg);
static int anx6345_dp_link_training(struct anx6345 *anx6345)