Unverified Commit 77674e72 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Robert Foss
Browse files

drm/bridge: ti-sn65dsi86: Group code in sections



Reorganize the functions in sections, related to connector operations,
bridge operations, AUX adapter, GPIO controller and probe & remove.

This prepares for proper support of DRM_BRIDGE_ATTACH_NO_CONNECTOR that
will add more functions, to ensure that the code will stay readable.

No functional change intended.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: default avatarStephen Boyd <swboyd@chromium.org>
Reviewed-by: default avatarDouglas Anderson <dianders@chromium.org>
Signed-off-by: default avatarRobert Foss <robert.foss@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210624000304.16281-6-laurent.pinchart+renesas@ideasonboard.com
parent 4e5763f0
Loading
Loading
Loading
Loading
+324 −301
Original line number Diff line number Diff line
@@ -394,7 +394,211 @@ static void ti_sn65dsi86_debugfs_init(struct ti_sn65dsi86 *pdata)
	debugfs_create_file("status", 0600, debugfs, pdata, &status_fops);
}

/* Connector funcs */
/* -----------------------------------------------------------------------------
 * Auxiliary Devices (*not* AUX)
 */

static void ti_sn65dsi86_uninit_aux(void *data)
{
	auxiliary_device_uninit(data);
}

static void ti_sn65dsi86_delete_aux(void *data)
{
	auxiliary_device_delete(data);
}

/*
 * AUX bus docs say that a non-NULL release is mandatory, but it makes no
 * sense for the model used here where all of the aux devices are allocated
 * in the single shared structure. We'll use this noop as a workaround.
 */
static void ti_sn65dsi86_noop(struct device *dev) {}

static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
				       struct auxiliary_device *aux,
				       const char *name)
{
	struct device *dev = pdata->dev;
	int ret;

	aux->name = name;
	aux->dev.parent = dev;
	aux->dev.release = ti_sn65dsi86_noop;
	device_set_of_node_from_dev(&aux->dev, dev);
	ret = auxiliary_device_init(aux);
	if (ret)
		return ret;
	ret = devm_add_action_or_reset(dev, ti_sn65dsi86_uninit_aux, aux);
	if (ret)
		return ret;

	ret = auxiliary_device_add(aux);
	if (ret)
		return ret;
	ret = devm_add_action_or_reset(dev, ti_sn65dsi86_delete_aux, aux);

	return ret;
}

/* -----------------------------------------------------------------------------
 * AUX Adapter
 */

static struct ti_sn65dsi86 *aux_to_ti_sn65dsi86(struct drm_dp_aux *aux)
{
	return container_of(aux, struct ti_sn65dsi86, aux);
}

static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux,
				  struct drm_dp_aux_msg *msg)
{
	struct ti_sn65dsi86 *pdata = aux_to_ti_sn65dsi86(aux);
	u32 request = msg->request & ~(DP_AUX_I2C_MOT | DP_AUX_I2C_WRITE_STATUS_UPDATE);
	u32 request_val = AUX_CMD_REQ(msg->request);
	u8 *buf = msg->buffer;
	unsigned int len = msg->size;
	unsigned int val;
	int ret;
	u8 addr_len[SN_AUX_LENGTH_REG + 1 - SN_AUX_ADDR_19_16_REG];

	if (len > SN_AUX_MAX_PAYLOAD_BYTES)
		return -EINVAL;

	pm_runtime_get_sync(pdata->dev);
	mutex_lock(&pdata->comms_mutex);

	/*
	 * If someone tries to do a DDC over AUX transaction before pre_enable()
	 * on a device without a dedicated reference clock then we just can't
	 * do it. Fail right away. This prevents non-refclk users from reading
	 * the EDID before enabling the panel but such is life.
	 */
	if (!pdata->comms_enabled) {
		ret = -EIO;
		goto exit;
	}

