18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright(c) 2016, Analogix Semiconductor.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based on anx7808 driver obtained from chromeos with copyright:
68c2ecf20Sopenharmony_ci * Copyright(c) 2013, Google Inc.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/err.h>
108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
118c2ecf20Sopenharmony_ci#include <linux/i2c.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/of_irq.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_dp_helper.h>
258c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
268c2ecf20Sopenharmony_ci#include <drm/drm_print.h>
278c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "analogix-anx78xx.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define I2C_NUM_ADDRESSES	5
328c2ecf20Sopenharmony_ci#define I2C_IDX_TX_P0		0
338c2ecf20Sopenharmony_ci#define I2C_IDX_TX_P1		1
348c2ecf20Sopenharmony_ci#define I2C_IDX_TX_P2		2
358c2ecf20Sopenharmony_ci#define I2C_IDX_RX_P0		3
368c2ecf20Sopenharmony_ci#define I2C_IDX_RX_P1		4
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define XTAL_CLK		270 /* 27M */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const u8 anx7808_i2c_addresses[] = {
418c2ecf20Sopenharmony_ci	[I2C_IDX_TX_P0] = 0x78,
428c2ecf20Sopenharmony_ci	[I2C_IDX_TX_P1] = 0x7a,
438c2ecf20Sopenharmony_ci	[I2C_IDX_TX_P2] = 0x72,
448c2ecf20Sopenharmony_ci	[I2C_IDX_RX_P0] = 0x7e,
458c2ecf20Sopenharmony_ci	[I2C_IDX_RX_P1] = 0x80,
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic const u8 anx781x_i2c_addresses[] = {
498c2ecf20Sopenharmony_ci	[I2C_IDX_TX_P0] = 0x70,
508c2ecf20Sopenharmony_ci	[I2C_IDX_TX_P1] = 0x7a,
518c2ecf20Sopenharmony_ci	[I2C_IDX_TX_P2] = 0x72,
528c2ecf20Sopenharmony_ci	[I2C_IDX_RX_P0] = 0x7e,
538c2ecf20Sopenharmony_ci	[I2C_IDX_RX_P1] = 0x80,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistruct anx78xx_platform_data {
578c2ecf20Sopenharmony_ci	struct regulator *dvdd10;
588c2ecf20Sopenharmony_ci	struct gpio_desc *gpiod_hpd;
598c2ecf20Sopenharmony_ci	struct gpio_desc *gpiod_pd;
608c2ecf20Sopenharmony_ci	struct gpio_desc *gpiod_reset;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	int hpd_irq;
638c2ecf20Sopenharmony_ci	int intp_irq;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct anx78xx {
678c2ecf20Sopenharmony_ci	struct drm_dp_aux aux;
688c2ecf20Sopenharmony_ci	struct drm_bridge bridge;
698c2ecf20Sopenharmony_ci	struct i2c_client *client;
708c2ecf20Sopenharmony_ci	struct edid *edid;
718c2ecf20Sopenharmony_ci	struct drm_connector connector;
728c2ecf20Sopenharmony_ci	struct anx78xx_platform_data pdata;
738c2ecf20Sopenharmony_ci	struct mutex lock;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/*
768c2ecf20Sopenharmony_ci	 * I2C Slave addresses of ANX7814 are mapped as TX_P0, TX_P1, TX_P2,
778c2ecf20Sopenharmony_ci	 * RX_P0 and RX_P1.
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci	struct i2c_client *i2c_dummy[I2C_NUM_ADDRESSES];
808c2ecf20Sopenharmony_ci	struct regmap *map[I2C_NUM_ADDRESSES];
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	u16 chipid;
838c2ecf20Sopenharmony_ci	u8 dpcd[DP_RECEIVER_CAP_SIZE];
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	bool powered;
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic inline struct anx78xx *connector_to_anx78xx(struct drm_connector *c)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	return container_of(c, struct anx78xx, connector);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic inline struct anx78xx *bridge_to_anx78xx(struct drm_bridge *bridge)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	return container_of(bridge, struct anx78xx, bridge);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int anx78xx_set_bits(struct regmap *map, u8 reg, u8 mask)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	return regmap_update_bits(map, reg, mask, mask);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int anx78xx_clear_bits(struct regmap *map, u8 reg, u8 mask)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	return regmap_update_bits(map, reg, mask, 0);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic ssize_t anx78xx_aux_transfer(struct drm_dp_aux *aux,
1098c2ecf20Sopenharmony_ci				    struct drm_dp_aux_msg *msg)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = container_of(aux, struct anx78xx, aux);
1128c2ecf20Sopenharmony_ci	return anx_dp_aux_transfer(anx78xx->map[I2C_IDX_TX_P0], msg);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int anx78xx_set_hpd(struct anx78xx *anx78xx)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	int err;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_RX_P0],
1208c2ecf20Sopenharmony_ci				 SP_TMDS_CTRL_BASE + 7, SP_PD_RT);
1218c2ecf20Sopenharmony_ci	if (err)
1228c2ecf20Sopenharmony_ci		return err;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL3_REG,
1258c2ecf20Sopenharmony_ci			       SP_HPD_OUT);
1268c2ecf20Sopenharmony_ci	if (err)
1278c2ecf20Sopenharmony_ci		return err;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int anx78xx_clear_hpd(struct anx78xx *anx78xx)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	int err;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL3_REG,
1378c2ecf20Sopenharmony_ci				 SP_HPD_OUT);
1388c2ecf20Sopenharmony_ci	if (err)
1398c2ecf20Sopenharmony_ci		return err;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
1428c2ecf20Sopenharmony_ci			       SP_TMDS_CTRL_BASE + 7, SP_PD_RT);
1438c2ecf20Sopenharmony_ci	if (err)
1448c2ecf20Sopenharmony_ci		return err;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return 0;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic const struct reg_sequence tmds_phy_initialization[] = {
1508c2ecf20Sopenharmony_ci	{ SP_TMDS_CTRL_BASE +  1, 0x90 },
1518c2ecf20Sopenharmony_ci	{ SP_TMDS_CTRL_BASE +  2, 0xa9 },
1528c2ecf20Sopenharmony_ci	{ SP_TMDS_CTRL_BASE +  6, 0x92 },
1538c2ecf20Sopenharmony_ci	{ SP_TMDS_CTRL_BASE +  7, 0x80 },
1548c2ecf20Sopenharmony_ci	{ SP_TMDS_CTRL_BASE + 20, 0xf2 },
1558c2ecf20Sopenharmony_ci	{ SP_TMDS_CTRL_BASE + 22, 0xc4 },
1568c2ecf20Sopenharmony_ci	{ SP_TMDS_CTRL_BASE + 23, 0x18 },
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int anx78xx_rx_initialization(struct anx78xx *anx78xx)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	int err;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_RX_P0], SP_HDMI_MUTE_CTRL_REG,
1648c2ecf20Sopenharmony_ci			   SP_AUD_MUTE | SP_VID_MUTE);
1658c2ecf20Sopenharmony_ci	if (err)
1668c2ecf20Sopenharmony_ci		return err;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0], SP_CHIP_CTRL_REG,
1698c2ecf20Sopenharmony_ci			       SP_MAN_HDMI5V_DET | SP_PLLLOCK_CKDT_EN |
1708c2ecf20Sopenharmony_ci			       SP_DIGITAL_CKDT_EN);
1718c2ecf20Sopenharmony_ci	if (err)
1728c2ecf20Sopenharmony_ci		return err;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
1758c2ecf20Sopenharmony_ci			       SP_SOFTWARE_RESET1_REG, SP_HDCP_MAN_RST |
1768c2ecf20Sopenharmony_ci			       SP_SW_MAN_RST | SP_TMDS_RST | SP_VIDEO_RST);
1778c2ecf20Sopenharmony_ci	if (err)
1788c2ecf20Sopenharmony_ci		return err;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_RX_P0],
1818c2ecf20Sopenharmony_ci				 SP_SOFTWARE_RESET1_REG, SP_HDCP_MAN_RST |
1828c2ecf20Sopenharmony_ci				 SP_SW_MAN_RST | SP_TMDS_RST | SP_VIDEO_RST);
1838c2ecf20Sopenharmony_ci	if (err)
1848c2ecf20Sopenharmony_ci		return err;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Sync detect change, GP set mute */
1878c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
1888c2ecf20Sopenharmony_ci			       SP_AUD_EXCEPTION_ENABLE_BASE + 1, BIT(5) |
1898c2ecf20Sopenharmony_ci			       BIT(6));
1908c2ecf20Sopenharmony_ci	if (err)
1918c2ecf20Sopenharmony_ci		return err;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
1948c2ecf20Sopenharmony_ci			       SP_AUD_EXCEPTION_ENABLE_BASE + 3,
1958c2ecf20Sopenharmony_ci			       SP_AEC_EN21);
1968c2ecf20Sopenharmony_ci	if (err)
1978c2ecf20Sopenharmony_ci		return err;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0], SP_AUDVID_CTRL_REG,
2008c2ecf20Sopenharmony_ci			       SP_AVC_EN | SP_AAC_OE | SP_AAC_EN);
2018c2ecf20Sopenharmony_ci	if (err)
2028c2ecf20Sopenharmony_ci		return err;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_RX_P0],
2058c2ecf20Sopenharmony_ci				 SP_SYSTEM_POWER_DOWN1_REG, SP_PWDN_CTRL);
2068c2ecf20Sopenharmony_ci	if (err)
2078c2ecf20Sopenharmony_ci		return err;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
2108c2ecf20Sopenharmony_ci			       SP_VID_DATA_RANGE_CTRL_REG, SP_R2Y_INPUT_LIMIT);
2118c2ecf20Sopenharmony_ci	if (err)
2128c2ecf20Sopenharmony_ci		return err;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* Enable DDC stretch */
2158c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
2168c2ecf20Sopenharmony_ci			   SP_DP_EXTRA_I2C_DEV_ADDR_REG, SP_I2C_EXTRA_ADDR);
2178c2ecf20Sopenharmony_ci	if (err)
2188c2ecf20Sopenharmony_ci		return err;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/* TMDS phy initialization */
2218c2ecf20Sopenharmony_ci	err = regmap_multi_reg_write(anx78xx->map[I2C_IDX_RX_P0],
2228c2ecf20Sopenharmony_ci				     tmds_phy_initialization,
2238c2ecf20Sopenharmony_ci				     ARRAY_SIZE(tmds_phy_initialization));
2248c2ecf20Sopenharmony_ci	if (err)
2258c2ecf20Sopenharmony_ci		return err;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	err = anx78xx_clear_hpd(anx78xx);
2288c2ecf20Sopenharmony_ci	if (err)
2298c2ecf20Sopenharmony_ci		return err;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return 0;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic const u8 dp_tx_output_precise_tune_bits[20] = {
2358c2ecf20Sopenharmony_ci	0x01, 0x03, 0x07, 0x7f, 0x71, 0x6b, 0x7f,
2368c2ecf20Sopenharmony_ci	0x73, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
2378c2ecf20Sopenharmony_ci	0x0c, 0x42, 0x1e, 0x3e, 0x72, 0x7e,
2388c2ecf20Sopenharmony_ci};
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int anx78xx_link_phy_initialization(struct anx78xx *anx78xx)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	int err;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/*
2458c2ecf20Sopenharmony_ci	 * REVISIT : It is writing to a RESERVED bits in Analog Control 0
2468c2ecf20Sopenharmony_ci	 * register.
2478c2ecf20Sopenharmony_ci	 */
2488c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P2], SP_ANALOG_CTRL0_REG,
2498c2ecf20Sopenharmony_ci			   0x02);
2508c2ecf20Sopenharmony_ci	if (err)
2518c2ecf20Sopenharmony_ci		return err;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/*
2548c2ecf20Sopenharmony_ci	 * Write DP TX output emphasis precise tune bits.
2558c2ecf20Sopenharmony_ci	 */
2568c2ecf20Sopenharmony_ci	err = regmap_bulk_write(anx78xx->map[I2C_IDX_TX_P1],
2578c2ecf20Sopenharmony_ci				SP_DP_TX_LT_CTRL0_REG,
2588c2ecf20Sopenharmony_ci				dp_tx_output_precise_tune_bits,
2598c2ecf20Sopenharmony_ci				ARRAY_SIZE(dp_tx_output_precise_tune_bits));
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (err)
2628c2ecf20Sopenharmony_ci		return err;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	return 0;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic int anx78xx_xtal_clk_sel(struct anx78xx *anx78xx)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	unsigned int value;
2708c2ecf20Sopenharmony_ci	int err;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P2],
2738c2ecf20Sopenharmony_ci				 SP_ANALOG_DEBUG2_REG,
2748c2ecf20Sopenharmony_ci				 SP_XTAL_FRQ | SP_FORCE_SW_OFF_BYPASS,
2758c2ecf20Sopenharmony_ci				 SP_XTAL_FRQ_27M);
2768c2ecf20Sopenharmony_ci	if (err)
2778c2ecf20Sopenharmony_ci		return err;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL3_REG,
2808c2ecf20Sopenharmony_ci			   XTAL_CLK & SP_WAIT_COUNTER_7_0_MASK);
2818c2ecf20Sopenharmony_ci	if (err)
2828c2ecf20Sopenharmony_ci		return err;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL4_REG,
2858c2ecf20Sopenharmony_ci			   ((XTAL_CLK & 0xff00) >> 2) | (XTAL_CLK / 10));
2868c2ecf20Sopenharmony_ci	if (err)
2878c2ecf20Sopenharmony_ci		return err;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
2908c2ecf20Sopenharmony_ci			   SP_I2C_GEN_10US_TIMER0_REG, XTAL_CLK & 0xff);
2918c2ecf20Sopenharmony_ci	if (err)
2928c2ecf20Sopenharmony_ci		return err;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
2958c2ecf20Sopenharmony_ci			   SP_I2C_GEN_10US_TIMER1_REG,
2968c2ecf20Sopenharmony_ci			   (XTAL_CLK & 0xff00) >> 8);
2978c2ecf20Sopenharmony_ci	if (err)
2988c2ecf20Sopenharmony_ci		return err;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_MISC_CTRL_REG,
3018c2ecf20Sopenharmony_ci			   XTAL_CLK / 10 - 1);
3028c2ecf20Sopenharmony_ci	if (err)
3038c2ecf20Sopenharmony_ci		return err;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	err = regmap_read(anx78xx->map[I2C_IDX_RX_P0],
3068c2ecf20Sopenharmony_ci			  SP_HDMI_US_TIMER_CTRL_REG,
3078c2ecf20Sopenharmony_ci			  &value);
3088c2ecf20Sopenharmony_ci	if (err)
3098c2ecf20Sopenharmony_ci		return err;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_RX_P0],
3128c2ecf20Sopenharmony_ci			   SP_HDMI_US_TIMER_CTRL_REG,
3138c2ecf20Sopenharmony_ci			   (value & SP_MS_TIMER_MARGIN_10_8_MASK) |
3148c2ecf20Sopenharmony_ci			   ((((XTAL_CLK / 10) >> 1) - 2) << 3));
3158c2ecf20Sopenharmony_ci	if (err)
3168c2ecf20Sopenharmony_ci		return err;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return 0;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic const struct reg_sequence otp_key_protect[] = {
3228c2ecf20Sopenharmony_ci	{ SP_OTP_KEY_PROTECT1_REG, SP_OTP_PSW1 },
3238c2ecf20Sopenharmony_ci	{ SP_OTP_KEY_PROTECT2_REG, SP_OTP_PSW2 },
3248c2ecf20Sopenharmony_ci	{ SP_OTP_KEY_PROTECT3_REG, SP_OTP_PSW3 },
3258c2ecf20Sopenharmony_ci};
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic int anx78xx_tx_initialization(struct anx78xx *anx78xx)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	int err;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* Set terminal resistor to 50 ohm */
3328c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL2_REG,
3338c2ecf20Sopenharmony_ci			   0x30);
3348c2ecf20Sopenharmony_ci	if (err)
3358c2ecf20Sopenharmony_ci		return err;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* Enable aux double diff output */
3388c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
3398c2ecf20Sopenharmony_ci			       SP_DP_AUX_CH_CTRL2_REG, 0x08);
3408c2ecf20Sopenharmony_ci	if (err)
3418c2ecf20Sopenharmony_ci		return err;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0],
3448c2ecf20Sopenharmony_ci				 SP_DP_HDCP_CTRL_REG, SP_AUTO_EN |
3458c2ecf20Sopenharmony_ci				 SP_AUTO_START);
3468c2ecf20Sopenharmony_ci	if (err)
3478c2ecf20Sopenharmony_ci		return err;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	err = regmap_multi_reg_write(anx78xx->map[I2C_IDX_TX_P0],
3508c2ecf20Sopenharmony_ci				     otp_key_protect,
3518c2ecf20Sopenharmony_ci				     ARRAY_SIZE(otp_key_protect));
3528c2ecf20Sopenharmony_ci	if (err)
3538c2ecf20Sopenharmony_ci		return err;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
3568c2ecf20Sopenharmony_ci			       SP_HDCP_KEY_COMMAND_REG, SP_DISABLE_SYNC_HDCP);
3578c2ecf20Sopenharmony_ci	if (err)
3588c2ecf20Sopenharmony_ci		return err;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL8_REG,
3618c2ecf20Sopenharmony_ci			   SP_VID_VRES_TH);
3628c2ecf20Sopenharmony_ci	if (err)
3638c2ecf20Sopenharmony_ci		return err;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/*
3668c2ecf20Sopenharmony_ci	 * DP HDCP auto authentication wait timer (when downstream starts to
3678c2ecf20Sopenharmony_ci	 * auth, DP side will wait for this period then do auth automatically)
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_HDCP_AUTO_TIMER_REG,
3708c2ecf20Sopenharmony_ci			   0x00);
3718c2ecf20Sopenharmony_ci	if (err)
3728c2ecf20Sopenharmony_ci		return err;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
3758c2ecf20Sopenharmony_ci			       SP_DP_HDCP_CTRL_REG, SP_LINK_POLLING);
3768c2ecf20Sopenharmony_ci	if (err)
3778c2ecf20Sopenharmony_ci		return err;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
3808c2ecf20Sopenharmony_ci			       SP_DP_LINK_DEBUG_CTRL_REG, SP_M_VID_DEBUG);
3818c2ecf20Sopenharmony_ci	if (err)
3828c2ecf20Sopenharmony_ci		return err;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P2],
3858c2ecf20Sopenharmony_ci			       SP_ANALOG_DEBUG2_REG, SP_POWERON_TIME_1P5MS);
3868c2ecf20Sopenharmony_ci	if (err)
3878c2ecf20Sopenharmony_ci		return err;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	err = anx78xx_xtal_clk_sel(anx78xx);
3908c2ecf20Sopenharmony_ci	if (err)
3918c2ecf20Sopenharmony_ci		return err;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_DEFER_CTRL_REG,
3948c2ecf20Sopenharmony_ci			   SP_DEFER_CTRL_EN | 0x0c);
3958c2ecf20Sopenharmony_ci	if (err)
3968c2ecf20Sopenharmony_ci		return err;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
3998c2ecf20Sopenharmony_ci			       SP_DP_POLLING_CTRL_REG,
4008c2ecf20Sopenharmony_ci			       SP_AUTO_POLLING_DISABLE);
4018c2ecf20Sopenharmony_ci	if (err)
4028c2ecf20Sopenharmony_ci		return err;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/*
4058c2ecf20Sopenharmony_ci	 * Short the link integrity check timer to speed up bstatus
4068c2ecf20Sopenharmony_ci	 * polling for HDCP CTS item 1A-07
4078c2ecf20Sopenharmony_ci	 */
4088c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
4098c2ecf20Sopenharmony_ci			   SP_HDCP_LINK_CHECK_TIMER_REG, 0x1d);
4108c2ecf20Sopenharmony_ci	if (err)
4118c2ecf20Sopenharmony_ci		return err;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
4148c2ecf20Sopenharmony_ci			       SP_DP_MISC_CTRL_REG, SP_EQ_TRAINING_LOOP);
4158c2ecf20Sopenharmony_ci	if (err)
4168c2ecf20Sopenharmony_ci		return err;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* Power down the main link by default */
4198c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
4208c2ecf20Sopenharmony_ci			       SP_DP_ANALOG_POWER_DOWN_REG, SP_CH0_PD);
4218c2ecf20Sopenharmony_ci	if (err)
4228c2ecf20Sopenharmony_ci		return err;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	err = anx78xx_link_phy_initialization(anx78xx);
4258c2ecf20Sopenharmony_ci	if (err)
4268c2ecf20Sopenharmony_ci		return err;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* Gen m_clk with downspreading */
4298c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
4308c2ecf20Sopenharmony_ci			       SP_DP_M_CALCULATION_CTRL_REG, SP_M_GEN_CLK_SEL);
4318c2ecf20Sopenharmony_ci	if (err)
4328c2ecf20Sopenharmony_ci		return err;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return 0;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic int anx78xx_enable_interrupts(struct anx78xx *anx78xx)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	int err;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/*
4428c2ecf20Sopenharmony_ci	 * BIT0: INT pin assertion polarity: 1 = assert high
4438c2ecf20Sopenharmony_ci	 * BIT1: INT pin output type: 0 = push/pull
4448c2ecf20Sopenharmony_ci	 */
4458c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P2], SP_INT_CTRL_REG, 0x01);
4468c2ecf20Sopenharmony_ci	if (err)
4478c2ecf20Sopenharmony_ci		return err;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P2],
4508c2ecf20Sopenharmony_ci			   SP_COMMON_INT_MASK4_REG, SP_HPD_LOST | SP_HPD_PLUG);
4518c2ecf20Sopenharmony_ci	if (err)
4528c2ecf20Sopenharmony_ci		return err;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P2], SP_DP_INT_MASK1_REG,
4558c2ecf20Sopenharmony_ci			   SP_TRAINING_FINISH);
4568c2ecf20Sopenharmony_ci	if (err)
4578c2ecf20Sopenharmony_ci		return err;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_RX_P0], SP_INT_MASK1_REG,
4608c2ecf20Sopenharmony_ci			   SP_CKDT_CHG | SP_SCDT_CHG);
4618c2ecf20Sopenharmony_ci	if (err)
4628c2ecf20Sopenharmony_ci		return err;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic void anx78xx_poweron(struct anx78xx *anx78xx)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	struct anx78xx_platform_data *pdata = &anx78xx->pdata;
4708c2ecf20Sopenharmony_ci	int err;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (WARN_ON(anx78xx->powered))
4738c2ecf20Sopenharmony_ci		return;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (pdata->dvdd10) {
4768c2ecf20Sopenharmony_ci		err = regulator_enable(pdata->dvdd10);
4778c2ecf20Sopenharmony_ci		if (err) {
4788c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to enable DVDD10 regulator: %d\n",
4798c2ecf20Sopenharmony_ci				  err);
4808c2ecf20Sopenharmony_ci			return;
4818c2ecf20Sopenharmony_ci		}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
4878c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(pdata->gpiod_pd, 0);
4908c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* Power on registers module */
4958c2ecf20Sopenharmony_ci	anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P2], SP_POWERDOWN_CTRL_REG,
4968c2ecf20Sopenharmony_ci			 SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
4978c2ecf20Sopenharmony_ci	anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P2], SP_POWERDOWN_CTRL_REG,
4988c2ecf20Sopenharmony_ci			   SP_REGISTER_PD | SP_TOTAL_PD);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	anx78xx->powered = true;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic void anx78xx_poweroff(struct anx78xx *anx78xx)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct anx78xx_platform_data *pdata = &anx78xx->pdata;
5068c2ecf20Sopenharmony_ci	int err;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (WARN_ON(!anx78xx->powered))
5098c2ecf20Sopenharmony_ci		return;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
5128c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(pdata->gpiod_pd, 1);
5158c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (pdata->dvdd10) {
5188c2ecf20Sopenharmony_ci		err = regulator_disable(pdata->dvdd10);
5198c2ecf20Sopenharmony_ci		if (err) {
5208c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to disable DVDD10 regulator: %d\n",
5218c2ecf20Sopenharmony_ci				  err);
5228c2ecf20Sopenharmony_ci			return;
5238c2ecf20Sopenharmony_ci		}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	anx78xx->powered = false;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic int anx78xx_start(struct anx78xx *anx78xx)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	int err;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* Power on all modules */
5368c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P2],
5378c2ecf20Sopenharmony_ci				 SP_POWERDOWN_CTRL_REG,
5388c2ecf20Sopenharmony_ci				 SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD |
5398c2ecf20Sopenharmony_ci				 SP_LINK_PD);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	err = anx78xx_enable_interrupts(anx78xx);
5428c2ecf20Sopenharmony_ci	if (err) {
5438c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to enable interrupts: %d\n", err);
5448c2ecf20Sopenharmony_ci		goto err_poweroff;
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	err = anx78xx_rx_initialization(anx78xx);
5488c2ecf20Sopenharmony_ci	if (err) {
5498c2ecf20Sopenharmony_ci		DRM_ERROR("Failed receiver initialization: %d\n", err);
5508c2ecf20Sopenharmony_ci		goto err_poweroff;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	err = anx78xx_tx_initialization(anx78xx);
5548c2ecf20Sopenharmony_ci	if (err) {
5558c2ecf20Sopenharmony_ci		DRM_ERROR("Failed transmitter initialization: %d\n", err);
5568c2ecf20Sopenharmony_ci		goto err_poweroff;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/*
5608c2ecf20Sopenharmony_ci	 * This delay seems to help keep the hardware in a good state. Without
5618c2ecf20Sopenharmony_ci	 * it, there are times where it fails silently.
5628c2ecf20Sopenharmony_ci	 */
5638c2ecf20Sopenharmony_ci	usleep_range(10000, 15000);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	return 0;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cierr_poweroff:
5688c2ecf20Sopenharmony_ci	DRM_ERROR("Failed SlimPort transmitter initialization: %d\n", err);
5698c2ecf20Sopenharmony_ci	anx78xx_poweroff(anx78xx);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	return err;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int anx78xx_init_pdata(struct anx78xx *anx78xx)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct anx78xx_platform_data *pdata = &anx78xx->pdata;
5778c2ecf20Sopenharmony_ci	struct device *dev = &anx78xx->client->dev;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* 1.0V digital core power regulator  */
5808c2ecf20Sopenharmony_ci	pdata->dvdd10 = devm_regulator_get(dev, "dvdd10");
5818c2ecf20Sopenharmony_ci	if (IS_ERR(pdata->dvdd10)) {
5828c2ecf20Sopenharmony_ci		if (PTR_ERR(pdata->dvdd10) != -EPROBE_DEFER)
5838c2ecf20Sopenharmony_ci			DRM_ERROR("DVDD10 regulator not found\n");
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		return PTR_ERR(pdata->dvdd10);
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* GPIO for HPD */
5898c2ecf20Sopenharmony_ci	pdata->gpiod_hpd = devm_gpiod_get(dev, "hpd", GPIOD_IN);
5908c2ecf20Sopenharmony_ci	if (IS_ERR(pdata->gpiod_hpd))
5918c2ecf20Sopenharmony_ci		return PTR_ERR(pdata->gpiod_hpd);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* GPIO for chip power down */
5948c2ecf20Sopenharmony_ci	pdata->gpiod_pd = devm_gpiod_get(dev, "pd", GPIOD_OUT_HIGH);
5958c2ecf20Sopenharmony_ci	if (IS_ERR(pdata->gpiod_pd))
5968c2ecf20Sopenharmony_ci		return PTR_ERR(pdata->gpiod_pd);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* GPIO for chip reset */
5998c2ecf20Sopenharmony_ci	pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(pdata->gpiod_reset);
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int anx78xx_dp_link_training(struct anx78xx *anx78xx)
6058c2ecf20Sopenharmony_ci{
6068c2ecf20Sopenharmony_ci	u8 dp_bw, dpcd[2];
6078c2ecf20Sopenharmony_ci	int err;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_RX_P0], SP_HDMI_MUTE_CTRL_REG,
6108c2ecf20Sopenharmony_ci			   0x0);
6118c2ecf20Sopenharmony_ci	if (err)
6128c2ecf20Sopenharmony_ci		return err;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P2],
6158c2ecf20Sopenharmony_ci				 SP_POWERDOWN_CTRL_REG,
6168c2ecf20Sopenharmony_ci				 SP_TOTAL_PD);
6178c2ecf20Sopenharmony_ci	if (err)
6188c2ecf20Sopenharmony_ci		return err;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_readb(&anx78xx->aux, DP_MAX_LINK_RATE, &dp_bw);
6218c2ecf20Sopenharmony_ci	if (err < 0)
6228c2ecf20Sopenharmony_ci		return err;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	switch (dp_bw) {
6258c2ecf20Sopenharmony_ci	case DP_LINK_BW_1_62:
6268c2ecf20Sopenharmony_ci	case DP_LINK_BW_2_7:
6278c2ecf20Sopenharmony_ci	case DP_LINK_BW_5_4:
6288c2ecf20Sopenharmony_ci		break;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	default:
6318c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("DP bandwidth (%#02x) not supported\n", dp_bw);
6328c2ecf20Sopenharmony_ci		return -EINVAL;
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL1_REG,
6368c2ecf20Sopenharmony_ci			       SP_VIDEO_MUTE);
6378c2ecf20Sopenharmony_ci	if (err)
6388c2ecf20Sopenharmony_ci		return err;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P2],
6418c2ecf20Sopenharmony_ci				 SP_VID_CTRL1_REG, SP_VIDEO_EN);
6428c2ecf20Sopenharmony_ci	if (err)
6438c2ecf20Sopenharmony_ci		return err;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	/* Get DPCD info */
6468c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_read(&anx78xx->aux, DP_DPCD_REV,
6478c2ecf20Sopenharmony_ci			       &anx78xx->dpcd, DP_RECEIVER_CAP_SIZE);
6488c2ecf20Sopenharmony_ci	if (err < 0) {
6498c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to read DPCD: %d\n", err);
6508c2ecf20Sopenharmony_ci		return err;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	/* Clear channel x SERDES power down */
6548c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0],
6558c2ecf20Sopenharmony_ci				 SP_DP_ANALOG_POWER_DOWN_REG, SP_CH0_PD);
6568c2ecf20Sopenharmony_ci	if (err)
6578c2ecf20Sopenharmony_ci		return err;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/*
6608c2ecf20Sopenharmony_ci	 * Power up the sink (DP_SET_POWER register is only available on DPCD
6618c2ecf20Sopenharmony_ci	 * v1.1 and later).
6628c2ecf20Sopenharmony_ci	 */
6638c2ecf20Sopenharmony_ci	if (anx78xx->dpcd[DP_DPCD_REV] >= 0x11) {
6648c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_readb(&anx78xx->aux, DP_SET_POWER, &dpcd[0]);
6658c2ecf20Sopenharmony_ci		if (err < 0) {
6668c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to read DP_SET_POWER register: %d\n",
6678c2ecf20Sopenharmony_ci				  err);
6688c2ecf20Sopenharmony_ci			return err;
6698c2ecf20Sopenharmony_ci		}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		dpcd[0] &= ~DP_SET_POWER_MASK;
6728c2ecf20Sopenharmony_ci		dpcd[0] |= DP_SET_POWER_D0;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_SET_POWER, dpcd[0]);
6758c2ecf20Sopenharmony_ci		if (err < 0) {
6768c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to power up DisplayPort link: %d\n",
6778c2ecf20Sopenharmony_ci				  err);
6788c2ecf20Sopenharmony_ci			return err;
6798c2ecf20Sopenharmony_ci		}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		/*
6828c2ecf20Sopenharmony_ci		 * According to the DP 1.1 specification, a "Sink Device must
6838c2ecf20Sopenharmony_ci		 * exit the power saving state within 1 ms" (Section 2.5.3.1,
6848c2ecf20Sopenharmony_ci		 * Table 5-52, "Sink Control Field" (register 0x600).
6858c2ecf20Sopenharmony_ci		 */
6868c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	/* Possibly enable downspread on the sink */
6908c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
6918c2ecf20Sopenharmony_ci			   SP_DP_DOWNSPREAD_CTRL1_REG, 0);
6928c2ecf20Sopenharmony_ci	if (err)
6938c2ecf20Sopenharmony_ci		return err;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (anx78xx->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) {
6968c2ecf20Sopenharmony_ci		DRM_DEBUG("Enable downspread on the sink\n");
6978c2ecf20Sopenharmony_ci		/* 4000PPM */
6988c2ecf20Sopenharmony_ci		err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
6998c2ecf20Sopenharmony_ci				   SP_DP_DOWNSPREAD_CTRL1_REG, 8);
7008c2ecf20Sopenharmony_ci		if (err)
7018c2ecf20Sopenharmony_ci			return err;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_DOWNSPREAD_CTRL,
7048c2ecf20Sopenharmony_ci					 DP_SPREAD_AMP_0_5);
7058c2ecf20Sopenharmony_ci		if (err < 0)
7068c2ecf20Sopenharmony_ci			return err;
7078c2ecf20Sopenharmony_ci	} else {
7088c2ecf20Sopenharmony_ci		err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_DOWNSPREAD_CTRL, 0);
7098c2ecf20Sopenharmony_ci		if (err < 0)
7108c2ecf20Sopenharmony_ci			return err;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	/* Set the lane count and the link rate on the sink */
7148c2ecf20Sopenharmony_ci	if (drm_dp_enhanced_frame_cap(anx78xx->dpcd))
7158c2ecf20Sopenharmony_ci		err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
7168c2ecf20Sopenharmony_ci				       SP_DP_SYSTEM_CTRL_BASE + 4,
7178c2ecf20Sopenharmony_ci				       SP_ENHANCED_MODE);
7188c2ecf20Sopenharmony_ci	else
7198c2ecf20Sopenharmony_ci		err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0],
7208c2ecf20Sopenharmony_ci					 SP_DP_SYSTEM_CTRL_BASE + 4,
7218c2ecf20Sopenharmony_ci					 SP_ENHANCED_MODE);
7228c2ecf20Sopenharmony_ci	if (err)
7238c2ecf20Sopenharmony_ci		return err;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0],
7268c2ecf20Sopenharmony_ci			   SP_DP_MAIN_LINK_BW_SET_REG,
7278c2ecf20Sopenharmony_ci			   anx78xx->dpcd[DP_MAX_LINK_RATE]);
7288c2ecf20Sopenharmony_ci	if (err)
7298c2ecf20Sopenharmony_ci		return err;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	dpcd[1] = drm_dp_max_lane_count(anx78xx->dpcd);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	if (drm_dp_enhanced_frame_cap(anx78xx->dpcd))
7348c2ecf20Sopenharmony_ci		dpcd[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_write(&anx78xx->aux, DP_LINK_BW_SET, dpcd,
7378c2ecf20Sopenharmony_ci				sizeof(dpcd));
7388c2ecf20Sopenharmony_ci	if (err < 0) {
7398c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to configure link: %d\n", err);
7408c2ecf20Sopenharmony_ci		return err;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	/* Start training on the source */
7448c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_LT_CTRL_REG,
7458c2ecf20Sopenharmony_ci			   SP_LT_EN);
7468c2ecf20Sopenharmony_ci	if (err)
7478c2ecf20Sopenharmony_ci		return err;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	return 0;
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistatic int anx78xx_config_dp_output(struct anx78xx *anx78xx)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	int err;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL1_REG,
7578c2ecf20Sopenharmony_ci				 SP_VIDEO_MUTE);
7588c2ecf20Sopenharmony_ci	if (err)
7598c2ecf20Sopenharmony_ci		return err;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	/* Enable DP output */
7628c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL1_REG,
7638c2ecf20Sopenharmony_ci			       SP_VIDEO_EN);
7648c2ecf20Sopenharmony_ci	if (err)
7658c2ecf20Sopenharmony_ci		return err;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic int anx78xx_send_video_infoframe(struct anx78xx *anx78xx,
7718c2ecf20Sopenharmony_ci					struct hdmi_avi_infoframe *frame)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
7748c2ecf20Sopenharmony_ci	int err;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	err = hdmi_avi_infoframe_pack(frame, buffer, sizeof(buffer));
7778c2ecf20Sopenharmony_ci	if (err < 0) {
7788c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to pack AVI infoframe: %d\n", err);
7798c2ecf20Sopenharmony_ci		return err;
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0],
7838c2ecf20Sopenharmony_ci				 SP_PACKET_SEND_CTRL_REG, SP_AVI_IF_EN);
7848c2ecf20Sopenharmony_ci	if (err)
7858c2ecf20Sopenharmony_ci		return err;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	err = regmap_bulk_write(anx78xx->map[I2C_IDX_TX_P2],
7888c2ecf20Sopenharmony_ci				SP_INFOFRAME_AVI_DB1_REG, buffer,
7898c2ecf20Sopenharmony_ci				frame->length);
7908c2ecf20Sopenharmony_ci	if (err)
7918c2ecf20Sopenharmony_ci		return err;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
7948c2ecf20Sopenharmony_ci			       SP_PACKET_SEND_CTRL_REG, SP_AVI_IF_UD);
7958c2ecf20Sopenharmony_ci	if (err)
7968c2ecf20Sopenharmony_ci		return err;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P0],
7998c2ecf20Sopenharmony_ci			       SP_PACKET_SEND_CTRL_REG, SP_AVI_IF_EN);
8008c2ecf20Sopenharmony_ci	if (err)
8018c2ecf20Sopenharmony_ci		return err;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	return 0;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic int anx78xx_get_downstream_info(struct anx78xx *anx78xx)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	u8 value;
8098c2ecf20Sopenharmony_ci	int err;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	err = drm_dp_dpcd_readb(&anx78xx->aux, DP_SINK_COUNT, &value);
8128c2ecf20Sopenharmony_ci	if (err < 0) {
8138c2ecf20Sopenharmony_ci		DRM_ERROR("Get sink count failed %d\n", err);
8148c2ecf20Sopenharmony_ci		return err;
8158c2ecf20Sopenharmony_ci	}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	if (!DP_GET_SINK_COUNT(value)) {
8188c2ecf20Sopenharmony_ci		DRM_ERROR("Downstream disconnected\n");
8198c2ecf20Sopenharmony_ci		return -EIO;
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	return 0;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistatic int anx78xx_get_modes(struct drm_connector *connector)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = connector_to_anx78xx(connector);
8288c2ecf20Sopenharmony_ci	int err, num_modes = 0;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (WARN_ON(!anx78xx->powered))
8318c2ecf20Sopenharmony_ci		return 0;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (anx78xx->edid)
8348c2ecf20Sopenharmony_ci		return drm_add_edid_modes(connector, anx78xx->edid);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	mutex_lock(&anx78xx->lock);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	err = anx78xx_get_downstream_info(anx78xx);
8398c2ecf20Sopenharmony_ci	if (err) {
8408c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to get downstream info: %d\n", err);
8418c2ecf20Sopenharmony_ci		goto unlock;
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	anx78xx->edid = drm_get_edid(connector, &anx78xx->aux.ddc);
8458c2ecf20Sopenharmony_ci	if (!anx78xx->edid) {
8468c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to read EDID\n");
8478c2ecf20Sopenharmony_ci		goto unlock;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	err = drm_connector_update_edid_property(connector,
8518c2ecf20Sopenharmony_ci						 anx78xx->edid);
8528c2ecf20Sopenharmony_ci	if (err) {
8538c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to update EDID property: %d\n", err);
8548c2ecf20Sopenharmony_ci		goto unlock;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	num_modes = drm_add_edid_modes(connector, anx78xx->edid);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ciunlock:
8608c2ecf20Sopenharmony_ci	mutex_unlock(&anx78xx->lock);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	return num_modes;
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cistatic const struct drm_connector_helper_funcs anx78xx_connector_helper_funcs = {
8668c2ecf20Sopenharmony_ci	.get_modes = anx78xx_get_modes,
8678c2ecf20Sopenharmony_ci};
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic enum drm_connector_status anx78xx_detect(struct drm_connector *connector,
8708c2ecf20Sopenharmony_ci						bool force)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = connector_to_anx78xx(connector);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	if (!gpiod_get_value(anx78xx->pdata.gpiod_hpd))
8758c2ecf20Sopenharmony_ci		return connector_status_disconnected;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	return connector_status_connected;
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs anx78xx_connector_funcs = {
8818c2ecf20Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
8828c2ecf20Sopenharmony_ci	.detect = anx78xx_detect,
8838c2ecf20Sopenharmony_ci	.destroy = drm_connector_cleanup,
8848c2ecf20Sopenharmony_ci	.reset = drm_atomic_helper_connector_reset,
8858c2ecf20Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
8868c2ecf20Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
8878c2ecf20Sopenharmony_ci};
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_cistatic int anx78xx_bridge_attach(struct drm_bridge *bridge,
8908c2ecf20Sopenharmony_ci				 enum drm_bridge_attach_flags flags)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
8938c2ecf20Sopenharmony_ci	int err;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
8968c2ecf20Sopenharmony_ci		DRM_ERROR("Fix bridge driver to make connector optional!");
8978c2ecf20Sopenharmony_ci		return -EINVAL;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	if (!bridge->encoder) {
9018c2ecf20Sopenharmony_ci		DRM_ERROR("Parent encoder object not found");
9028c2ecf20Sopenharmony_ci		return -ENODEV;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	/* Register aux channel */
9068c2ecf20Sopenharmony_ci	anx78xx->aux.name = "DP-AUX";
9078c2ecf20Sopenharmony_ci	anx78xx->aux.dev = &anx78xx->client->dev;
9088c2ecf20Sopenharmony_ci	anx78xx->aux.transfer = anx78xx_aux_transfer;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	err = drm_dp_aux_register(&anx78xx->aux);
9118c2ecf20Sopenharmony_ci	if (err < 0) {
9128c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to register aux channel: %d\n", err);
9138c2ecf20Sopenharmony_ci		return err;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	err = drm_connector_init(bridge->dev, &anx78xx->connector,
9178c2ecf20Sopenharmony_ci				 &anx78xx_connector_funcs,
9188c2ecf20Sopenharmony_ci				 DRM_MODE_CONNECTOR_DisplayPort);
9198c2ecf20Sopenharmony_ci	if (err) {
9208c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to initialize connector: %d\n", err);
9218c2ecf20Sopenharmony_ci		return err;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	drm_connector_helper_add(&anx78xx->connector,
9258c2ecf20Sopenharmony_ci				 &anx78xx_connector_helper_funcs);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	err = drm_connector_register(&anx78xx->connector);
9288c2ecf20Sopenharmony_ci	if (err) {
9298c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to register connector: %d\n", err);
9308c2ecf20Sopenharmony_ci		return err;
9318c2ecf20Sopenharmony_ci	}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	anx78xx->connector.polled = DRM_CONNECTOR_POLL_HPD;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	err = drm_connector_attach_encoder(&anx78xx->connector,
9368c2ecf20Sopenharmony_ci					   bridge->encoder);
9378c2ecf20Sopenharmony_ci	if (err) {
9388c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
9398c2ecf20Sopenharmony_ci		return err;
9408c2ecf20Sopenharmony_ci	}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	return 0;
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_cistatic enum drm_mode_status
9468c2ecf20Sopenharmony_cianx78xx_bridge_mode_valid(struct drm_bridge *bridge,
9478c2ecf20Sopenharmony_ci			  const struct drm_display_info *info,
9488c2ecf20Sopenharmony_ci			  const struct drm_display_mode *mode)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
9518c2ecf20Sopenharmony_ci		return MODE_NO_INTERLACE;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	/* Max 1200p at 5.4 Ghz, one lane */
9548c2ecf20Sopenharmony_ci	if (mode->clock > 154000)
9558c2ecf20Sopenharmony_ci		return MODE_CLOCK_HIGH;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	return MODE_OK;
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic void anx78xx_bridge_disable(struct drm_bridge *bridge)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	/* Power off all modules except configuration registers access */
9658c2ecf20Sopenharmony_ci	anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P2], SP_POWERDOWN_CTRL_REG,
9668c2ecf20Sopenharmony_ci			 SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic void anx78xx_bridge_mode_set(struct drm_bridge *bridge,
9708c2ecf20Sopenharmony_ci				const struct drm_display_mode *mode,
9718c2ecf20Sopenharmony_ci				const struct drm_display_mode *adjusted_mode)
9728c2ecf20Sopenharmony_ci{
9738c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
9748c2ecf20Sopenharmony_ci	struct hdmi_avi_infoframe frame;
9758c2ecf20Sopenharmony_ci	int err;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	if (WARN_ON(!anx78xx->powered))
9788c2ecf20Sopenharmony_ci		return;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	mutex_lock(&anx78xx->lock);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	err = drm_hdmi_avi_infoframe_from_display_mode(&frame,
9838c2ecf20Sopenharmony_ci						       &anx78xx->connector,
9848c2ecf20Sopenharmony_ci						       adjusted_mode);
9858c2ecf20Sopenharmony_ci	if (err) {
9868c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to setup AVI infoframe: %d\n", err);
9878c2ecf20Sopenharmony_ci		goto unlock;
9888c2ecf20Sopenharmony_ci	}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	err = anx78xx_send_video_infoframe(anx78xx, &frame);
9918c2ecf20Sopenharmony_ci	if (err)
9928c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to send AVI infoframe: %d\n", err);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ciunlock:
9958c2ecf20Sopenharmony_ci	mutex_unlock(&anx78xx->lock);
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic void anx78xx_bridge_enable(struct drm_bridge *bridge)
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
10018c2ecf20Sopenharmony_ci	int err;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	err = anx78xx_start(anx78xx);
10048c2ecf20Sopenharmony_ci	if (err) {
10058c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to initialize: %d\n", err);
10068c2ecf20Sopenharmony_ci		return;
10078c2ecf20Sopenharmony_ci	}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	err = anx78xx_set_hpd(anx78xx);
10108c2ecf20Sopenharmony_ci	if (err)
10118c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to set HPD: %d\n", err);
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs anx78xx_bridge_funcs = {
10158c2ecf20Sopenharmony_ci	.attach = anx78xx_bridge_attach,
10168c2ecf20Sopenharmony_ci	.mode_valid = anx78xx_bridge_mode_valid,
10178c2ecf20Sopenharmony_ci	.disable = anx78xx_bridge_disable,
10188c2ecf20Sopenharmony_ci	.mode_set = anx78xx_bridge_mode_set,
10198c2ecf20Sopenharmony_ci	.enable = anx78xx_bridge_enable,
10208c2ecf20Sopenharmony_ci};
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic irqreturn_t anx78xx_hpd_threaded_handler(int irq, void *data)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = data;
10258c2ecf20Sopenharmony_ci	int err;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (anx78xx->powered)
10288c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	mutex_lock(&anx78xx->lock);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	/* Cable is pulled, power on the chip */
10338c2ecf20Sopenharmony_ci	anx78xx_poweron(anx78xx);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	err = anx78xx_enable_interrupts(anx78xx);
10368c2ecf20Sopenharmony_ci	if (err)
10378c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to enable interrupts: %d\n", err);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	mutex_unlock(&anx78xx->lock);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic int anx78xx_handle_dp_int_1(struct anx78xx *anx78xx, u8 irq)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	int err;
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("Handle DP interrupt 1: %02x\n", irq);
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P2], SP_DP_INT_STATUS1_REG,
10518c2ecf20Sopenharmony_ci			   irq);
10528c2ecf20Sopenharmony_ci	if (err)
10538c2ecf20Sopenharmony_ci		return err;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (irq & SP_TRAINING_FINISH) {
10568c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("IRQ: hardware link training finished\n");
10578c2ecf20Sopenharmony_ci		err = anx78xx_config_dp_output(anx78xx);
10588c2ecf20Sopenharmony_ci	}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	return err;
10618c2ecf20Sopenharmony_ci}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_cistatic bool anx78xx_handle_common_int_4(struct anx78xx *anx78xx, u8 irq)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	bool event = false;
10668c2ecf20Sopenharmony_ci	int err;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("Handle common interrupt 4: %02x\n", irq);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_TX_P2],
10718c2ecf20Sopenharmony_ci			   SP_COMMON_INT_STATUS4_REG, irq);
10728c2ecf20Sopenharmony_ci	if (err) {
10738c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to write SP_COMMON_INT_STATUS4 %d\n", err);
10748c2ecf20Sopenharmony_ci		return event;
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	if (irq & SP_HPD_LOST) {
10788c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("IRQ: Hot plug detect - cable is pulled out\n");
10798c2ecf20Sopenharmony_ci		event = true;
10808c2ecf20Sopenharmony_ci		anx78xx_poweroff(anx78xx);
10818c2ecf20Sopenharmony_ci		/* Free cached EDID */
10828c2ecf20Sopenharmony_ci		kfree(anx78xx->edid);
10838c2ecf20Sopenharmony_ci		anx78xx->edid = NULL;
10848c2ecf20Sopenharmony_ci	} else if (irq & SP_HPD_PLUG) {
10858c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("IRQ: Hot plug detect - cable plug\n");
10868c2ecf20Sopenharmony_ci		event = true;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	return event;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_cistatic void anx78xx_handle_hdmi_int_1(struct anx78xx *anx78xx, u8 irq)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	unsigned int value;
10958c2ecf20Sopenharmony_ci	int err;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	DRM_DEBUG_KMS("Handle HDMI interrupt 1: %02x\n", irq);
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	err = regmap_write(anx78xx->map[I2C_IDX_RX_P0], SP_INT_STATUS1_REG,
11008c2ecf20Sopenharmony_ci			   irq);
11018c2ecf20Sopenharmony_ci	if (err) {
11028c2ecf20Sopenharmony_ci		DRM_ERROR("Write HDMI int 1 failed: %d\n", err);
11038c2ecf20Sopenharmony_ci		return;
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	if ((irq & SP_CKDT_CHG) || (irq & SP_SCDT_CHG)) {
11078c2ecf20Sopenharmony_ci		DRM_DEBUG_KMS("IRQ: HDMI input detected\n");
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci		err = regmap_read(anx78xx->map[I2C_IDX_RX_P0],
11108c2ecf20Sopenharmony_ci				  SP_SYSTEM_STATUS_REG, &value);
11118c2ecf20Sopenharmony_ci		if (err) {
11128c2ecf20Sopenharmony_ci			DRM_ERROR("Read system status reg failed: %d\n", err);
11138c2ecf20Sopenharmony_ci			return;
11148c2ecf20Sopenharmony_ci		}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci		if (!(value & SP_TMDS_CLOCK_DET)) {
11178c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("IRQ: *** Waiting for HDMI clock ***\n");
11188c2ecf20Sopenharmony_ci			return;
11198c2ecf20Sopenharmony_ci		}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci		if (!(value & SP_TMDS_DE_DET)) {
11228c2ecf20Sopenharmony_ci			DRM_DEBUG_KMS("IRQ: *** Waiting for HDMI signal ***\n");
11238c2ecf20Sopenharmony_ci			return;
11248c2ecf20Sopenharmony_ci		}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci		err = anx78xx_dp_link_training(anx78xx);
11278c2ecf20Sopenharmony_ci		if (err)
11288c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to start link training: %d\n", err);
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic irqreturn_t anx78xx_intp_threaded_handler(int unused, void *data)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = data;
11358c2ecf20Sopenharmony_ci	bool event = false;
11368c2ecf20Sopenharmony_ci	unsigned int irq;
11378c2ecf20Sopenharmony_ci	int err;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	mutex_lock(&anx78xx->lock);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	err = regmap_read(anx78xx->map[I2C_IDX_TX_P2], SP_DP_INT_STATUS1_REG,
11428c2ecf20Sopenharmony_ci			  &irq);
11438c2ecf20Sopenharmony_ci	if (err) {
11448c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to read DP interrupt 1 status: %d\n", err);
11458c2ecf20Sopenharmony_ci		goto unlock;
11468c2ecf20Sopenharmony_ci	}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	if (irq)
11498c2ecf20Sopenharmony_ci		anx78xx_handle_dp_int_1(anx78xx, irq);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	err = regmap_read(anx78xx->map[I2C_IDX_TX_P2],
11528c2ecf20Sopenharmony_ci			  SP_COMMON_INT_STATUS4_REG, &irq);
11538c2ecf20Sopenharmony_ci	if (err) {
11548c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to read common interrupt 4 status: %d\n",
11558c2ecf20Sopenharmony_ci			  err);
11568c2ecf20Sopenharmony_ci		goto unlock;
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	if (irq)
11608c2ecf20Sopenharmony_ci		event = anx78xx_handle_common_int_4(anx78xx, irq);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	/* Make sure we are still powered after handle HPD events */
11638c2ecf20Sopenharmony_ci	if (!anx78xx->powered)
11648c2ecf20Sopenharmony_ci		goto unlock;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	err = regmap_read(anx78xx->map[I2C_IDX_RX_P0], SP_INT_STATUS1_REG,
11678c2ecf20Sopenharmony_ci			  &irq);
11688c2ecf20Sopenharmony_ci	if (err) {
11698c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to read HDMI int 1 status: %d\n", err);
11708c2ecf20Sopenharmony_ci		goto unlock;
11718c2ecf20Sopenharmony_ci	}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	if (irq)
11748c2ecf20Sopenharmony_ci		anx78xx_handle_hdmi_int_1(anx78xx, irq);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ciunlock:
11778c2ecf20Sopenharmony_ci	mutex_unlock(&anx78xx->lock);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	if (event)
11808c2ecf20Sopenharmony_ci		drm_helper_hpd_irq_event(anx78xx->connector.dev);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_cistatic void unregister_i2c_dummy_clients(struct anx78xx *anx78xx)
11868c2ecf20Sopenharmony_ci{
11878c2ecf20Sopenharmony_ci	unsigned int i;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(anx78xx->i2c_dummy); i++)
11908c2ecf20Sopenharmony_ci		i2c_unregister_device(anx78xx->i2c_dummy[i]);
11918c2ecf20Sopenharmony_ci}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_cistatic const struct regmap_config anx78xx_regmap_config = {
11948c2ecf20Sopenharmony_ci	.reg_bits = 8,
11958c2ecf20Sopenharmony_ci	.val_bits = 8,
11968c2ecf20Sopenharmony_ci};
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistatic const u16 anx78xx_chipid_list[] = {
11998c2ecf20Sopenharmony_ci	0x7808,
12008c2ecf20Sopenharmony_ci	0x7812,
12018c2ecf20Sopenharmony_ci	0x7814,
12028c2ecf20Sopenharmony_ci	0x7818,
12038c2ecf20Sopenharmony_ci};
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cistatic int anx78xx_i2c_probe(struct i2c_client *client,
12068c2ecf20Sopenharmony_ci			     const struct i2c_device_id *id)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx;
12098c2ecf20Sopenharmony_ci	struct anx78xx_platform_data *pdata;
12108c2ecf20Sopenharmony_ci	unsigned int i, idl, idh, version;
12118c2ecf20Sopenharmony_ci	const u8 *i2c_addresses;
12128c2ecf20Sopenharmony_ci	bool found = false;
12138c2ecf20Sopenharmony_ci	int err;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	anx78xx = devm_kzalloc(&client->dev, sizeof(*anx78xx), GFP_KERNEL);
12168c2ecf20Sopenharmony_ci	if (!anx78xx)
12178c2ecf20Sopenharmony_ci		return -ENOMEM;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	pdata = &anx78xx->pdata;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	mutex_init(&anx78xx->lock);
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
12248c2ecf20Sopenharmony_ci	anx78xx->bridge.of_node = client->dev.of_node;
12258c2ecf20Sopenharmony_ci#endif
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	anx78xx->client = client;
12288c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, anx78xx);
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	err = anx78xx_init_pdata(anx78xx);
12318c2ecf20Sopenharmony_ci	if (err) {
12328c2ecf20Sopenharmony_ci		if (err != -EPROBE_DEFER)
12338c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to initialize pdata: %d\n", err);
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci		return err;
12368c2ecf20Sopenharmony_ci	}
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	pdata->hpd_irq = gpiod_to_irq(pdata->gpiod_hpd);
12398c2ecf20Sopenharmony_ci	if (pdata->hpd_irq < 0) {
12408c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to get HPD IRQ: %d\n", pdata->hpd_irq);
12418c2ecf20Sopenharmony_ci		return -ENODEV;
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	pdata->intp_irq = client->irq;
12458c2ecf20Sopenharmony_ci	if (!pdata->intp_irq) {
12468c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to get CABLE_DET and INTP IRQ\n");
12478c2ecf20Sopenharmony_ci		return -ENODEV;
12488c2ecf20Sopenharmony_ci	}
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	/* Map slave addresses of ANX7814 */
12518c2ecf20Sopenharmony_ci	i2c_addresses = device_get_match_data(&client->dev);
12528c2ecf20Sopenharmony_ci	for (i = 0; i < I2C_NUM_ADDRESSES; i++) {
12538c2ecf20Sopenharmony_ci		struct i2c_client *i2c_dummy;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci		i2c_dummy = i2c_new_dummy_device(client->adapter,
12568c2ecf20Sopenharmony_ci						 i2c_addresses[i] >> 1);
12578c2ecf20Sopenharmony_ci		if (IS_ERR(i2c_dummy)) {
12588c2ecf20Sopenharmony_ci			err = PTR_ERR(i2c_dummy);
12598c2ecf20Sopenharmony_ci			DRM_ERROR("Failed to reserve I2C bus %02x: %d\n",
12608c2ecf20Sopenharmony_ci				  i2c_addresses[i], err);
12618c2ecf20Sopenharmony_ci			goto err_unregister_i2c;
12628c2ecf20Sopenharmony_ci		}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci		anx78xx->i2c_dummy[i] = i2c_dummy;
12658c2ecf20Sopenharmony_ci		anx78xx->map[i] = devm_regmap_init_i2c(anx78xx->i2c_dummy[i],
12668c2ecf20Sopenharmony_ci						       &anx78xx_regmap_config);
12678c2ecf20Sopenharmony_ci		if (IS_ERR(anx78xx->map[i])) {
12688c2ecf20Sopenharmony_ci			err = PTR_ERR(anx78xx->map[i]);
12698c2ecf20Sopenharmony_ci			DRM_ERROR("Failed regmap initialization %02x\n",
12708c2ecf20Sopenharmony_ci				  i2c_addresses[i]);
12718c2ecf20Sopenharmony_ci			goto err_unregister_i2c;
12728c2ecf20Sopenharmony_ci		}
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	/* Look for supported chip ID */
12768c2ecf20Sopenharmony_ci	anx78xx_poweron(anx78xx);
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	err = regmap_read(anx78xx->map[I2C_IDX_TX_P2], SP_DEVICE_IDL_REG,
12798c2ecf20Sopenharmony_ci			  &idl);
12808c2ecf20Sopenharmony_ci	if (err)
12818c2ecf20Sopenharmony_ci		goto err_poweroff;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	err = regmap_read(anx78xx->map[I2C_IDX_TX_P2], SP_DEVICE_IDH_REG,
12848c2ecf20Sopenharmony_ci			  &idh);
12858c2ecf20Sopenharmony_ci	if (err)
12868c2ecf20Sopenharmony_ci		goto err_poweroff;
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	anx78xx->chipid = (u8)idl | ((u8)idh << 8);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	err = regmap_read(anx78xx->map[I2C_IDX_TX_P2], SP_DEVICE_VERSION_REG,
12918c2ecf20Sopenharmony_ci			  &version);
12928c2ecf20Sopenharmony_ci	if (err)
12938c2ecf20Sopenharmony_ci		goto err_poweroff;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(anx78xx_chipid_list); i++) {
12968c2ecf20Sopenharmony_ci		if (anx78xx->chipid == anx78xx_chipid_list[i]) {
12978c2ecf20Sopenharmony_ci			DRM_INFO("Found ANX%x (ver. %d) SlimPort Transmitter\n",
12988c2ecf20Sopenharmony_ci				 anx78xx->chipid, version);
12998c2ecf20Sopenharmony_ci			found = true;
13008c2ecf20Sopenharmony_ci			break;
13018c2ecf20Sopenharmony_ci		}
13028c2ecf20Sopenharmony_ci	}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	if (!found) {
13058c2ecf20Sopenharmony_ci		DRM_ERROR("ANX%x (ver. %d) not supported by this driver\n",
13068c2ecf20Sopenharmony_ci			  anx78xx->chipid, version);
13078c2ecf20Sopenharmony_ci		err = -ENODEV;
13088c2ecf20Sopenharmony_ci		goto err_poweroff;
13098c2ecf20Sopenharmony_ci	}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	err = devm_request_threaded_irq(&client->dev, pdata->hpd_irq, NULL,
13128c2ecf20Sopenharmony_ci					anx78xx_hpd_threaded_handler,
13138c2ecf20Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
13148c2ecf20Sopenharmony_ci					"anx78xx-hpd", anx78xx);
13158c2ecf20Sopenharmony_ci	if (err) {
13168c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to request CABLE_DET threaded IRQ: %d\n",
13178c2ecf20Sopenharmony_ci			  err);
13188c2ecf20Sopenharmony_ci		goto err_poweroff;
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	err = devm_request_threaded_irq(&client->dev, pdata->intp_irq, NULL,
13228c2ecf20Sopenharmony_ci					anx78xx_intp_threaded_handler,
13238c2ecf20Sopenharmony_ci					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
13248c2ecf20Sopenharmony_ci					"anx78xx-intp", anx78xx);
13258c2ecf20Sopenharmony_ci	if (err) {
13268c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to request INTP threaded IRQ: %d\n", err);
13278c2ecf20Sopenharmony_ci		goto err_poweroff;
13288c2ecf20Sopenharmony_ci	}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	anx78xx->bridge.funcs = &anx78xx_bridge_funcs;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	drm_bridge_add(&anx78xx->bridge);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	/* If cable is pulled out, just poweroff and wait for HPD event */
13358c2ecf20Sopenharmony_ci	if (!gpiod_get_value(anx78xx->pdata.gpiod_hpd))
13368c2ecf20Sopenharmony_ci		anx78xx_poweroff(anx78xx);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	return 0;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_cierr_poweroff:
13418c2ecf20Sopenharmony_ci	anx78xx_poweroff(anx78xx);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_cierr_unregister_i2c:
13448c2ecf20Sopenharmony_ci	unregister_i2c_dummy_clients(anx78xx);
13458c2ecf20Sopenharmony_ci	return err;
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_cistatic int anx78xx_i2c_remove(struct i2c_client *client)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	struct anx78xx *anx78xx = i2c_get_clientdata(client);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	drm_bridge_remove(&anx78xx->bridge);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	unregister_i2c_dummy_clients(anx78xx);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	kfree(anx78xx->edid);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	return 0;
13598c2ecf20Sopenharmony_ci}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_cistatic const struct i2c_device_id anx78xx_id[] = {
13628c2ecf20Sopenharmony_ci	{ "anx7814", 0 },
13638c2ecf20Sopenharmony_ci	{ /* sentinel */ }
13648c2ecf20Sopenharmony_ci};
13658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, anx78xx_id);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
13688c2ecf20Sopenharmony_cistatic const struct of_device_id anx78xx_match_table[] = {
13698c2ecf20Sopenharmony_ci	{ .compatible = "analogix,anx7808", .data = anx7808_i2c_addresses },
13708c2ecf20Sopenharmony_ci	{ .compatible = "analogix,anx7812", .data = anx781x_i2c_addresses },
13718c2ecf20Sopenharmony_ci	{ .compatible = "analogix,anx7814", .data = anx781x_i2c_addresses },
13728c2ecf20Sopenharmony_ci	{ .compatible = "analogix,anx7818", .data = anx781x_i2c_addresses },
13738c2ecf20Sopenharmony_ci	{ /* sentinel */ },
13748c2ecf20Sopenharmony_ci};
13758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, anx78xx_match_table);
13768c2ecf20Sopenharmony_ci#endif
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_cistatic struct i2c_driver anx78xx_driver = {
13798c2ecf20Sopenharmony_ci	.driver = {
13808c2ecf20Sopenharmony_ci		   .name = "anx7814",
13818c2ecf20Sopenharmony_ci		   .of_match_table = of_match_ptr(anx78xx_match_table),
13828c2ecf20Sopenharmony_ci		  },
13838c2ecf20Sopenharmony_ci	.probe = anx78xx_i2c_probe,
13848c2ecf20Sopenharmony_ci	.remove = anx78xx_i2c_remove,
13858c2ecf20Sopenharmony_ci	.id_table = anx78xx_id,
13868c2ecf20Sopenharmony_ci};
13878c2ecf20Sopenharmony_cimodule_i2c_driver(anx78xx_driver);
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ANX78xx SlimPort Transmitter driver");
13908c2ecf20Sopenharmony_ciMODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
13918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1392