18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Samsung Electronics
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Authors:
68c2ecf20Sopenharmony_ci *    Tomasz Stanislawski <t.stanislaws@samsung.com>
78c2ecf20Sopenharmony_ci *    Maciej Purski <m.purski@samsung.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Based on sii9234 driver created by:
108c2ecf20Sopenharmony_ci *    Adam Hampson <ahampson@sta.samsung.com>
118c2ecf20Sopenharmony_ci *    Erik Gilling <konkers@android.com>
128c2ecf20Sopenharmony_ci *    Shankar Bandal <shankar.b@samsung.com>
138c2ecf20Sopenharmony_ci *    Dharam Kumar <dharam.kr@samsung.com>
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci#include <drm/bridge/mhl.h>
168c2ecf20Sopenharmony_ci#include <drm/drm_bridge.h>
178c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h>
188c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/delay.h>
218c2ecf20Sopenharmony_ci#include <linux/err.h>
228c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
238c2ecf20Sopenharmony_ci#include <linux/i2c.h>
248c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
258c2ecf20Sopenharmony_ci#include <linux/irq.h>
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/module.h>
288c2ecf20Sopenharmony_ci#include <linux/mutex.h>
298c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
308c2ecf20Sopenharmony_ci#include <linux/slab.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define CBUS_DEVCAP_OFFSET		0x80
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define SII9234_MHL_VERSION		0x11
358c2ecf20Sopenharmony_ci#define SII9234_SCRATCHPAD_SIZE		0x10
368c2ecf20Sopenharmony_ci#define SII9234_INT_STAT_SIZE		0x33
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define BIT_TMDS_CCTRL_TMDS_OE		BIT(4)
398c2ecf20Sopenharmony_ci#define MHL_HPD_OUT_OVR_EN		BIT(4)
408c2ecf20Sopenharmony_ci#define MHL_HPD_OUT_OVR_VAL		BIT(5)
418c2ecf20Sopenharmony_ci#define MHL_INIT_TIMEOUT		0x0C
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* MHL Tx registers and bits */
448c2ecf20Sopenharmony_ci#define MHL_TX_SRST			0x05
458c2ecf20Sopenharmony_ci#define MHL_TX_SYSSTAT_REG		0x09
468c2ecf20Sopenharmony_ci#define MHL_TX_INTR1_REG		0x71
478c2ecf20Sopenharmony_ci#define MHL_TX_INTR4_REG		0x74
488c2ecf20Sopenharmony_ci#define MHL_TX_INTR1_ENABLE_REG		0x75
498c2ecf20Sopenharmony_ci#define MHL_TX_INTR4_ENABLE_REG		0x78
508c2ecf20Sopenharmony_ci#define MHL_TX_INT_CTRL_REG		0x79
518c2ecf20Sopenharmony_ci#define MHL_TX_TMDS_CCTRL		0x80
528c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL1_REG		0x90
538c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL2_REG		0x91
548c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL3_REG		0x92
558c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL4_REG		0x93
568c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL5_REG		0x94
578c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL6_REG		0x95
588c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL7_REG		0x96
598c2ecf20Sopenharmony_ci#define MHL_TX_DISC_CTRL8_REG		0x97
608c2ecf20Sopenharmony_ci#define MHL_TX_STAT2_REG		0x99
618c2ecf20Sopenharmony_ci#define MHL_TX_MHLTX_CTL1_REG		0xA0
628c2ecf20Sopenharmony_ci#define MHL_TX_MHLTX_CTL2_REG		0xA1
638c2ecf20Sopenharmony_ci#define MHL_TX_MHLTX_CTL4_REG		0xA3
648c2ecf20Sopenharmony_ci#define MHL_TX_MHLTX_CTL6_REG		0xA5
658c2ecf20Sopenharmony_ci#define MHL_TX_MHLTX_CTL7_REG		0xA6
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define RSEN_STATUS			BIT(2)
688c2ecf20Sopenharmony_ci#define HPD_CHANGE_INT			BIT(6)
698c2ecf20Sopenharmony_ci#define RSEN_CHANGE_INT			BIT(5)
708c2ecf20Sopenharmony_ci#define RGND_READY_INT			BIT(6)
718c2ecf20Sopenharmony_ci#define VBUS_LOW_INT			BIT(5)
728c2ecf20Sopenharmony_ci#define CBUS_LKOUT_INT			BIT(4)
738c2ecf20Sopenharmony_ci#define MHL_DISC_FAIL_INT		BIT(3)
748c2ecf20Sopenharmony_ci#define MHL_EST_INT			BIT(2)
758c2ecf20Sopenharmony_ci#define HPD_CHANGE_INT_MASK		BIT(6)
768c2ecf20Sopenharmony_ci#define RSEN_CHANGE_INT_MASK		BIT(5)
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define RGND_READY_MASK			BIT(6)
798c2ecf20Sopenharmony_ci#define CBUS_LKOUT_MASK			BIT(4)
808c2ecf20Sopenharmony_ci#define MHL_DISC_FAIL_MASK		BIT(3)
818c2ecf20Sopenharmony_ci#define MHL_EST_MASK			BIT(2)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define SKIP_GND			BIT(6)
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define ATT_THRESH_SHIFT		0x04
868c2ecf20Sopenharmony_ci#define ATT_THRESH_MASK			(0x03 << ATT_THRESH_SHIFT)
878c2ecf20Sopenharmony_ci#define USB_D_OEN			BIT(3)
888c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_MASK		0x07
898c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_2MS		0
908c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_4MS		1
918c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_8MS		2
928c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_16MS		3
938c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_40MS		4
948c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_50MS		5
958c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_60MS		6
968c2ecf20Sopenharmony_ci#define DEGLITCH_TIME_128MS		7
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define USB_D_OVR			BIT(7)
998c2ecf20Sopenharmony_ci#define USB_ID_OVR			BIT(6)
1008c2ecf20Sopenharmony_ci#define DVRFLT_SEL			BIT(5)
1018c2ecf20Sopenharmony_ci#define BLOCK_RGND_INT			BIT(4)
1028c2ecf20Sopenharmony_ci#define SKIP_DEG			BIT(3)
1038c2ecf20Sopenharmony_ci#define CI2CA_POL			BIT(2)
1048c2ecf20Sopenharmony_ci#define CI2CA_WKUP			BIT(1)
1058c2ecf20Sopenharmony_ci#define SINGLE_ATT			BIT(0)
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#define USB_D_ODN			BIT(5)
1088c2ecf20Sopenharmony_ci#define VBUS_CHECK			BIT(2)
1098c2ecf20Sopenharmony_ci#define RGND_INTP_MASK			0x03
1108c2ecf20Sopenharmony_ci#define RGND_INTP_OPEN			0
1118c2ecf20Sopenharmony_ci#define RGND_INTP_2K			1
1128c2ecf20Sopenharmony_ci#define RGND_INTP_1K			2
1138c2ecf20Sopenharmony_ci#define RGND_INTP_SHORT			3
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/* HDMI registers */
1168c2ecf20Sopenharmony_ci#define HDMI_RX_TMDS0_CCTRL1_REG	0x10
1178c2ecf20Sopenharmony_ci#define HDMI_RX_TMDS_CLK_EN_REG		0x11
1188c2ecf20Sopenharmony_ci#define HDMI_RX_TMDS_CH_EN_REG		0x12
1198c2ecf20Sopenharmony_ci#define HDMI_RX_PLL_CALREFSEL_REG	0x17
1208c2ecf20Sopenharmony_ci#define HDMI_RX_PLL_VCOCAL_REG		0x1A
1218c2ecf20Sopenharmony_ci#define HDMI_RX_EQ_DATA0_REG		0x22
1228c2ecf20Sopenharmony_ci#define HDMI_RX_EQ_DATA1_REG		0x23
1238c2ecf20Sopenharmony_ci#define HDMI_RX_EQ_DATA2_REG		0x24
1248c2ecf20Sopenharmony_ci#define HDMI_RX_EQ_DATA3_REG		0x25
1258c2ecf20Sopenharmony_ci#define HDMI_RX_EQ_DATA4_REG		0x26
1268c2ecf20Sopenharmony_ci#define HDMI_RX_TMDS_ZONE_CTRL_REG	0x4C
1278c2ecf20Sopenharmony_ci#define HDMI_RX_TMDS_MODE_CTRL_REG	0x4D
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/* CBUS registers */
1308c2ecf20Sopenharmony_ci#define CBUS_INT_STATUS_1_REG		0x08
1318c2ecf20Sopenharmony_ci#define CBUS_INTR1_ENABLE_REG		0x09
1328c2ecf20Sopenharmony_ci#define CBUS_MSC_REQ_ABORT_REASON_REG	0x0D
1338c2ecf20Sopenharmony_ci#define CBUS_INT_STATUS_2_REG		0x1E
1348c2ecf20Sopenharmony_ci#define CBUS_INTR2_ENABLE_REG		0x1F
1358c2ecf20Sopenharmony_ci#define CBUS_LINK_CONTROL_2_REG		0x31
1368c2ecf20Sopenharmony_ci#define CBUS_MHL_STATUS_REG_0		0xB0
1378c2ecf20Sopenharmony_ci#define CBUS_MHL_STATUS_REG_1		0xB1
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define BIT_CBUS_RESET			BIT(3)
1408c2ecf20Sopenharmony_ci#define SET_HPD_DOWNSTREAM		BIT(6)
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/* TPI registers */
1438c2ecf20Sopenharmony_ci#define TPI_DPD_REG			0x3D
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/* Timeouts in msec */
1468c2ecf20Sopenharmony_ci#define T_SRC_VBUS_CBUS_TO_STABLE	200
1478c2ecf20Sopenharmony_ci#define T_SRC_CBUS_FLOAT		100
1488c2ecf20Sopenharmony_ci#define T_SRC_CBUS_DEGLITCH		2
1498c2ecf20Sopenharmony_ci#define T_SRC_RXSENSE_DEGLITCH		110
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define MHL1_MAX_CLK			75000 /* in kHz */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci#define I2C_TPI_ADDR			0x3D
1548c2ecf20Sopenharmony_ci#define I2C_HDMI_ADDR			0x49
1558c2ecf20Sopenharmony_ci#define I2C_CBUS_ADDR			0x64
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cienum sii9234_state {
1588c2ecf20Sopenharmony_ci	ST_OFF,
1598c2ecf20Sopenharmony_ci	ST_D3,
1608c2ecf20Sopenharmony_ci	ST_RGND_INIT,
1618c2ecf20Sopenharmony_ci	ST_RGND_1K,
1628c2ecf20Sopenharmony_ci	ST_RSEN_HIGH,
1638c2ecf20Sopenharmony_ci	ST_MHL_ESTABLISHED,
1648c2ecf20Sopenharmony_ci	ST_FAILURE_DISCOVERY,
1658c2ecf20Sopenharmony_ci	ST_FAILURE,
1668c2ecf20Sopenharmony_ci};
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistruct sii9234 {
1698c2ecf20Sopenharmony_ci	struct i2c_client *client[4];
1708c2ecf20Sopenharmony_ci	struct drm_bridge bridge;
1718c2ecf20Sopenharmony_ci	struct device *dev;
1728c2ecf20Sopenharmony_ci	struct gpio_desc *gpio_reset;
1738c2ecf20Sopenharmony_ci	int i2c_error;
1748c2ecf20Sopenharmony_ci	struct regulator_bulk_data supplies[4];
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	struct mutex lock; /* Protects fields below and device registers */
1778c2ecf20Sopenharmony_ci	enum sii9234_state state;
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cienum sii9234_client_id {
1818c2ecf20Sopenharmony_ci	I2C_MHL,
1828c2ecf20Sopenharmony_ci	I2C_TPI,
1838c2ecf20Sopenharmony_ci	I2C_HDMI,
1848c2ecf20Sopenharmony_ci	I2C_CBUS,
1858c2ecf20Sopenharmony_ci};
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic const char * const sii9234_client_name[] = {
1888c2ecf20Sopenharmony_ci	[I2C_MHL] = "MHL",
1898c2ecf20Sopenharmony_ci	[I2C_TPI] = "TPI",
1908c2ecf20Sopenharmony_ci	[I2C_HDMI] = "HDMI",
1918c2ecf20Sopenharmony_ci	[I2C_CBUS] = "CBUS",
1928c2ecf20Sopenharmony_ci};
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int sii9234_writeb(struct sii9234 *ctx, int id, int offset,
1958c2ecf20Sopenharmony_ci			  int value)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	int ret;
1988c2ecf20Sopenharmony_ci	struct i2c_client *client = ctx->client[id];
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (ctx->i2c_error)
2018c2ecf20Sopenharmony_ci		return ctx->i2c_error;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, offset, value);
2048c2ecf20Sopenharmony_ci	if (ret < 0)
2058c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "writeb: %4s[0x%02x] <- 0x%02x\n",
2068c2ecf20Sopenharmony_ci			sii9234_client_name[id], offset, value);
2078c2ecf20Sopenharmony_ci	ctx->i2c_error = ret;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	return ret;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic int sii9234_writebm(struct sii9234 *ctx, int id, int offset,
2138c2ecf20Sopenharmony_ci			   int value, int mask)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int ret;
2168c2ecf20Sopenharmony_ci	struct i2c_client *client = ctx->client[id];
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (ctx->i2c_error)
2198c2ecf20Sopenharmony_ci		return ctx->i2c_error;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte(client, offset);
2228c2ecf20Sopenharmony_ci	if (ret < 0) {
2238c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
2248c2ecf20Sopenharmony_ci			sii9234_client_name[id], offset, value);
2258c2ecf20Sopenharmony_ci		ctx->i2c_error = ret;
2268c2ecf20Sopenharmony_ci		return ret;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte(client);
2308c2ecf20Sopenharmony_ci	if (ret < 0) {
2318c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
2328c2ecf20Sopenharmony_ci			sii9234_client_name[id], offset, value);
2338c2ecf20Sopenharmony_ci		ctx->i2c_error = ret;
2348c2ecf20Sopenharmony_ci		return ret;
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	value = (value & mask) | (ret & ~mask);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, offset, value);
2408c2ecf20Sopenharmony_ci	if (ret < 0) {
2418c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
2428c2ecf20Sopenharmony_ci			sii9234_client_name[id], offset, value);
2438c2ecf20Sopenharmony_ci		ctx->i2c_error = ret;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return ret;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic int sii9234_readb(struct sii9234 *ctx, int id, int offset)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	int ret;
2528c2ecf20Sopenharmony_ci	struct i2c_client *client = ctx->client[id];
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (ctx->i2c_error)
2558c2ecf20Sopenharmony_ci		return ctx->i2c_error;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte(client, offset);
2588c2ecf20Sopenharmony_ci	if (ret < 0) {
2598c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
2608c2ecf20Sopenharmony_ci			sii9234_client_name[id], offset);
2618c2ecf20Sopenharmony_ci		ctx->i2c_error = ret;
2628c2ecf20Sopenharmony_ci		return ret;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte(client);
2668c2ecf20Sopenharmony_ci	if (ret < 0) {
2678c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
2688c2ecf20Sopenharmony_ci			sii9234_client_name[id], offset);
2698c2ecf20Sopenharmony_ci		ctx->i2c_error = ret;
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return ret;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int sii9234_clear_error(struct sii9234 *ctx)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	int ret = ctx->i2c_error;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	ctx->i2c_error = 0;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return ret;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci#define mhl_tx_writeb(sii9234, offset, value) \
2858c2ecf20Sopenharmony_ci	sii9234_writeb(sii9234, I2C_MHL, offset, value)
2868c2ecf20Sopenharmony_ci#define mhl_tx_writebm(sii9234, offset, value, mask) \
2878c2ecf20Sopenharmony_ci	sii9234_writebm(sii9234, I2C_MHL, offset, value, mask)
2888c2ecf20Sopenharmony_ci#define mhl_tx_readb(sii9234, offset) \
2898c2ecf20Sopenharmony_ci	sii9234_readb(sii9234, I2C_MHL, offset)
2908c2ecf20Sopenharmony_ci#define cbus_writeb(sii9234, offset, value) \
2918c2ecf20Sopenharmony_ci	sii9234_writeb(sii9234, I2C_CBUS, offset, value)
2928c2ecf20Sopenharmony_ci#define cbus_writebm(sii9234, offset, value, mask) \
2938c2ecf20Sopenharmony_ci	sii9234_writebm(sii9234, I2C_CBUS, offset, value, mask)
2948c2ecf20Sopenharmony_ci#define cbus_readb(sii9234, offset) \
2958c2ecf20Sopenharmony_ci	sii9234_readb(sii9234, I2C_CBUS, offset)
2968c2ecf20Sopenharmony_ci#define hdmi_writeb(sii9234, offset, value) \
2978c2ecf20Sopenharmony_ci	sii9234_writeb(sii9234, I2C_HDMI, offset, value)
2988c2ecf20Sopenharmony_ci#define hdmi_writebm(sii9234, offset, value, mask) \
2998c2ecf20Sopenharmony_ci	sii9234_writebm(sii9234, I2C_HDMI, offset, value, mask)
3008c2ecf20Sopenharmony_ci#define hdmi_readb(sii9234, offset) \
3018c2ecf20Sopenharmony_ci	sii9234_readb(sii9234, I2C_HDMI, offset)
3028c2ecf20Sopenharmony_ci#define tpi_writeb(sii9234, offset, value) \
3038c2ecf20Sopenharmony_ci	sii9234_writeb(sii9234, I2C_TPI, offset, value)
3048c2ecf20Sopenharmony_ci#define tpi_writebm(sii9234, offset, value, mask) \
3058c2ecf20Sopenharmony_ci	sii9234_writebm(sii9234, I2C_TPI, offset, value, mask)
3068c2ecf20Sopenharmony_ci#define tpi_readb(sii9234, offset) \
3078c2ecf20Sopenharmony_ci	sii9234_readb(sii9234, I2C_TPI, offset)
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic u8 sii9234_tmds_control(struct sii9234 *ctx, bool enable)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_TMDS_CCTRL, enable ? ~0 : 0,
3128c2ecf20Sopenharmony_ci		       BIT_TMDS_CCTRL_TMDS_OE);
3138c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, enable ? ~0 : 0,
3148c2ecf20Sopenharmony_ci		       MHL_HPD_OUT_OVR_EN | MHL_HPD_OUT_OVR_VAL);
3158c2ecf20Sopenharmony_ci	return sii9234_clear_error(ctx);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic int sii9234_cbus_reset(struct sii9234 *ctx)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	int i;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_SRST, ~0, BIT_CBUS_RESET);
3238c2ecf20Sopenharmony_ci	msleep(T_SRC_CBUS_DEGLITCH);
3248c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_SRST, 0, BIT_CBUS_RESET);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
3278c2ecf20Sopenharmony_ci		/*
3288c2ecf20Sopenharmony_ci		 * Enable WRITE_STAT interrupt for writes to all
3298c2ecf20Sopenharmony_ci		 * 4 MSC Status registers.
3308c2ecf20Sopenharmony_ci		 */
3318c2ecf20Sopenharmony_ci		cbus_writeb(ctx, 0xE0 + i, 0xF2);
3328c2ecf20Sopenharmony_ci		/*
3338c2ecf20Sopenharmony_ci		 * Enable SET_INT interrupt for writes to all
3348c2ecf20Sopenharmony_ci		 * 4 MSC Interrupt registers.
3358c2ecf20Sopenharmony_ci		 */
3368c2ecf20Sopenharmony_ci		cbus_writeb(ctx, 0xF0 + i, 0xF2);
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return sii9234_clear_error(ctx);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci/* Require to chek mhl imformation of samsung in cbus_init_register */
3438c2ecf20Sopenharmony_cistatic int sii9234_cbus_init(struct sii9234 *ctx)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x07, 0xF2);
3468c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x40, 0x03);
3478c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x42, 0x06);
3488c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x36, 0x0C);
3498c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x3D, 0xFD);
3508c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x1C, 0x01);
3518c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x1D, 0x0F);
3528c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x44, 0x02);
3538c2ecf20Sopenharmony_ci	/* Setup our devcap */
3548c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEV_STATE, 0x00);
3558c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_MHL_VERSION,
3568c2ecf20Sopenharmony_ci		    SII9234_MHL_VERSION);
3578c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_CAT,
3588c2ecf20Sopenharmony_ci		    MHL_DCAP_CAT_SOURCE);
3598c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_H, 0x01);
3608c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_L, 0x41);
3618c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VID_LINK_MODE,
3628c2ecf20Sopenharmony_ci		    MHL_DCAP_VID_LINK_RGB444 | MHL_DCAP_VID_LINK_YCBCR444);
3638c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VIDEO_TYPE,
3648c2ecf20Sopenharmony_ci		    MHL_DCAP_VT_GRAPHICS);
3658c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_LOG_DEV_MAP,
3668c2ecf20Sopenharmony_ci		    MHL_DCAP_LD_GUI);
3678c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_BANDWIDTH, 0x0F);
3688c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_FEATURE_FLAG,
3698c2ecf20Sopenharmony_ci		    MHL_DCAP_FEATURE_RCP_SUPPORT | MHL_DCAP_FEATURE_RAP_SUPPORT
3708c2ecf20Sopenharmony_ci			| MHL_DCAP_FEATURE_SP_SUPPORT);
3718c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_H, 0x0);
3728c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_L, 0x0);
3738c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_SCRATCHPAD_SIZE,
3748c2ecf20Sopenharmony_ci		    SII9234_SCRATCHPAD_SIZE);
3758c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_INT_STAT_SIZE,
3768c2ecf20Sopenharmony_ci		    SII9234_INT_STAT_SIZE);
3778c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_RESERVED, 0);
3788c2ecf20Sopenharmony_ci	cbus_writebm(ctx, 0x31, 0x0C, 0x0C);
3798c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x30, 0x01);
3808c2ecf20Sopenharmony_ci	cbus_writebm(ctx, 0x3C, 0x30, 0x38);
3818c2ecf20Sopenharmony_ci	cbus_writebm(ctx, 0x22, 0x0D, 0x0F);
3828c2ecf20Sopenharmony_ci	cbus_writebm(ctx, 0x2E, 0x15, 0x15);
3838c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_INTR1_ENABLE_REG, 0);
3848c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_INTR2_ENABLE_REG, 0);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return sii9234_clear_error(ctx);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic void force_usb_id_switch_open(struct sii9234 *ctx)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	/* Disable CBUS discovery */
3928c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0, 0x01);
3938c2ecf20Sopenharmony_ci	/* Force USB ID switch to open */
3948c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
3958c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
3968c2ecf20Sopenharmony_ci	/* Force upstream HPD to 0 when not in MHL mode. */
3978c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x30);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic void release_usb_id_switch_open(struct sii9234 *ctx)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	msleep(T_SRC_CBUS_FLOAT);
4038c2ecf20Sopenharmony_ci	/* Clear USB ID switch to open */
4048c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0, USB_ID_OVR);
4058c2ecf20Sopenharmony_ci	/* Enable CBUS discovery */
4068c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 0x01);
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int sii9234_power_init(struct sii9234 *ctx)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	/* Force the SiI9234 into the D0 state. */
4128c2ecf20Sopenharmony_ci	tpi_writeb(ctx, TPI_DPD_REG, 0x3F);
4138c2ecf20Sopenharmony_ci	/* Enable TxPLL Clock */
4148c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_TMDS_CLK_EN_REG, 0x01);
4158c2ecf20Sopenharmony_ci	/* Enable Tx Clock Path & Equalizer */
4168c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_TMDS_CH_EN_REG, 0x15);
4178c2ecf20Sopenharmony_ci	/* Power Up TMDS */
4188c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, 0x08, 0x35);
4198c2ecf20Sopenharmony_ci	return sii9234_clear_error(ctx);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int sii9234_hdmi_init(struct sii9234 *ctx)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
4258c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_PLL_CALREFSEL_REG, 0x03);
4268c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_PLL_VCOCAL_REG, 0x20);
4278c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_EQ_DATA0_REG, 0x8A);
4288c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_EQ_DATA1_REG, 0x6A);
4298c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_EQ_DATA2_REG, 0xAA);
4308c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_EQ_DATA3_REG, 0xCA);
4318c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_EQ_DATA4_REG, 0xEA);
4328c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_TMDS_ZONE_CTRL_REG, 0xA0);
4338c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_TMDS_MODE_CTRL_REG, 0x00);
4348c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_TMDS_CCTRL, 0x34);
4358c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, 0x45, 0x44);
4368c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, 0x31, 0x0A);
4378c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return sii9234_clear_error(ctx);
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int sii9234_mhl_tx_ctl_int(struct sii9234 *ctx)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0xD0);
4458c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL2_REG, 0xFC);
4468c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL4_REG, 0xEB);
4478c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL7_REG, 0x0C);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return sii9234_clear_error(ctx);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic int sii9234_reset(struct sii9234 *ctx)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	int ret;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	sii9234_clear_error(ctx);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	ret = sii9234_power_init(ctx);
4598c2ecf20Sopenharmony_ci	if (ret < 0)
4608c2ecf20Sopenharmony_ci		return ret;
4618c2ecf20Sopenharmony_ci	ret = sii9234_cbus_reset(ctx);
4628c2ecf20Sopenharmony_ci	if (ret < 0)
4638c2ecf20Sopenharmony_ci		return ret;
4648c2ecf20Sopenharmony_ci	ret = sii9234_hdmi_init(ctx);
4658c2ecf20Sopenharmony_ci	if (ret < 0)
4668c2ecf20Sopenharmony_ci		return ret;
4678c2ecf20Sopenharmony_ci	ret = sii9234_mhl_tx_ctl_int(ctx);
4688c2ecf20Sopenharmony_ci	if (ret < 0)
4698c2ecf20Sopenharmony_ci		return ret;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* Enable HDCP Compliance safety */
4728c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, 0x2B, 0x01);
4738c2ecf20Sopenharmony_ci	/* CBUS discovery cycle time for each drive and float = 150us */
4748c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0x04, 0x06);
4758c2ecf20Sopenharmony_ci	/* Clear bit 6 (reg_skip_rgnd) */
4768c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL2_REG, (1 << 7) /* Reserved */
4778c2ecf20Sopenharmony_ci		      | 2 << ATT_THRESH_SHIFT | DEGLITCH_TIME_50MS);
4788c2ecf20Sopenharmony_ci	/*
4798c2ecf20Sopenharmony_ci	 * Changed from 66 to 65 for 94[1:0] = 01 = 5k reg_cbusmhl_pup_sel
4808c2ecf20Sopenharmony_ci	 * 1.8V CBUS VTH & GND threshold
4818c2ecf20Sopenharmony_ci	 * to meet CTS 3.3.7.2 spec
4828c2ecf20Sopenharmony_ci	 */
4838c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
4848c2ecf20Sopenharmony_ci	cbus_writebm(ctx, CBUS_LINK_CONTROL_2_REG, ~0, MHL_INIT_TIMEOUT);
4858c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL6_REG, 0xA0);
4868c2ecf20Sopenharmony_ci	/* RGND & single discovery attempt (RGND blocking) */
4878c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL6_REG, BLOCK_RGND_INT |
4888c2ecf20Sopenharmony_ci		      DVRFLT_SEL | SINGLE_ATT);
4898c2ecf20Sopenharmony_ci	/* Use VBUS path of discovery state machine */
4908c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL8_REG, 0);
4918c2ecf20Sopenharmony_ci	/* 0x92[3] sets the CBUS / ID switch */
4928c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
4938c2ecf20Sopenharmony_ci	/*
4948c2ecf20Sopenharmony_ci	 * To allow RGND engine to operate correctly.
4958c2ecf20Sopenharmony_ci	 * When moving the chip from D2 to D0 (power up, init regs)
4968c2ecf20Sopenharmony_ci	 * the values should be
4978c2ecf20Sopenharmony_ci	 * 94[1:0] = 01  reg_cbusmhl_pup_sel[1:0] should be set for 5k
4988c2ecf20Sopenharmony_ci	 * 93[7:6] = 10  reg_cbusdisc_pup_sel[1:0] should be
4998c2ecf20Sopenharmony_ci	 * set for 10k (default)
5008c2ecf20Sopenharmony_ci	 * 93[5:4] = 00  reg_cbusidle_pup_sel[1:0] = open (default)
5018c2ecf20Sopenharmony_ci	 */
5028c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
5038c2ecf20Sopenharmony_ci	/*
5048c2ecf20Sopenharmony_ci	 * Change from CC to 8C to match 5K
5058c2ecf20Sopenharmony_ci	 * to meet CTS 3.3.72 spec
5068c2ecf20Sopenharmony_ci	 */
5078c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
5088c2ecf20Sopenharmony_ci	/* Configure the interrupt as active high */
5098c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x06);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	msleep(25);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/* Release usb_id switch */
5148c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0,  USB_ID_OVR);
5158c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL1_REG, 0x27);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	ret = sii9234_clear_error(ctx);
5188c2ecf20Sopenharmony_ci	if (ret < 0)
5198c2ecf20Sopenharmony_ci		return ret;
5208c2ecf20Sopenharmony_ci	ret = sii9234_cbus_init(ctx);
5218c2ecf20Sopenharmony_ci	if (ret < 0)
5228c2ecf20Sopenharmony_ci		return ret;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	/* Enable Auto soft reset on SCDT = 0 */
5258c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, 0x05, 0x04);
5268c2ecf20Sopenharmony_ci	/* HDMI Transcode mode enable */
5278c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, 0x0D, 0x1C);
5288c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_INTR4_ENABLE_REG,
5298c2ecf20Sopenharmony_ci		      RGND_READY_MASK | CBUS_LKOUT_MASK
5308c2ecf20Sopenharmony_ci			| MHL_DISC_FAIL_MASK | MHL_EST_MASK);
5318c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG, 0x60);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	/* This point is very important before measure RGND impedance */
5348c2ecf20Sopenharmony_ci	force_usb_id_switch_open(ctx);
5358c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, 0, 0xF0);
5368c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL5_REG, 0, 0x03);
5378c2ecf20Sopenharmony_ci	release_usb_id_switch_open(ctx);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	/* Force upstream HPD to 0 when not in MHL mode */
5408c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 1 << 5);
5418c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, ~0, 1 << 4);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	return sii9234_clear_error(ctx);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic int sii9234_goto_d3(struct sii9234 *ctx)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	int ret;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "sii9234: detection started d3\n");
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	ret = sii9234_reset(ctx);
5538c2ecf20Sopenharmony_ci	if (ret < 0)
5548c2ecf20Sopenharmony_ci		goto exit;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	hdmi_writeb(ctx, 0x01, 0x03);
5578c2ecf20Sopenharmony_ci	tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
5588c2ecf20Sopenharmony_ci	/* I2C above is expected to fail because power goes down */
5598c2ecf20Sopenharmony_ci	sii9234_clear_error(ctx);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	ctx->state = ST_D3;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	return 0;
5648c2ecf20Sopenharmony_ci exit:
5658c2ecf20Sopenharmony_ci	dev_err(ctx->dev, "%s failed\n", __func__);
5668c2ecf20Sopenharmony_ci	return -1;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic int sii9234_hw_on(struct sii9234 *ctx)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic void sii9234_hw_off(struct sii9234 *ctx)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	gpiod_set_value(ctx->gpio_reset, 1);
5778c2ecf20Sopenharmony_ci	msleep(20);
5788c2ecf20Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic void sii9234_hw_reset(struct sii9234 *ctx)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	gpiod_set_value(ctx->gpio_reset, 1);
5848c2ecf20Sopenharmony_ci	msleep(20);
5858c2ecf20Sopenharmony_ci	gpiod_set_value(ctx->gpio_reset, 0);
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic void sii9234_cable_in(struct sii9234 *ctx)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	int ret;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	mutex_lock(&ctx->lock);
5938c2ecf20Sopenharmony_ci	if (ctx->state != ST_OFF)
5948c2ecf20Sopenharmony_ci		goto unlock;
5958c2ecf20Sopenharmony_ci	ret = sii9234_hw_on(ctx);
5968c2ecf20Sopenharmony_ci	if (ret < 0)
5978c2ecf20Sopenharmony_ci		goto unlock;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	sii9234_hw_reset(ctx);
6008c2ecf20Sopenharmony_ci	sii9234_goto_d3(ctx);
6018c2ecf20Sopenharmony_ci	/* To avoid irq storm, when hw is in meta state */
6028c2ecf20Sopenharmony_ci	enable_irq(to_i2c_client(ctx->dev)->irq);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ciunlock:
6058c2ecf20Sopenharmony_ci	mutex_unlock(&ctx->lock);
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic void sii9234_cable_out(struct sii9234 *ctx)
6098c2ecf20Sopenharmony_ci{
6108c2ecf20Sopenharmony_ci	mutex_lock(&ctx->lock);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (ctx->state == ST_OFF)
6138c2ecf20Sopenharmony_ci		goto unlock;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	disable_irq(to_i2c_client(ctx->dev)->irq);
6168c2ecf20Sopenharmony_ci	tpi_writeb(ctx, TPI_DPD_REG, 0);
6178c2ecf20Sopenharmony_ci	/* Turn on&off hpd festure for only QCT HDMI */
6188c2ecf20Sopenharmony_ci	sii9234_hw_off(ctx);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	ctx->state = ST_OFF;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ciunlock:
6238c2ecf20Sopenharmony_ci	mutex_unlock(&ctx->lock);
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cistatic enum sii9234_state sii9234_rgnd_ready_irq(struct sii9234 *ctx)
6278c2ecf20Sopenharmony_ci{
6288c2ecf20Sopenharmony_ci	int value;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	if (ctx->state == ST_D3) {
6318c2ecf20Sopenharmony_ci		int ret;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		dev_dbg(ctx->dev, "RGND_READY_INT\n");
6348c2ecf20Sopenharmony_ci		sii9234_hw_reset(ctx);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci		ret = sii9234_reset(ctx);
6378c2ecf20Sopenharmony_ci		if (ret < 0) {
6388c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "sii9234_reset() failed\n");
6398c2ecf20Sopenharmony_ci			return ST_FAILURE;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		return ST_RGND_INIT;
6438c2ecf20Sopenharmony_ci	}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	/* Got interrupt in inappropriate state */
6468c2ecf20Sopenharmony_ci	if (ctx->state != ST_RGND_INIT)
6478c2ecf20Sopenharmony_ci		return ST_FAILURE;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	value = mhl_tx_readb(ctx, MHL_TX_STAT2_REG);
6508c2ecf20Sopenharmony_ci	if (sii9234_clear_error(ctx))
6518c2ecf20Sopenharmony_ci		return ST_FAILURE;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if ((value & RGND_INTP_MASK) != RGND_INTP_1K) {
6548c2ecf20Sopenharmony_ci		dev_warn(ctx->dev, "RGND is not 1k\n");
6558c2ecf20Sopenharmony_ci		return ST_RGND_INIT;
6568c2ecf20Sopenharmony_ci	}
6578c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "RGND 1K!!\n");
6588c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
6598c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
6608c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, 0x05);
6618c2ecf20Sopenharmony_ci	if (sii9234_clear_error(ctx))
6628c2ecf20Sopenharmony_ci		return ST_FAILURE;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	msleep(T_SRC_VBUS_CBUS_TO_STABLE);
6658c2ecf20Sopenharmony_ci	return ST_RGND_1K;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic enum sii9234_state sii9234_mhl_established(struct sii9234 *ctx)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "mhl est interrupt\n");
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/* Discovery override */
6738c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0x10);
6748c2ecf20Sopenharmony_ci	/* Increase DDC translation layer timer (byte mode) */
6758c2ecf20Sopenharmony_ci	cbus_writeb(ctx, 0x07, 0x32);
6768c2ecf20Sopenharmony_ci	cbus_writebm(ctx, 0x44, ~0, 1 << 1);
6778c2ecf20Sopenharmony_ci	/* Keep the discovery enabled. Need RGND interrupt */
6788c2ecf20Sopenharmony_ci	mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 1);
6798c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG,
6808c2ecf20Sopenharmony_ci		      RSEN_CHANGE_INT_MASK | HPD_CHANGE_INT_MASK);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (sii9234_clear_error(ctx))
6838c2ecf20Sopenharmony_ci		return ST_FAILURE;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	return ST_MHL_ESTABLISHED;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_cistatic enum sii9234_state sii9234_hpd_change(struct sii9234 *ctx)
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	int value;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	value = cbus_readb(ctx, CBUS_MSC_REQ_ABORT_REASON_REG);
6938c2ecf20Sopenharmony_ci	if (sii9234_clear_error(ctx))
6948c2ecf20Sopenharmony_ci		return ST_FAILURE;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (value & SET_HPD_DOWNSTREAM) {
6978c2ecf20Sopenharmony_ci		/* Downstream HPD High, Enable TMDS */
6988c2ecf20Sopenharmony_ci		sii9234_tmds_control(ctx, true);
6998c2ecf20Sopenharmony_ci	} else {
7008c2ecf20Sopenharmony_ci		/* Downstream HPD Low, Disable TMDS */
7018c2ecf20Sopenharmony_ci		sii9234_tmds_control(ctx, false);
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	return ctx->state;
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_cistatic enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	int value;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	/* Work_around code to handle wrong interrupt */
7128c2ecf20Sopenharmony_ci	if (ctx->state != ST_RGND_1K) {
7138c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n");
7148c2ecf20Sopenharmony_ci		return ST_FAILURE;
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci	value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
7178c2ecf20Sopenharmony_ci	if (value < 0)
7188c2ecf20Sopenharmony_ci		return ST_FAILURE;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (value & RSEN_STATUS) {
7218c2ecf20Sopenharmony_ci		dev_dbg(ctx->dev, "MHL cable connected.. RSEN High\n");
7228c2ecf20Sopenharmony_ci		return ST_RSEN_HIGH;
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "RSEN lost\n");
7258c2ecf20Sopenharmony_ci	/*
7268c2ecf20Sopenharmony_ci	 * Once RSEN loss is confirmed,we need to check
7278c2ecf20Sopenharmony_ci	 * based on cable status and chip power status,whether
7288c2ecf20Sopenharmony_ci	 * it is SINK Loss(HDMI cable not connected, TV Off)
7298c2ecf20Sopenharmony_ci	 * or MHL cable disconnection
7308c2ecf20Sopenharmony_ci	 * TODO: Define the below mhl_disconnection()
7318c2ecf20Sopenharmony_ci	 */
7328c2ecf20Sopenharmony_ci	msleep(T_SRC_RXSENSE_DEGLITCH);
7338c2ecf20Sopenharmony_ci	value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
7348c2ecf20Sopenharmony_ci	if (value < 0)
7358c2ecf20Sopenharmony_ci		return ST_FAILURE;
7368c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "sys_stat: %x\n", value);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	if (value & RSEN_STATUS) {
7398c2ecf20Sopenharmony_ci		dev_dbg(ctx->dev, "RSEN recovery\n");
7408c2ecf20Sopenharmony_ci		return ST_RSEN_HIGH;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "RSEN Really LOW\n");
7438c2ecf20Sopenharmony_ci	/* To meet CTS 3.3.22.2 spec */
7448c2ecf20Sopenharmony_ci	sii9234_tmds_control(ctx, false);
7458c2ecf20Sopenharmony_ci	force_usb_id_switch_open(ctx);
7468c2ecf20Sopenharmony_ci	release_usb_id_switch_open(ctx);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	return ST_FAILURE;
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic irqreturn_t sii9234_irq_thread(int irq, void *data)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	struct sii9234 *ctx = data;
7548c2ecf20Sopenharmony_ci	int intr1, intr4;
7558c2ecf20Sopenharmony_ci	int intr1_en, intr4_en;
7568c2ecf20Sopenharmony_ci	int cbus_intr1, cbus_intr2;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "%s\n", __func__);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	mutex_lock(&ctx->lock);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	intr1 = mhl_tx_readb(ctx, MHL_TX_INTR1_REG);
7638c2ecf20Sopenharmony_ci	intr4 = mhl_tx_readb(ctx, MHL_TX_INTR4_REG);
7648c2ecf20Sopenharmony_ci	intr1_en = mhl_tx_readb(ctx, MHL_TX_INTR1_ENABLE_REG);
7658c2ecf20Sopenharmony_ci	intr4_en = mhl_tx_readb(ctx, MHL_TX_INTR4_ENABLE_REG);
7668c2ecf20Sopenharmony_ci	cbus_intr1 = cbus_readb(ctx, CBUS_INT_STATUS_1_REG);
7678c2ecf20Sopenharmony_ci	cbus_intr2 = cbus_readb(ctx, CBUS_INT_STATUS_2_REG);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	if (sii9234_clear_error(ctx))
7708c2ecf20Sopenharmony_ci		goto done;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "irq %02x/%02x %02x/%02x %02x/%02x\n",
7738c2ecf20Sopenharmony_ci		intr1, intr1_en, intr4, intr4_en, cbus_intr1, cbus_intr2);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (intr4 & RGND_READY_INT)
7768c2ecf20Sopenharmony_ci		ctx->state = sii9234_rgnd_ready_irq(ctx);
7778c2ecf20Sopenharmony_ci	if (intr1 & RSEN_CHANGE_INT)
7788c2ecf20Sopenharmony_ci		ctx->state = sii9234_rsen_change(ctx);
7798c2ecf20Sopenharmony_ci	if (intr4 & MHL_EST_INT)
7808c2ecf20Sopenharmony_ci		ctx->state = sii9234_mhl_established(ctx);
7818c2ecf20Sopenharmony_ci	if (intr1 & HPD_CHANGE_INT)
7828c2ecf20Sopenharmony_ci		ctx->state = sii9234_hpd_change(ctx);
7838c2ecf20Sopenharmony_ci	if (intr4 & CBUS_LKOUT_INT)
7848c2ecf20Sopenharmony_ci		ctx->state = ST_FAILURE;
7858c2ecf20Sopenharmony_ci	if (intr4 & MHL_DISC_FAIL_INT)
7868c2ecf20Sopenharmony_ci		ctx->state = ST_FAILURE_DISCOVERY;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci done:
7898c2ecf20Sopenharmony_ci	/* Clean interrupt status and pending flags */
7908c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_INTR1_REG, intr1);
7918c2ecf20Sopenharmony_ci	mhl_tx_writeb(ctx, MHL_TX_INTR4_REG, intr4);
7928c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_MHL_STATUS_REG_0, 0xFF);
7938c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_MHL_STATUS_REG_1, 0xFF);
7948c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_INT_STATUS_1_REG, cbus_intr1);
7958c2ecf20Sopenharmony_ci	cbus_writeb(ctx, CBUS_INT_STATUS_2_REG, cbus_intr2);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	sii9234_clear_error(ctx);
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (ctx->state == ST_FAILURE) {
8008c2ecf20Sopenharmony_ci		dev_dbg(ctx->dev, "try to reset after failure\n");
8018c2ecf20Sopenharmony_ci		sii9234_hw_reset(ctx);
8028c2ecf20Sopenharmony_ci		sii9234_goto_d3(ctx);
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (ctx->state == ST_FAILURE_DISCOVERY) {
8068c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "discovery failed, no power for MHL?\n");
8078c2ecf20Sopenharmony_ci		tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
8088c2ecf20Sopenharmony_ci		ctx->state = ST_D3;
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	mutex_unlock(&ctx->lock);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic int sii9234_init_resources(struct sii9234 *ctx,
8178c2ecf20Sopenharmony_ci				  struct i2c_client *client)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
8208c2ecf20Sopenharmony_ci	int ret;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (!ctx->dev->of_node) {
8238c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "not DT device\n");
8248c2ecf20Sopenharmony_ci		return -ENODEV;
8258c2ecf20Sopenharmony_ci	}
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW);
8288c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->gpio_reset)) {
8298c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to get reset gpio from DT\n");
8308c2ecf20Sopenharmony_ci		return PTR_ERR(ctx->gpio_reset);
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	ctx->supplies[0].supply = "avcc12";
8348c2ecf20Sopenharmony_ci	ctx->supplies[1].supply = "avcc33";
8358c2ecf20Sopenharmony_ci	ctx->supplies[2].supply = "iovcc18";
8368c2ecf20Sopenharmony_ci	ctx->supplies[3].supply = "cvcc12";
8378c2ecf20Sopenharmony_ci	ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies);
8388c2ecf20Sopenharmony_ci	if (ret) {
8398c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
8408c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "regulator_bulk failed\n");
8418c2ecf20Sopenharmony_ci		return ret;
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	ctx->client[I2C_MHL] = client;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	ctx->client[I2C_TPI] = devm_i2c_new_dummy_device(&client->dev, adapter,
8478c2ecf20Sopenharmony_ci							 I2C_TPI_ADDR);
8488c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->client[I2C_TPI])) {
8498c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to create TPI client\n");
8508c2ecf20Sopenharmony_ci		return PTR_ERR(ctx->client[I2C_TPI]);
8518c2ecf20Sopenharmony_ci	}
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	ctx->client[I2C_HDMI] = devm_i2c_new_dummy_device(&client->dev, adapter,
8548c2ecf20Sopenharmony_ci							  I2C_HDMI_ADDR);
8558c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->client[I2C_HDMI])) {
8568c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to create HDMI RX client\n");
8578c2ecf20Sopenharmony_ci		return PTR_ERR(ctx->client[I2C_HDMI]);
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	ctx->client[I2C_CBUS] = devm_i2c_new_dummy_device(&client->dev, adapter,
8618c2ecf20Sopenharmony_ci							  I2C_CBUS_ADDR);
8628c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->client[I2C_CBUS])) {
8638c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to create CBUS client\n");
8648c2ecf20Sopenharmony_ci		return PTR_ERR(ctx->client[I2C_CBUS]);
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	return 0;
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_cistatic inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	return container_of(bridge, struct sii9234, bridge);
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge,
8768c2ecf20Sopenharmony_ci					 const struct drm_display_info *info,
8778c2ecf20Sopenharmony_ci					 const struct drm_display_mode *mode)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	if (mode->clock > MHL1_MAX_CLK)
8808c2ecf20Sopenharmony_ci		return MODE_CLOCK_HIGH;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	return MODE_OK;
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic const struct drm_bridge_funcs sii9234_bridge_funcs = {
8868c2ecf20Sopenharmony_ci	.mode_valid = sii9234_mode_valid,
8878c2ecf20Sopenharmony_ci};
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_cistatic int sii9234_probe(struct i2c_client *client,
8908c2ecf20Sopenharmony_ci			 const struct i2c_device_id *id)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
8938c2ecf20Sopenharmony_ci	struct sii9234 *ctx;
8948c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
8958c2ecf20Sopenharmony_ci	int ret;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
8988c2ecf20Sopenharmony_ci	if (!ctx)
8998c2ecf20Sopenharmony_ci		return -ENOMEM;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	ctx->dev = dev;
9028c2ecf20Sopenharmony_ci	mutex_init(&ctx->lock);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
9058c2ecf20Sopenharmony_ci		dev_err(dev, "I2C adapter lacks SMBUS feature\n");
9068c2ecf20Sopenharmony_ci		return -EIO;
9078c2ecf20Sopenharmony_ci	}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	if (!client->irq) {
9108c2ecf20Sopenharmony_ci		dev_err(dev, "no irq provided\n");
9118c2ecf20Sopenharmony_ci		return -EINVAL;
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
9158c2ecf20Sopenharmony_ci	ret = devm_request_threaded_irq(dev, client->irq, NULL,
9168c2ecf20Sopenharmony_ci					sii9234_irq_thread,
9178c2ecf20Sopenharmony_ci					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
9188c2ecf20Sopenharmony_ci					"sii9234", ctx);
9198c2ecf20Sopenharmony_ci	if (ret < 0) {
9208c2ecf20Sopenharmony_ci		dev_err(dev, "failed to install IRQ handler\n");
9218c2ecf20Sopenharmony_ci		return ret;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	ret = sii9234_init_resources(ctx, client);
9258c2ecf20Sopenharmony_ci	if (ret < 0)
9268c2ecf20Sopenharmony_ci		return ret;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, ctx);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	ctx->bridge.funcs = &sii9234_bridge_funcs;
9318c2ecf20Sopenharmony_ci	ctx->bridge.of_node = dev->of_node;
9328c2ecf20Sopenharmony_ci	drm_bridge_add(&ctx->bridge);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	sii9234_cable_in(ctx);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	return 0;
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_cistatic int sii9234_remove(struct i2c_client *client)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	struct sii9234 *ctx = i2c_get_clientdata(client);
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	sii9234_cable_out(ctx);
9448c2ecf20Sopenharmony_ci	drm_bridge_remove(&ctx->bridge);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	return 0;
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cistatic const struct of_device_id sii9234_dt_match[] = {
9508c2ecf20Sopenharmony_ci	{ .compatible = "sil,sii9234" },
9518c2ecf20Sopenharmony_ci	{ },
9528c2ecf20Sopenharmony_ci};
9538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sii9234_dt_match);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic const struct i2c_device_id sii9234_id[] = {
9568c2ecf20Sopenharmony_ci	{ "SII9234", 0 },
9578c2ecf20Sopenharmony_ci	{ },
9588c2ecf20Sopenharmony_ci};
9598c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sii9234_id);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic struct i2c_driver sii9234_driver = {
9628c2ecf20Sopenharmony_ci	.driver = {
9638c2ecf20Sopenharmony_ci		.name	= "sii9234",
9648c2ecf20Sopenharmony_ci		.of_match_table = sii9234_dt_match,
9658c2ecf20Sopenharmony_ci	},
9668c2ecf20Sopenharmony_ci	.probe = sii9234_probe,
9678c2ecf20Sopenharmony_ci	.remove = sii9234_remove,
9688c2ecf20Sopenharmony_ci	.id_table = sii9234_id,
9698c2ecf20Sopenharmony_ci};
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cimodule_i2c_driver(sii9234_driver);
9728c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
973