	switch (request) {
	case DP_AUX_NATIVE_WRITE:
	case DP_AUX_I2C_WRITE:
	case DP_AUX_NATIVE_READ:
	case DP_AUX_I2C_READ:
		regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val);
		/* Assume it's good */
		msg->reply = 0;
		break;
	default:
		ret = -EINVAL;
		goto exit;
	}

	BUILD_BUG_ON(sizeof(addr_len) != sizeof(__be32));
	put_unaligned_be32((msg->address & SN_AUX_ADDR_MASK) << 8 | len,
			   addr_len);
	regmap_bulk_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, addr_len,
			  ARRAY_SIZE(addr_len));

	if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE)
		regmap_bulk_write(pdata->regmap, SN_AUX_WDATA_REG(0), buf, len);

	/* Clear old status bits before start so we don't get confused */
	regmap_write(pdata->regmap, SN_AUX_CMD_STATUS_REG,
		     AUX_IRQ_STATUS_NAT_I2C_FAIL |
		     AUX_IRQ_STATUS_AUX_RPLY_TOUT |
		     AUX_IRQ_STATUS_AUX_SHORT);

	regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val | AUX_CMD_SEND);

	/* Zero delay loop because i2c transactions are slow already */
	ret = regmap_read_poll_timeout(pdata->regmap, SN_AUX_CMD_REG, val,
				       !(val & AUX_CMD_SEND), 0, 50 * 1000);
	if (ret)
		goto exit;

	ret = regmap_read(pdata->regmap, SN_AUX_CMD_STATUS_REG, &val);
	if (ret)
		goto exit;

	if (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT) {
		/*
		 * The hardware tried the message seven times per the DP spec
		 * but it hit a timeout. We ignore defers here because they're
		 * handled in hardware.
		 */
		ret = -ETIMEDOUT;
		goto exit;
	}

	if (val & AUX_IRQ_STATUS_AUX_SHORT) {
		ret = regmap_read(pdata->regmap, SN_AUX_LENGTH_REG, &len);
		if (ret)
			goto exit;
	} else if (val & AUX_IRQ_STATUS_NAT_I2C_FAIL) {
		switch (request) {
		case DP_AUX_I2C_WRITE:
		case DP_AUX_I2C_READ:
			msg->reply |= DP_AUX_I2C_REPLY_NACK;
			break;
		case DP_AUX_NATIVE_READ:
		case DP_AUX_NATIVE_WRITE:
			msg->reply |= DP_AUX_NATIVE_REPLY_NACK;
			break;
		}
		len = 0;
		goto exit;
	}

	if (request != DP_AUX_NATIVE_WRITE && request != DP_AUX_I2C_WRITE && len != 0)
		ret = regmap_bulk_read(pdata->regmap, SN_AUX_RDATA_REG(0), buf, len);

exit:
	mutex_unlock(&pdata->comms_mutex);
	pm_runtime_mark_last_busy(pdata->dev);
	pm_runtime_put_autosuspend(pdata->dev);

	if (ret)
		return ret;
	return len;
}

static int ti_sn_aux_probe(struct auxiliary_device *adev,
			   const struct auxiliary_device_id *id)
{
	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
	int ret;

	pdata->aux.name = "ti-sn65dsi86-aux";
	pdata->aux.dev = &adev->dev;
	pdata->aux.transfer = ti_sn_aux_transfer;
	drm_dp_aux_init(&pdata->aux);

	ret = devm_of_dp_aux_populate_ep_devices(&pdata->aux);
	if (ret)
		return ret;

	/*
	 * The eDP to MIPI bridge parts don't work until the AUX channel is
	 * setup so we don't add it in the main driver probe, we add it now.
	 */
	return ti_sn65dsi86_add_aux_device(pdata, &pdata->bridge_aux, "bridge");
}

static const struct auxiliary_device_id ti_sn_aux_id_table[] = {
	{ .name = "ti_sn65dsi86.aux", },
	{},
};

static struct auxiliary_driver ti_sn_aux_driver = {
	.name = "aux",
	.probe = ti_sn_aux_probe,
	.id_table = ti_sn_aux_id_table,
};

/* -----------------------------------------------------------------------------
 * DRM Connector Operations
 */

