18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright(c) 2016, Analogix Semiconductor.
48c2ecf20Sopenharmony_ci * Copyright(c) 2017, Icenowy Zheng <icenowy@aosc.io>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Based on anx7808 driver obtained from chromeos with copyright:
78c2ecf20Sopenharmony_ci * Copyright(c) 2013, Google Inc.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
128c2ecf20Sopenharmony_ci#include <linux/i2c.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
178c2ecf20Sopenharmony_ci#include <linux/regmap.h>
188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
198c2ecf20Sopenharmony_ci#include <linux/types.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
228c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h>
238c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h>
248c2ecf20Sopenharmony_ci#include <drm/drm_crtc_helper.h>
258c2ecf20Sopenharmony_ci#include <drm/drm_dp_helper.h>
268c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
278c2ecf20Sopenharmony_ci#include <drm/drm_of.h>
288c2ecf20Sopenharmony_ci#include <drm/drm_panel.h>
298c2ecf20Sopenharmony_ci#include <drm/drm_print.h>
308c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "analogix-i2c-dptx.h"
338c2ecf20Sopenharmony_ci#include "analogix-i2c-txcommon.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define POLL_DELAY		50000 /* us */
368c2ecf20Sopenharmony_ci#define POLL_TIMEOUT		5000000 /* us */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define I2C_IDX_DPTX		0
398c2ecf20Sopenharmony_ci#define I2C_IDX_TXCOM		1
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic const u8 anx6345_i2c_addresses[] = {
428c2ecf20Sopenharmony_ci	[I2C_IDX_DPTX]	= 0x70,
438c2ecf20Sopenharmony_ci	[I2C_IDX_TXCOM]	= 0x72,
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci#define I2C_NUM_ADDRESSES	ARRAY_SIZE(anx6345_i2c_addresses)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistruct anx6345 {
488c2ecf20Sopenharmony_ci	struct drm_dp_aux aux;
498c2ecf20Sopenharmony_ci	struct drm_bridge bridge;
508c2ecf20Sopenharmony_ci	struct i2c_client *client;
518c2ecf20Sopenharmony_ci	struct edid *edid;
528c2ecf20Sopenharmony_ci	struct drm_connector connector;
538c2ecf20Sopenharmony_ci	struct drm_panel *panel;
548c2ecf20Sopenharmony_ci	struct regulator *dvdd12;
558c2ecf20Sopenharmony_ci	struct regulator *dvdd25;
568c2ecf20Sopenharmony_ci	struct gpio_desc *gpiod_reset;
578c2ecf20Sopenharmony_ci	struct mutex lock;	/* protect EDID access */
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* I2C Slave addresses of ANX6345 are mapped as DPTX and SYS */
608c2ecf20Sopenharmony_ci	struct i2c_client *i2c_clients[I2C_NUM_ADDRESSES];
618c2ecf20Sopenharmony_ci	struct regmap *map[I2C_NUM_ADDRESSES];
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	u16 chipid;
648c2ecf20Sopenharmony_ci	u8 dpcd[DP_RECEIVER_CAP_SIZE];
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	bool powered;
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic inline struct anx6345 *connector_to_anx6345(struct drm_connector *c)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	return container_of(c, struct anx6345, connector);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic inline struct anx6345 *bridge_to_anx6345(struct drm_bridge *bridge)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	return container_of(bridge, struct anx6345, bridge);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int anx6345_set_bits(struct regmap *map, u8 reg, u8 mask)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	return regmap_update_bits(map, reg, mask, mask);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int anx6345_clear_bits(struct regmap *map, u8 reg, u8 mask)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	return regmap_update_bits(map, reg, mask, 0);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic ssize_t anx6345_aux_transfer(struct drm_dp_aux *aux,
908c2ecf20Sopenharmony_ci				    struct drm_dp_aux_msg *msg)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct anx6345 *anx6345 = container_of(aux, struct anx6345, aux);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return anx_dp_aux_transfer(anx6345->map[I2C_IDX_DPTX], msg);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int anx6345_dp_link_training(struct anx6345 *anx6345)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	unsigned int value;
1008c2ecf20Sopenharmony_ci	u8 dp_bw, dpcd[2];
1018c2ecf20Sopenharmony_ci	int err;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
1048c2ecf20Sopenharmony_ci				 SP_POWERDOWN_CTRL_REG,
1058c2ecf20Sopenharmony_ci				 SP_TOTAL_PD);
1068c2ecf20Sopenharmony_ci	if (err)
1078c2ecf20Sopenharmony_ci		return err;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_readb(&anx6345->aux, DP_MAX_LINK_RATE, &dp_bw);
1108c2ecf20Sopenharmony_ci	if (err < 0)
1118c2ecf20Sopenharmony_ci		return err;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	switch (dp_bw) {
1148c2ecf20Sopenharmony_ci	case DP_LINK_BW_1_62:
1158c2ecf20Sopenharmony_ci	case DP_LINK_BW_2_7:
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	default:
1198c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("DP bandwidth (%#02x) not supported\n", dp_bw);
1208c2ecf20Sopenharmony_ci		return -EINVAL;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
1248c2ecf20Sopenharmony_ci			       SP_VIDEO_MUTE);
1258c2ecf20Sopenharmony_ci	if (err)
1268c2ecf20Sopenharmony_ci		return err;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
1298c2ecf20Sopenharmony_ci				 SP_VID_CTRL1_REG, SP_VIDEO_EN);
1308c2ecf20Sopenharmony_ci	if (err)
1318c2ecf20Sopenharmony_ci		return err;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* Get DPCD info */
1348c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_read(&anx6345->aux, DP_DPCD_REV,
1358c2ecf20Sopenharmony_ci			       &anx6345->dpcd, DP_RECEIVER_CAP_SIZE);
1368c2ecf20Sopenharmony_ci	if (err < 0) {
1378c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to read DPCD: %d\n", err);
1388c2ecf20Sopenharmony_ci		return err;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* Clear channel x SERDES power down */
1428c2ecf20Sopenharmony_ci	err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
1438c2ecf20Sopenharmony_ci				 SP_DP_ANALOG_POWER_DOWN_REG, SP_CH0_PD);
1448c2ecf20Sopenharmony_ci	if (err)
1458c2ecf20Sopenharmony_ci		return err;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/*
1488c2ecf20Sopenharmony_ci	 * Power up the sink (DP_SET_POWER register is only available on DPCD
1498c2ecf20Sopenharmony_ci	 * v1.1 and later).
1508c2ecf20Sopenharmony_ci	 */
1518c2ecf20Sopenharmony_ci	if (anx6345->dpcd[DP_DPCD_REV] >= 0x11) {
1528c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_readb(&anx6345->aux, DP_SET_POWER, &dpcd[0]);
1538c2ecf20Sopenharmony_ci		if (err < 0) {
1548c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to read DP_SET_POWER register: %d\n",
1558c2ecf20Sopenharmony_ci				  err);
1568c2ecf20Sopenharmony_ci			return err;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		dpcd[0] &= ~DP_SET_POWER_MASK;
1608c2ecf20Sopenharmony_ci		dpcd[0] |= DP_SET_POWER_D0;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_writeb(&anx6345->aux, DP_SET_POWER, dpcd[0]);
1638c2ecf20Sopenharmony_ci		if (err < 0) {
1648c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to power up DisplayPort link: %d\n",
1658c2ecf20Sopenharmony_ci				  err);
1668c2ecf20Sopenharmony_ci			return err;
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		/*
1708c2ecf20Sopenharmony_ci		 * According to the DP 1.1 specification, a "Sink Device must
1718c2ecf20Sopenharmony_ci		 * exit the power saving state within 1 ms" (Section 2.5.3.1,
1728c2ecf20Sopenharmony_ci		 * Table 5-52, "Sink Control Field" (register 0x600).
1738c2ecf20Sopenharmony_ci		 */
1748c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Possibly enable downspread on the sink */
1788c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_DPTX],
1798c2ecf20Sopenharmony_ci			   SP_DP_DOWNSPREAD_CTRL1_REG, 0);
1808c2ecf20Sopenharmony_ci	if (err)
1818c2ecf20Sopenharmony_ci		return err;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (anx6345->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) {
1848c2ecf20Sopenharmony_ci		DRM_DEBUG("Enable downspread on the sink\n");
1858c2ecf20Sopenharmony_ci		/* 4000PPM */
1868c2ecf20Sopenharmony_ci		err = regmap_write(anx6345->map[I2C_IDX_DPTX],
1878c2ecf20Sopenharmony_ci				   SP_DP_DOWNSPREAD_CTRL1_REG, 8);
1888c2ecf20Sopenharmony_ci		if (err)
1898c2ecf20Sopenharmony_ci			return err;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL,
1928c2ecf20Sopenharmony_ci					 DP_SPREAD_AMP_0_5);
1938c2ecf20Sopenharmony_ci		if (err < 0)
1948c2ecf20Sopenharmony_ci			return err;
1958c2ecf20Sopenharmony_ci	} else {
1968c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL, 0);
1978c2ecf20Sopenharmony_ci		if (err < 0)
1988c2ecf20Sopenharmony_ci			return err;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* Set the lane count and the link rate on the sink */
2028c2ecf20Sopenharmony_ci	if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
2038c2ecf20Sopenharmony_ci		err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
2048c2ecf20Sopenharmony_ci				       SP_DP_SYSTEM_CTRL_BASE + 4,
2058c2ecf20Sopenharmony_ci				       SP_ENHANCED_MODE);
2068c2ecf20Sopenharmony_ci	else
2078c2ecf20Sopenharmony_ci		err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
2088c2ecf20Sopenharmony_ci					 SP_DP_SYSTEM_CTRL_BASE + 4,
2098c2ecf20Sopenharmony_ci					 SP_ENHANCED_MODE);
2108c2ecf20Sopenharmony_ci	if (err)
2118c2ecf20Sopenharmony_ci		return err;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	dpcd[0] = dp_bw;
2148c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_DPTX],
2158c2ecf20Sopenharmony_ci			   SP_DP_MAIN_LINK_BW_SET_REG, dpcd[0]);
2168c2ecf20Sopenharmony_ci	if (err)
2178c2ecf20Sopenharmony_ci		return err;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	dpcd[1] = drm_dp_max_lane_count(anx6345->dpcd);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_DPTX],
2228c2ecf20Sopenharmony_ci			   SP_DP_LANE_COUNT_SET_REG, dpcd[1]);
2238c2ecf20Sopenharmony_ci	if (err)
2248c2ecf20Sopenharmony_ci		return err;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
2278c2ecf20Sopenharmony_ci		dpcd[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_write(&anx6345->aux, DP_LINK_BW_SET, dpcd,
2308c2ecf20Sopenharmony_ci				sizeof(dpcd));
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (err < 0) {
2338c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to configure link: %d\n", err);
2348c2ecf20Sopenharmony_ci		return err;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* Start training on the source */
2388c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_LT_CTRL_REG,
2398c2ecf20Sopenharmony_ci			   SP_LT_EN);
2408c2ecf20Sopenharmony_ci	if (err)
2418c2ecf20Sopenharmony_ci		return err;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return regmap_read_poll_timeout(anx6345->map[I2C_IDX_DPTX],
2448c2ecf20Sopenharmony_ci				       SP_DP_LT_CTRL_REG,
2458c2ecf20Sopenharmony_ci				       value, !(value & SP_DP_LT_INPROGRESS),
2468c2ecf20Sopenharmony_ci				       POLL_DELAY, POLL_TIMEOUT);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic int anx6345_tx_initialization(struct anx6345 *anx6345)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	int err, i;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* FIXME: colordepth is hardcoded for now */
2548c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL2_REG,
2558c2ecf20Sopenharmony_ci			   SP_IN_BPC_6BIT << SP_IN_BPC_SHIFT);
2568c2ecf20Sopenharmony_ci	if (err)
2578c2ecf20Sopenharmony_ci		return err;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_PLL_CTRL_REG, 0);
2608c2ecf20Sopenharmony_ci	if (err)
2618c2ecf20Sopenharmony_ci		return err;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_TXCOM],
2648c2ecf20Sopenharmony_ci			   SP_ANALOG_DEBUG1_REG, 0);
2658c2ecf20Sopenharmony_ci	if (err)
2668c2ecf20Sopenharmony_ci		return err;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_DPTX],
2698c2ecf20Sopenharmony_ci			   SP_DP_LINK_DEBUG_CTRL_REG,
2708c2ecf20Sopenharmony_ci			   SP_NEW_PRBS7 | SP_M_VID_DEBUG);
2718c2ecf20Sopenharmony_ci	if (err)
2728c2ecf20Sopenharmony_ci		return err;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	err = regmap_write(anx6345->map[I2C_IDX_DPTX],
2758c2ecf20Sopenharmony_ci			   SP_DP_ANALOG_POWER_DOWN_REG, 0);
2768c2ecf20Sopenharmony_ci	if (err)
2778c2ecf20Sopenharmony_ci		return err;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* Force HPD */
2808c2ecf20Sopenharmony_ci	err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
2818c2ecf20Sopenharmony_ci			       SP_DP_SYSTEM_CTRL_BASE + 3,
2828c2ecf20Sopenharmony_ci			       SP_HPD_FORCE | SP_HPD_CTRL);
2838c2ecf20Sopenharmony_ci	if (err)
2848c2ecf20Sopenharmony_ci		return err;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
2878c2ecf20Sopenharmony_ci		/* 4 lanes */
2888c2ecf20Sopenharmony_ci		err = regmap_write(anx6345->map[I2C_IDX_DPTX],
2898c2ecf20Sopenharmony_ci				   SP_DP_LANE0_LT_CTRL_REG + i, 0);
2908c2ecf20Sopenharmony_ci		if (err)
2918c2ecf20Sopenharmony_ci			return err;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/* Reset AUX */
2958c2ecf20Sopenharmony_ci	err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM],
2968c2ecf20Sopenharmony_ci			       SP_RESET_CTRL2_REG, SP_AUX_RST);
2978c2ecf20Sopenharmony_ci	if (err)
2988c2ecf20Sopenharmony_ci		return err;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
3018c2ecf20Sopenharmony_ci				 SP_RESET_CTRL2_REG, SP_AUX_RST);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic void anx6345_poweron(struct anx6345 *anx6345)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	int err;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/* Ensure reset is asserted before starting power on sequence */
3098c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
3108c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	err = regulator_enable(anx6345->dvdd12);
3138c2ecf20Sopenharmony_ci	if (err) {
3148c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to enable dvdd12 regulator: %d\n",
3158c2ecf20Sopenharmony_ci			  err);
3168c2ecf20Sopenharmony_ci		return;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* T1 - delay between VDD12 and VDD25 should be 0-2ms */
3208c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	err = regulator_enable(anx6345->dvdd25);
3238c2ecf20Sopenharmony_ci	if (err) {
3248c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to enable dvdd25 regulator: %d\n",
3258c2ecf20Sopenharmony_ci			  err);
3268c2ecf20Sopenharmony_ci		return;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* T2 - delay between RESETN and all power rail stable,
3308c2ecf20Sopenharmony_ci	 * should be 2-5ms
3318c2ecf20Sopenharmony_ci	 */
3328c2ecf20Sopenharmony_ci	usleep_range(2000, 5000);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(anx6345->gpiod_reset, 0);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	/* Power on registers module */
3378c2ecf20Sopenharmony_ci	anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
3388c2ecf20Sopenharmony_ci			 SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
3398c2ecf20Sopenharmony_ci	anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
3408c2ecf20Sopenharmony_ci			   SP_REGISTER_PD | SP_TOTAL_PD);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (anx6345->panel)
3438c2ecf20Sopenharmony_ci		drm_panel_prepare(anx6345->panel);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	anx6345->powered = true;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic void anx6345_poweroff(struct anx6345 *anx6345)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	int err;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
3538c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (anx6345->panel)
3568c2ecf20Sopenharmony_ci		drm_panel_unprepare(anx6345->panel);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	err = regulator_disable(anx6345->dvdd25);
3598c2ecf20Sopenharmony_ci	if (err) {
3608c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to disable dvdd25 regulator: %d\n",
3618c2ecf20Sopenharmony_ci			  err);
3628c2ecf20Sopenharmony_ci		return;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	usleep_range(5000, 10000);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	err = regulator_disable(anx6345->dvdd12);
3688c2ecf20Sopenharmony_ci	if (err) {
3698c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to disable dvdd12 regulator: %d\n",
3708c2ecf20Sopenharmony_ci			  err);
3718c2ecf20Sopenharmony_ci		return;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	anx6345->powered = false;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int anx6345_start(struct anx6345 *anx6345)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	int err;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (!anx6345->powered)
3848c2ecf20Sopenharmony_ci		anx6345_poweron(anx6345);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* Power on needed modules */
3878c2ecf20Sopenharmony_ci	err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
3888c2ecf20Sopenharmony_ci				SP_POWERDOWN_CTRL_REG,
3898c2ecf20Sopenharmony_ci				SP_VIDEO_PD | SP_LINK_PD);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	err = anx6345_tx_initialization(anx6345);
3928c2ecf20Sopenharmony_ci	if (err) {
3938c2ecf20Sopenharmony_ci		DRM_ERROR("Failed eDP transmitter initialization: %d\n", err);
3948c2ecf20Sopenharmony_ci		anx6345_poweroff(anx6345);
3958c2ecf20Sopenharmony_ci		return err;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	err = anx6345_dp_link_training(anx6345);
3998c2ecf20Sopenharmony_ci	if (err) {
4008c2ecf20Sopenharmony_ci		DRM_ERROR("Failed link training: %d\n", err);
4018c2ecf20Sopenharmony_ci		anx6345_poweroff(anx6345);
4028c2ecf20Sopenharmony_ci		return err;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/*
4068c2ecf20Sopenharmony_ci	 * This delay seems to help keep the hardware in a good state. Without
4078c2ecf20Sopenharmony_ci	 * it, there are times where it fails silently.
4088c2ecf20Sopenharmony_ci	 */
4098c2ecf20Sopenharmony_ci	usleep_range(10000, 15000);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	return 0;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic int anx6345_config_dp_output(struct anx6345 *anx6345)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	int err;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
4198c2ecf20Sopenharmony_ci				 SP_VIDEO_MUTE);
4208c2ecf20Sopenharmony_ci	if (err)
4218c2ecf20Sopenharmony_ci		return err;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/* Enable DP output */
4248c2ecf20Sopenharmony_ci	err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
4258c2ecf20Sopenharmony_ci			       SP_VIDEO_EN);
4268c2ecf20Sopenharmony_ci	if (err)
4278c2ecf20Sopenharmony_ci		return err;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	/* Force stream valid */
4308c2ecf20Sopenharmony_ci	return anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
4318c2ecf20Sopenharmony_ci			       SP_DP_SYSTEM_CTRL_BASE + 3,
4328c2ecf20Sopenharmony_ci			       SP_STRM_FORCE | SP_STRM_CTRL);
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic int anx6345_get_downstream_info(struct anx6345 *anx6345)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	u8 value;
4388c2ecf20Sopenharmony_ci	int err;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_readb(&anx6345->aux, DP_SINK_COUNT, &value);
4418c2ecf20Sopenharmony_ci	if (err < 0) {
4428c2ecf20Sopenharmony_ci		DRM_ERROR("Get sink count failed %d\n", err);
4438c2ecf20Sopenharmony_ci		return err;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (!DP_GET_SINK_COUNT(value)) {
4478c2ecf20Sopenharmony_ci		DRM_ERROR("Downstream disconnected\n");
4488c2ecf20Sopenharmony_ci		return -EIO;
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	return 0;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int anx6345_get_modes(struct drm_connector *connector)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct anx6345 *anx6345 = connector_to_anx6345(connector);
4578c2ecf20Sopenharmony_ci	int err, num_modes = 0;
4588c2ecf20Sopenharmony_ci	bool power_off = false;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	mutex_lock(&anx6345->lock);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (!anx6345->edid) {
4638c2ecf20Sopenharmony_ci		if (!anx6345->powered) {
4648c2ecf20Sopenharmony_ci			anx6345_poweron(anx6345);
4658c2ecf20Sopenharmony_ci			power_off = true;
4668c2ecf20Sopenharmony_ci		}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		err = anx6345_get_downstream_info(anx6345);
4698c2ecf20Sopenharmony_ci		if (err) {
4708c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to get downstream info: %d\n", err);
4718c2ecf20Sopenharmony_ci			goto unlock;
4728c2ecf20Sopenharmony_ci		}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci		anx6345->edid = drm_get_edid(connector, &anx6345->aux.ddc);
4758c2ecf20Sopenharmony_ci		if (!anx6345->edid)
4768c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to read EDID from panel\n");
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		err = drm_connector_update_edid_property(connector,
4798c2ecf20Sopenharmony_ci							 anx6345->edid);
4808c2ecf20Sopenharmony_ci		if (err) {
4818c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to update EDID property: %d\n", err);
4828c2ecf20Sopenharmony_ci			goto unlock;
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	num_modes += drm_add_edid_modes(connector, anx6345->edid);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	/* Driver currently supports only 6bpc */
4898c2ecf20Sopenharmony_ci	connector->display_info.bpc = 6;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ciunlock:
4928c2ecf20Sopenharmony_ci	if (power_off)
4938c2ecf20Sopenharmony_ci		anx6345_poweroff(anx6345);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	mutex_unlock(&anx6345->lock);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (!num_modes && anx6345->panel)
4988c2ecf20Sopenharmony_ci		num_modes += drm_panel_get_modes(anx6345->panel, connector);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	return num_modes;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs anx6345_connector_helper_funcs = {
5048c2ecf20Sopenharmony_ci	.get_modes = anx6345_get_modes,
5058c2ecf20Sopenharmony_ci};
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic void
5088c2ecf20Sopenharmony_cianx6345_connector_destroy(struct drm_connector *connector)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	drm_connector_cleanup(connector);
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs anx6345_connector_funcs = {
5148c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
5158c2ecf20Sopenharmony_ci	.destroy = anx6345_connector_destroy,
5168c2ecf20Sopenharmony_ci	.reset = drm_atomic_helper_connector_reset,
5178c2ecf20Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
5188c2ecf20Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
5198c2ecf20Sopenharmony_ci};
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic int anx6345_bridge_attach(struct drm_bridge *bridge,
5228c2ecf20Sopenharmony_ci				 enum drm_bridge_attach_flags flags)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
5258c2ecf20Sopenharmony_ci	int err;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
5288c2ecf20Sopenharmony_ci		DRM_ERROR("Fix bridge driver to make connector optional!");
5298c2ecf20Sopenharmony_ci		return -EINVAL;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (!bridge->encoder) {
5338c2ecf20Sopenharmony_ci		DRM_ERROR("Parent encoder object not found");
5348c2ecf20Sopenharmony_ci		return -ENODEV;
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* Register aux channel */
5388c2ecf20Sopenharmony_ci	anx6345->aux.name = "DP-AUX";
5398c2ecf20Sopenharmony_ci	anx6345->aux.dev = &anx6345->client->dev;
5408c2ecf20Sopenharmony_ci	anx6345->aux.transfer = anx6345_aux_transfer;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	err = drm_dp_aux_register(&anx6345->aux);
5438c2ecf20Sopenharmony_ci	if (err < 0) {
5448c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to register aux channel: %d\n", err);
5458c2ecf20Sopenharmony_ci		return err;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	err = drm_connector_init(bridge->dev, &anx6345->connector,
5498c2ecf20Sopenharmony_ci				 &anx6345_connector_funcs,
5508c2ecf20Sopenharmony_ci				 DRM_MODE_CONNECTOR_eDP);
5518c2ecf20Sopenharmony_ci	if (err) {
5528c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to initialize connector: %d\n", err);
5538c2ecf20Sopenharmony_ci		return err;
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	drm_connector_helper_add(&anx6345->connector,
5578c2ecf20Sopenharmony_ci				 &anx6345_connector_helper_funcs);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	err = drm_connector_register(&anx6345->connector);
5608c2ecf20Sopenharmony_ci	if (err) {
5618c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to register connector: %d\n", err);
5628c2ecf20Sopenharmony_ci		return err;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	err = drm_connector_attach_encoder(&anx6345->connector,
5688c2ecf20Sopenharmony_ci					   bridge->encoder);
5698c2ecf20Sopenharmony_ci	if (err) {
5708c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
5718c2ecf20Sopenharmony_ci		return err;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return 0;
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic enum drm_mode_status
5788c2ecf20Sopenharmony_cianx6345_bridge_mode_valid(struct drm_bridge *bridge,
5798c2ecf20Sopenharmony_ci			  const struct drm_display_info *info,
5808c2ecf20Sopenharmony_ci			  const struct drm_display_mode *mode)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
5838c2ecf20Sopenharmony_ci		return MODE_NO_INTERLACE;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* Max 1200p at 5.4 Ghz, one lane */
5868c2ecf20Sopenharmony_ci	if (mode->clock > 154000)
5878c2ecf20Sopenharmony_ci		return MODE_CLOCK_HIGH;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	return MODE_OK;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic void anx6345_bridge_disable(struct drm_bridge *bridge)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	/* Power off all modules except configuration registers access */
5978c2ecf20Sopenharmony_ci	anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
5988c2ecf20Sopenharmony_ci			 SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
5998c2ecf20Sopenharmony_ci	if (anx6345->panel)
6008c2ecf20Sopenharmony_ci		drm_panel_disable(anx6345->panel);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (anx6345->powered)
6038c2ecf20Sopenharmony_ci		anx6345_poweroff(anx6345);
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_cistatic void anx6345_bridge_enable(struct drm_bridge *bridge)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
6098c2ecf20Sopenharmony_ci	int err;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (anx6345->panel)
6128c2ecf20Sopenharmony_ci		drm_panel_enable(anx6345->panel);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	err = anx6345_start(anx6345);
6158c2ecf20Sopenharmony_ci	if (err) {
6168c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to initialize: %d\n", err);
6178c2ecf20Sopenharmony_ci		return;
6188c2ecf20Sopenharmony_ci	}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	err = anx6345_config_dp_output(anx6345);
6218c2ecf20Sopenharmony_ci	if (err)
6228c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to enable DP output: %d\n", err);
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs anx6345_bridge_funcs = {
6268c2ecf20Sopenharmony_ci	.attach = anx6345_bridge_attach,
6278c2ecf20Sopenharmony_ci	.mode_valid = anx6345_bridge_mode_valid,
6288c2ecf20Sopenharmony_ci	.disable = anx6345_bridge_disable,
6298c2ecf20Sopenharmony_ci	.enable = anx6345_bridge_enable,
6308c2ecf20Sopenharmony_ci};
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cistatic void unregister_i2c_dummy_clients(struct anx6345 *anx6345)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	unsigned int i;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(anx6345->i2c_clients); i++)
6378c2ecf20Sopenharmony_ci		if (anx6345->i2c_clients[i] &&
6388c2ecf20Sopenharmony_ci		    anx6345->i2c_clients[i]->addr != anx6345->client->addr)
6398c2ecf20Sopenharmony_ci			i2c_unregister_device(anx6345->i2c_clients[i]);
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic const struct regmap_config anx6345_regmap_config = {
6438c2ecf20Sopenharmony_ci	.reg_bits = 8,
6448c2ecf20Sopenharmony_ci	.val_bits = 8,
6458c2ecf20Sopenharmony_ci	.max_register = 0xff,
6468c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_NONE,
6478c2ecf20Sopenharmony_ci};
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cistatic const u16 anx6345_chipid_list[] = {
6508c2ecf20Sopenharmony_ci	0x6345,
6518c2ecf20Sopenharmony_ci};
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic bool anx6345_get_chip_id(struct anx6345 *anx6345)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	unsigned int i, idl, idh, version;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDL_REG, &idl))
6588c2ecf20Sopenharmony_ci		return false;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDH_REG, &idh))
6618c2ecf20Sopenharmony_ci		return false;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	anx6345->chipid = (u8)idl | ((u8)idh << 8);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_VERSION_REG,
6668c2ecf20Sopenharmony_ci			&version))
6678c2ecf20Sopenharmony_ci		return false;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(anx6345_chipid_list); i++) {
6708c2ecf20Sopenharmony_ci		if (anx6345->chipid == anx6345_chipid_list[i]) {
6718c2ecf20Sopenharmony_ci			DRM_INFO("Found ANX%x (ver. %d) eDP Transmitter\n",
6728c2ecf20Sopenharmony_ci				 anx6345->chipid, version);
6738c2ecf20Sopenharmony_ci			return true;
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	DRM_ERROR("ANX%x (ver. %d) not supported by this driver\n",
6788c2ecf20Sopenharmony_ci		  anx6345->chipid, version);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	return false;
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_cistatic int anx6345_i2c_probe(struct i2c_client *client,
6848c2ecf20Sopenharmony_ci			     const struct i2c_device_id *id)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	struct anx6345 *anx6345;
6878c2ecf20Sopenharmony_ci	struct device *dev;
6888c2ecf20Sopenharmony_ci	int i, err;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	anx6345 = devm_kzalloc(&client->dev, sizeof(*anx6345), GFP_KERNEL);
6918c2ecf20Sopenharmony_ci	if (!anx6345)
6928c2ecf20Sopenharmony_ci		return -ENOMEM;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	mutex_init(&anx6345->lock);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	anx6345->bridge.of_node = client->dev.of_node;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	anx6345->client = client;
6998c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, anx6345);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	dev = &anx6345->client->dev;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	err = drm_of_find_panel_or_bridge(client->dev.of_node, 1, 0,
7048c2ecf20Sopenharmony_ci					  &anx6345->panel, NULL);
7058c2ecf20Sopenharmony_ci	if (err == -EPROBE_DEFER)
7068c2ecf20Sopenharmony_ci		return err;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (err)
7098c2ecf20Sopenharmony_ci		DRM_DEBUG("No panel found\n");
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	/* 1.2V digital core power regulator  */
7128c2ecf20Sopenharmony_ci	anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12");
7138c2ecf20Sopenharmony_ci	if (IS_ERR(anx6345->dvdd12)) {
7148c2ecf20Sopenharmony_ci		if (PTR_ERR(anx6345->dvdd12) != -EPROBE_DEFER)
7158c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to get dvdd12 supply (%ld)\n",
7168c2ecf20Sopenharmony_ci				  PTR_ERR(anx6345->dvdd12));
7178c2ecf20Sopenharmony_ci		return PTR_ERR(anx6345->dvdd12);
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	/* 2.5V digital core power regulator  */
7218c2ecf20Sopenharmony_ci	anx6345->dvdd25 = devm_regulator_get(dev, "dvdd25");
7228c2ecf20Sopenharmony_ci	if (IS_ERR(anx6345->dvdd25)) {
7238c2ecf20Sopenharmony_ci		if (PTR_ERR(anx6345->dvdd25) != -EPROBE_DEFER)
7248c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to get dvdd25 supply (%ld)\n",
7258c2ecf20Sopenharmony_ci				  PTR_ERR(anx6345->dvdd25));
7268c2ecf20Sopenharmony_ci		return PTR_ERR(anx6345->dvdd25);
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	/* GPIO for chip reset */
7308c2ecf20Sopenharmony_ci	anx6345->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
7318c2ecf20Sopenharmony_ci	if (IS_ERR(anx6345->gpiod_reset)) {
7328c2ecf20Sopenharmony_ci		DRM_ERROR("Reset gpio not found\n");
7338c2ecf20Sopenharmony_ci		return PTR_ERR(anx6345->gpiod_reset);
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	/* Map slave addresses of ANX6345 */
7378c2ecf20Sopenharmony_ci	for (i = 0; i < I2C_NUM_ADDRESSES; i++) {
7388c2ecf20Sopenharmony_ci		if (anx6345_i2c_addresses[i] >> 1 != client->addr)
7398c2ecf20Sopenharmony_ci			anx6345->i2c_clients[i] = i2c_new_dummy_device(client->adapter,
7408c2ecf20Sopenharmony_ci						anx6345_i2c_addresses[i] >> 1);
7418c2ecf20Sopenharmony_ci		else
7428c2ecf20Sopenharmony_ci			anx6345->i2c_clients[i] = client;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		if (IS_ERR(anx6345->i2c_clients[i])) {
7458c2ecf20Sopenharmony_ci			err = PTR_ERR(anx6345->i2c_clients[i]);
7468c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to reserve I2C bus %02x\n",
7478c2ecf20Sopenharmony_ci				  anx6345_i2c_addresses[i]);
7488c2ecf20Sopenharmony_ci			goto err_unregister_i2c;
7498c2ecf20Sopenharmony_ci		}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		anx6345->map[i] = devm_regmap_init_i2c(anx6345->i2c_clients[i],
7528c2ecf20Sopenharmony_ci						       &anx6345_regmap_config);
7538c2ecf20Sopenharmony_ci		if (IS_ERR(anx6345->map[i])) {
7548c2ecf20Sopenharmony_ci			err = PTR_ERR(anx6345->map[i]);
7558c2ecf20Sopenharmony_ci			DRM_ERROR("Failed regmap initialization %02x\n",
7568c2ecf20Sopenharmony_ci				  anx6345_i2c_addresses[i]);
7578c2ecf20Sopenharmony_ci			goto err_unregister_i2c;
7588c2ecf20Sopenharmony_ci		}
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	/* Look for supported chip ID */
7628c2ecf20Sopenharmony_ci	anx6345_poweron(anx6345);
7638c2ecf20Sopenharmony_ci	if (anx6345_get_chip_id(anx6345)) {
7648c2ecf20Sopenharmony_ci		anx6345->bridge.funcs = &anx6345_bridge_funcs;
7658c2ecf20Sopenharmony_ci		drm_bridge_add(&anx6345->bridge);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		return 0;
7688c2ecf20Sopenharmony_ci	} else {
7698c2ecf20Sopenharmony_ci		anx6345_poweroff(anx6345);
7708c2ecf20Sopenharmony_ci		err = -ENODEV;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_cierr_unregister_i2c:
7748c2ecf20Sopenharmony_ci	unregister_i2c_dummy_clients(anx6345);
7758c2ecf20Sopenharmony_ci	return err;
7768c2ecf20Sopenharmony_ci}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_cistatic int anx6345_i2c_remove(struct i2c_client *client)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	struct anx6345 *anx6345 = i2c_get_clientdata(client);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	drm_bridge_remove(&anx6345->bridge);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	unregister_i2c_dummy_clients(anx6345);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	kfree(anx6345->edid);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	mutex_destroy(&anx6345->lock);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	return 0;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_cistatic const struct i2c_device_id anx6345_id[] = {
7948c2ecf20Sopenharmony_ci	{ "anx6345", 0 },
7958c2ecf20Sopenharmony_ci	{ /* sentinel */ }
7968c2ecf20Sopenharmony_ci};
7978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, anx6345_id);
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic const struct of_device_id anx6345_match_table[] = {
8008c2ecf20Sopenharmony_ci	{ .compatible = "analogix,anx6345", },
8018c2ecf20Sopenharmony_ci	{ /* sentinel */ },
8028c2ecf20Sopenharmony_ci};
8038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, anx6345_match_table);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_cistatic struct i2c_driver anx6345_driver = {
8068c2ecf20Sopenharmony_ci	.driver = {
8078c2ecf20Sopenharmony_ci		   .name = "anx6345",
8088c2ecf20Sopenharmony_ci		   .of_match_table = of_match_ptr(anx6345_match_table),
8098c2ecf20Sopenharmony_ci		  },
8108c2ecf20Sopenharmony_ci	.probe = anx6345_i2c_probe,
8118c2ecf20Sopenharmony_ci	.remove = anx6345_i2c_remove,
8128c2ecf20Sopenharmony_ci	.id_table = anx6345_id,
8138c2ecf20Sopenharmony_ci};
8148c2ecf20Sopenharmony_cimodule_i2c_driver(anx6345_driver);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ANX6345 eDP Transmitter driver");
8178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
8188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
819