static struct ti_sn65dsi86 *
connector_to_ti_sn65dsi86(struct drm_connector *connector)
{
@@ -432,25 +636,15 @@ static const struct drm_connector_funcs ti_sn_bridge_connector_funcs = {
	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};

/*------------------------------------------------------------------------------
 * DRM Bridge
 */

static struct ti_sn65dsi86 *bridge_to_ti_sn65dsi86(struct drm_bridge *bridge)
{
	return container_of(bridge, struct ti_sn65dsi86, bridge);
}

static int ti_sn65dsi86_parse_regulators(struct ti_sn65dsi86 *pdata)
{
	unsigned int i;
	const char * const ti_sn_bridge_supply_names[] = {
		"vcca", "vcc", "vccio", "vpll",
	};

	for (i = 0; i < SN_REGULATOR_SUPPLY_NUM; i++)
		pdata->supplies[i].supply = ti_sn_bridge_supply_names[i];

	return devm_regulator_bulk_get(pdata->dev, SN_REGULATOR_SUPPLY_NUM,
				       pdata->supplies);
}

static int ti_sn_bridge_attach(struct drm_bridge *bridge,
			       enum drm_bridge_attach_flags flags)
{
@@ -916,137 +1110,135 @@ static const struct drm_bridge_funcs ti_sn_bridge_funcs = {
	.post_disable = ti_sn_bridge_post_disable,
};

static struct ti_sn65dsi86 *aux_to_ti_sn65dsi86(struct drm_dp_aux *aux)
{
	return container_of(aux, struct ti_sn65dsi86, aux);
}

static ssize_t ti_sn_aux_transfer(struct drm_dp_aux *aux,
				  struct drm_dp_aux_msg *msg)
static void ti_sn_bridge_parse_lanes(struct ti_sn65dsi86 *pdata,
				     struct device_node *np)
{
	struct ti_sn65dsi86 *pdata = aux_to_ti_sn65dsi86(aux);
	u32 request = msg->request & ~(DP_AUX_I2C_MOT | DP_AUX_I2C_WRITE_STATUS_UPDATE);
	u32 request_val = AUX_CMD_REQ(msg->request);
	u8 *buf = msg->buffer;
	unsigned int len = msg->size;
	unsigned int val;
	int ret;
	u8 addr_len[SN_AUX_LENGTH_REG + 1 - SN_AUX_ADDR_19_16_REG];

	if (len > SN_AUX_MAX_PAYLOAD_BYTES)
		return -EINVAL;

	pm_runtime_get_sync(pdata->dev);
	mutex_lock(&pdata->comms_mutex);
	u32 lane_assignments[SN_MAX_DP_LANES] = { 0, 1, 2, 3 };
	u32 lane_polarities[SN_MAX_DP_LANES] = { };
	struct device_node *endpoint;
	u8 ln_assign = 0;
	u8 ln_polrs = 0;
	int dp_lanes;
	int i;

	/*
	 * If someone tries to do a DDC over AUX transaction before pre_enable()
	 * on a device without a dedicated reference clock then we just can't
	 * do it. Fail right away. This prevents non-refclk users from reading
	 * the EDID before enabling the panel but such is life.
	 */
	if (!pdata->comms_enabled) {
		ret = -EIO;
		goto exit;
	}

	switch (request) {
	case DP_AUX_NATIVE_WRITE:
	case DP_AUX_I2C_WRITE:
	case DP_AUX_NATIVE_READ:
	case DP_AUX_I2C_READ:
		regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val);
		/* Assume it's good */
		msg->reply = 0;
		break;
	default:
		ret = -EINVAL;
		goto exit;
	 * Read config from the device tree about lane remapping and lane
	 * polarities.  These are optional and we assume identity map and
	 * normal polarity if nothing is specified.  It's OK to specify just
	 * data-lanes but not lane-polarities but not vice versa.
	 *
	 * Error checking is light (we just make sure we don't crash or
	 * buffer overrun) and we assume dts is well formed and specifying
	 * mappings that the hardware supports.
	 */
	endpoint = of_graph_get_endpoint_by_regs(np, 1, -1);
	dp_lanes = of_property_count_u32_elems(endpoint, "data-lanes");
	if (dp_lanes > 0 && dp_lanes <= SN_MAX_DP_LANES) {
		of_property_read_u32_array(endpoint, "data-lanes",
					   lane_assignments, dp_lanes);
		of_property_read_u32_array(endpoint, "lane-polarities",
					   lane_polarities, dp_lanes);
	} else {
		dp_lanes = SN_MAX_DP_LANES;
	}
	of_node_put(endpoint);

	BUILD_BUG_ON(sizeof(addr_len) != sizeof(__be32));
	put_unaligned_be32((msg->address & SN_AUX_ADDR_MASK) << 8 | len,
			   addr_len);
	regmap_bulk_write(pdata->regmap, SN_AUX_ADDR_19_16_REG, addr_len,
			  ARRAY_SIZE(addr_len));

	if (request == DP_AUX_NATIVE_WRITE || request == DP_AUX_I2C_WRITE)
		regmap_bulk_write(pdata->regmap, SN_AUX_WDATA_REG(0), buf, len);
	/*
	 * Convert into register format.  Loop over all lanes even if
	 * data-lanes had fewer elements so that we nicely initialize
	 * the LN_ASSIGN register.
	 */
	for (i = SN_MAX_DP_LANES - 1; i >= 0; i--) {
		ln_assign = ln_assign << LN_ASSIGN_WIDTH | lane_assignments[i];
		ln_polrs = ln_polrs << 1 | lane_polarities[i];
	}

	/* Clear old status bits before start so we don't get confused */
	regmap_write(pdata->regmap, SN_AUX_CMD_STATUS_REG,
		     AUX_IRQ_STATUS_NAT_I2C_FAIL |
		     AUX_IRQ_STATUS_AUX_RPLY_TOUT |
		     AUX_IRQ_STATUS_AUX_SHORT);
	/* Stash in our struct for when we power on */
	pdata->dp_lanes = dp_lanes;
	pdata->ln_assign = ln_assign;
	pdata->ln_polrs = ln_polrs;
}

	regmap_write(pdata->regmap, SN_AUX_CMD_REG, request_val | AUX_CMD_SEND);
static int ti_sn_bridge_parse_dsi_host(struct ti_sn65dsi86 *pdata)
{
	struct device_node *np = pdata->dev->of_node;

	/* Zero delay loop because i2c transactions are slow already */
	ret = regmap_read_poll_timeout(pdata->regmap, SN_AUX_CMD_REG, val,
				       !(val & AUX_CMD_SEND), 0, 50 * 1000);
	if (ret)
		goto exit;
	pdata->host_node = of_graph_get_remote_node(np, 0, 0);

	ret = regmap_read(pdata->regmap, SN_AUX_CMD_STATUS_REG, &val);
	if (ret)
		goto exit;
	if (!pdata->host_node) {
		DRM_ERROR("remote dsi host node not found\n");
		return -ENODEV;
	}

	if (val & AUX_IRQ_STATUS_AUX_RPLY_TOUT) {
		/*
		 * The hardware tried the message seven times per the DP spec
		 * but it hit a timeout. We ignore defers here because they're
		 * handled in hardware.
		 */
		ret = -ETIMEDOUT;
		goto exit;
	return 0;
}

	if (val & AUX_IRQ_STATUS_AUX_SHORT) {
		ret = regmap_read(pdata->regmap, SN_AUX_LENGTH_REG, &len);
static int ti_sn_bridge_probe(struct auxiliary_device *adev,
			      const struct auxiliary_device_id *id)
{
	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
	struct device_node *np = pdata->dev->of_node;
	struct drm_panel *panel;
	int ret;

	ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
	if (ret)
			goto exit;
	} else if (val & AUX_IRQ_STATUS_NAT_I2C_FAIL) {
		switch (request) {
		case DP_AUX_I2C_WRITE:
		case DP_AUX_I2C_READ:
			msg->reply |= DP_AUX_I2C_REPLY_NACK;
			break;
		case DP_AUX_NATIVE_READ:
		case DP_AUX_NATIVE_WRITE:
			msg->reply |= DP_AUX_NATIVE_REPLY_NACK;
			break;
		}
		len = 0;
		goto exit;
	}
		return dev_err_probe(&adev->dev, ret,
				     "could not find any panel node\n");

	if (request != DP_AUX_NATIVE_WRITE && request != DP_AUX_I2C_WRITE && len != 0)
		ret = regmap_bulk_read(pdata->regmap, SN_AUX_RDATA_REG(0), buf, len);
	pdata->next_bridge = devm_drm_panel_bridge_add(pdata->dev, panel);
	if (IS_ERR(pdata->next_bridge)) {
		DRM_ERROR("failed to create panel bridge\n");
		return PTR_ERR(pdata->next_bridge);
	}

exit:
	mutex_unlock(&pdata->comms_mutex);
	pm_runtime_mark_last_busy(pdata->dev);
	pm_runtime_put_autosuspend(pdata->dev);
	ti_sn_bridge_parse_lanes(pdata, np);

	ret = ti_sn_bridge_parse_dsi_host(pdata);
	if (ret)
		return ret;
	return len;

	pdata->bridge.funcs = &ti_sn_bridge_funcs;
	pdata->bridge.of_node = np;

	drm_bridge_add(&pdata->bridge);

	return 0;
}

static int ti_sn_bridge_parse_dsi_host(struct ti_sn65dsi86 *pdata)
static void ti_sn_bridge_remove(struct auxiliary_device *adev)
{
	struct device_node *np = pdata->dev->of_node;
	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);

	pdata->host_node = of_graph_get_remote_node(np, 0, 0);
	if (!pdata)
		return;

	if (!pdata->host_node) {
		DRM_ERROR("remote dsi host node not found\n");
		return -ENODEV;
	if (pdata->dsi) {
		mipi_dsi_detach(pdata->dsi);
		mipi_dsi_device_unregister(pdata->dsi);
	}

	return 0;
	drm_bridge_remove(&pdata->bridge);

	of_node_put(pdata->host_node);
}

static const struct auxiliary_device_id ti_sn_bridge_id_table[] = {
	{ .name = "ti_sn65dsi86.bridge", },
	{},
};

static struct auxiliary_driver ti_sn_bridge_driver = {
	.name = "bridge",
	.probe = ti_sn_bridge_probe,
	.remove = ti_sn_bridge_remove,
	.id_table = ti_sn_bridge_id_table,
};

/* -----------------------------------------------------------------------------
 * GPIO Controller
 */

#if defined(CONFIG_OF_GPIO)

static int tn_sn_bridge_of_xlate(struct gpio_chip *chip,
@@ -1251,198 +1443,29 @@ static inline void ti_sn_gpio_unregister(void) {}

#endif

static void ti_sn_bridge_parse_lanes(struct ti_sn65dsi86 *pdata,
				     struct device_node *np)
{
	u32 lane_assignments[SN_MAX_DP_LANES] = { 0, 1, 2, 3 };
	u32 lane_polarities[SN_MAX_DP_LANES] = { };
	struct device_node *endpoint;
	u8 ln_assign = 0;
	u8 ln_polrs = 0;
	int dp_lanes;
	int i;

	/*
	 * Read config from the device tree about lane remapping and lane
	 * polarities.  These are optional and we assume identity map and
	 * normal polarity if nothing is specified.  It's OK to specify just
	 * data-lanes but not lane-polarities but not vice versa.
	 *
	 * Error checking is light (we just make sure we don't crash or
	 * buffer overrun) and we assume dts is well formed and specifying
	 * mappings that the hardware supports.
	 */
	endpoint = of_graph_get_endpoint_by_regs(np, 1, -1);
	dp_lanes = of_property_count_u32_elems(endpoint, "data-lanes");
	if (dp_lanes > 0 && dp_lanes <= SN_MAX_DP_LANES) {
		of_property_read_u32_array(endpoint, "data-lanes",
					   lane_assignments, dp_lanes);
		of_property_read_u32_array(endpoint, "lane-polarities",
					   lane_polarities, dp_lanes);
	} else {
		dp_lanes = SN_MAX_DP_LANES;
	}
	of_node_put(endpoint);

	/*
	 * Convert into register format.  Loop over all lanes even if
	 * data-lanes had fewer elements so that we nicely initialize
	 * the LN_ASSIGN register.
/* -----------------------------------------------------------------------------
 * Probe & Remove
 */
	for (i = SN_MAX_DP_LANES - 1; i >= 0; i--) {
		ln_assign = ln_assign << LN_ASSIGN_WIDTH | lane_assignments[i];
		ln_polrs = ln_polrs << 1 | lane_polarities[i];
	}

	/* Stash in our struct for when we power on */
	pdata->dp_lanes = dp_lanes;
	pdata->ln_assign = ln_assign;
	pdata->ln_polrs = ln_polrs;
}

static int ti_sn_bridge_probe(struct auxiliary_device *adev,
			      const struct auxiliary_device_id *id)
{
	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
	struct device_node *np = pdata->dev->of_node;
	struct drm_panel *panel;
	int ret;

	ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, NULL);
	if (ret)
		return dev_err_probe(&adev->dev, ret,
				     "could not find any panel node\n");

	pdata->next_bridge = devm_drm_panel_bridge_add(pdata->dev, panel);
	if (IS_ERR(pdata->next_bridge)) {
		DRM_ERROR("failed to create panel bridge\n");
		return PTR_ERR(pdata->next_bridge);
	}

	ti_sn_bridge_parse_lanes(pdata, np);

	ret = ti_sn_bridge_parse_dsi_host(pdata);
	if (ret)
		return ret;

	pdata->bridge.funcs = &ti_sn_bridge_funcs;
	pdata->bridge.of_node = np;

	drm_bridge_add(&pdata->bridge);

	return 0;
}

static void ti_sn_bridge_remove(struct auxiliary_device *adev)
{
	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);

	if (!pdata)
		return;

	if (pdata->dsi) {
		mipi_dsi_detach(pdata->dsi);
		mipi_dsi_device_unregister(pdata->dsi);
	}

	drm_bridge_remove(&pdata->bridge);

	of_node_put(pdata->host_node);
}

static const struct auxiliary_device_id ti_sn_bridge_id_table[] = {
	{ .name = "ti_sn65dsi86.bridge", },
	{},
};

static struct auxiliary_driver ti_sn_bridge_driver = {
	.name = "bridge",
	.probe = ti_sn_bridge_probe,
	.remove = ti_sn_bridge_remove,
	.id_table = ti_sn_bridge_id_table,
};

static void ti_sn65dsi86_runtime_disable(void *data)
{
	pm_runtime_disable(data);
}

static void ti_sn65dsi86_uninit_aux(void *data)
{
	auxiliary_device_uninit(data);
}

static void ti_sn65dsi86_delete_aux(void *data)
{
	auxiliary_device_delete(data);
}

/*
 * AUX bus docs say that a non-NULL release is mandatory, but it makes no
 * sense for the model used here where all of the aux devices are allocated
 * in the single shared structure. We'll use this noop as a workaround.
 */
static void ti_sn65dsi86_noop(struct device *dev) {}

static int ti_sn65dsi86_add_aux_device(struct ti_sn65dsi86 *pdata,
				       struct auxiliary_device *aux,
				       const char *name)
{
	struct device *dev = pdata->dev;
	int ret;

	aux->name = name;
	aux->dev.parent = dev;
	aux->dev.release = ti_sn65dsi86_noop;
	device_set_of_node_from_dev(&aux->dev, dev);
	ret = auxiliary_device_init(aux);
	if (ret)
		return ret;
	ret = devm_add_action_or_reset(dev, ti_sn65dsi86_uninit_aux, aux);
	if (ret)
		return ret;

	ret = auxiliary_device_add(aux);
	if (ret)
		return ret;
	ret = devm_add_action_or_reset(dev, ti_sn65dsi86_delete_aux, aux);

	return ret;
}

static int ti_sn_aux_probe(struct auxiliary_device *adev,
			   const struct auxiliary_device_id *id)
static int ti_sn65dsi86_parse_regulators(struct ti_sn65dsi86 *pdata)
{
	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
	int ret;

	pdata->aux.name = "ti-sn65dsi86-aux";
	pdata->aux.dev = &adev->dev;
	pdata->aux.transfer = ti_sn_aux_transfer;
	drm_dp_aux_init(&pdata->aux);
	unsigned int i;
	const char * const ti_sn_bridge_supply_names[] = {
		"vcca", "vcc", "vccio", "vpll",
	};

	ret = devm_of_dp_aux_populate_ep_devices(&pdata->aux);
	if (ret)
		return ret;
	for (i = 0; i < SN_REGULATOR_SUPPLY_NUM; i++)
		pdata->supplies[i].supply = ti_sn_bridge_supply_names[i];

	/*
	 * The eDP to MIPI bridge parts don't work until the AUX channel is
	 * setup so we don't add it in the main driver probe, we add it now.
	 */
	return ti_sn65dsi86_add_aux_device(pdata, &pdata->bridge_aux, "bridge");
	return devm_regulator_bulk_get(pdata->dev, SN_REGULATOR_SUPPLY_NUM,
				       pdata->supplies);
}

static const struct auxiliary_device_id ti_sn_aux_id_table[] = {
	{ .name = "ti_sn65dsi86.aux", },
	{},
};

static struct auxiliary_driver ti_sn_aux_driver = {
	.name = "aux",
	.probe = ti_sn_aux_probe,
	.id_table = ti_sn_aux_id_table,
};

static int ti_sn65dsi86_probe(struct i2c_client *client,
			      const struct i2c_device_id *id)
{