Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2017 Samsung Electronics
0004  *
0005  * Authors:
0006  *    Tomasz Stanislawski <t.stanislaws@samsung.com>
0007  *    Maciej Purski <m.purski@samsung.com>
0008  *
0009  * Based on sii9234 driver created by:
0010  *    Adam Hampson <ahampson@sta.samsung.com>
0011  *    Erik Gilling <konkers@android.com>
0012  *    Shankar Bandal <shankar.b@samsung.com>
0013  *    Dharam Kumar <dharam.kr@samsung.com>
0014  */
0015 #include <drm/bridge/mhl.h>
0016 #include <drm/drm_bridge.h>
0017 #include <drm/drm_crtc.h>
0018 #include <drm/drm_edid.h>
0019 
0020 #include <linux/delay.h>
0021 #include <linux/err.h>
0022 #include <linux/gpio/consumer.h>
0023 #include <linux/i2c.h>
0024 #include <linux/interrupt.h>
0025 #include <linux/irq.h>
0026 #include <linux/kernel.h>
0027 #include <linux/module.h>
0028 #include <linux/mutex.h>
0029 #include <linux/regulator/consumer.h>
0030 #include <linux/slab.h>
0031 
0032 #define CBUS_DEVCAP_OFFSET      0x80
0033 
0034 #define SII9234_MHL_VERSION     0x11
0035 #define SII9234_SCRATCHPAD_SIZE     0x10
0036 #define SII9234_INT_STAT_SIZE       0x33
0037 
0038 #define BIT_TMDS_CCTRL_TMDS_OE      BIT(4)
0039 #define MHL_HPD_OUT_OVR_EN      BIT(4)
0040 #define MHL_HPD_OUT_OVR_VAL     BIT(5)
0041 #define MHL_INIT_TIMEOUT        0x0C
0042 
0043 /* MHL Tx registers and bits */
0044 #define MHL_TX_SRST         0x05
0045 #define MHL_TX_SYSSTAT_REG      0x09
0046 #define MHL_TX_INTR1_REG        0x71
0047 #define MHL_TX_INTR4_REG        0x74
0048 #define MHL_TX_INTR1_ENABLE_REG     0x75
0049 #define MHL_TX_INTR4_ENABLE_REG     0x78
0050 #define MHL_TX_INT_CTRL_REG     0x79
0051 #define MHL_TX_TMDS_CCTRL       0x80
0052 #define MHL_TX_DISC_CTRL1_REG       0x90
0053 #define MHL_TX_DISC_CTRL2_REG       0x91
0054 #define MHL_TX_DISC_CTRL3_REG       0x92
0055 #define MHL_TX_DISC_CTRL4_REG       0x93
0056 #define MHL_TX_DISC_CTRL5_REG       0x94
0057 #define MHL_TX_DISC_CTRL6_REG       0x95
0058 #define MHL_TX_DISC_CTRL7_REG       0x96
0059 #define MHL_TX_DISC_CTRL8_REG       0x97
0060 #define MHL_TX_STAT2_REG        0x99
0061 #define MHL_TX_MHLTX_CTL1_REG       0xA0
0062 #define MHL_TX_MHLTX_CTL2_REG       0xA1
0063 #define MHL_TX_MHLTX_CTL4_REG       0xA3
0064 #define MHL_TX_MHLTX_CTL6_REG       0xA5
0065 #define MHL_TX_MHLTX_CTL7_REG       0xA6
0066 
0067 #define RSEN_STATUS         BIT(2)
0068 #define HPD_CHANGE_INT          BIT(6)
0069 #define RSEN_CHANGE_INT         BIT(5)
0070 #define RGND_READY_INT          BIT(6)
0071 #define VBUS_LOW_INT            BIT(5)
0072 #define CBUS_LKOUT_INT          BIT(4)
0073 #define MHL_DISC_FAIL_INT       BIT(3)
0074 #define MHL_EST_INT         BIT(2)
0075 #define HPD_CHANGE_INT_MASK     BIT(6)
0076 #define RSEN_CHANGE_INT_MASK        BIT(5)
0077 
0078 #define RGND_READY_MASK         BIT(6)
0079 #define CBUS_LKOUT_MASK         BIT(4)
0080 #define MHL_DISC_FAIL_MASK      BIT(3)
0081 #define MHL_EST_MASK            BIT(2)
0082 
0083 #define SKIP_GND            BIT(6)
0084 
0085 #define ATT_THRESH_SHIFT        0x04
0086 #define ATT_THRESH_MASK         (0x03 << ATT_THRESH_SHIFT)
0087 #define USB_D_OEN           BIT(3)
0088 #define DEGLITCH_TIME_MASK      0x07
0089 #define DEGLITCH_TIME_2MS       0
0090 #define DEGLITCH_TIME_4MS       1
0091 #define DEGLITCH_TIME_8MS       2
0092 #define DEGLITCH_TIME_16MS      3
0093 #define DEGLITCH_TIME_40MS      4
0094 #define DEGLITCH_TIME_50MS      5
0095 #define DEGLITCH_TIME_60MS      6
0096 #define DEGLITCH_TIME_128MS     7
0097 
0098 #define USB_D_OVR           BIT(7)
0099 #define USB_ID_OVR          BIT(6)
0100 #define DVRFLT_SEL          BIT(5)
0101 #define BLOCK_RGND_INT          BIT(4)
0102 #define SKIP_DEG            BIT(3)
0103 #define CI2CA_POL           BIT(2)
0104 #define CI2CA_WKUP          BIT(1)
0105 #define SINGLE_ATT          BIT(0)
0106 
0107 #define USB_D_ODN           BIT(5)
0108 #define VBUS_CHECK          BIT(2)
0109 #define RGND_INTP_MASK          0x03
0110 #define RGND_INTP_OPEN          0
0111 #define RGND_INTP_2K            1
0112 #define RGND_INTP_1K            2
0113 #define RGND_INTP_SHORT         3
0114 
0115 /* HDMI registers */
0116 #define HDMI_RX_TMDS0_CCTRL1_REG    0x10
0117 #define HDMI_RX_TMDS_CLK_EN_REG     0x11
0118 #define HDMI_RX_TMDS_CH_EN_REG      0x12
0119 #define HDMI_RX_PLL_CALREFSEL_REG   0x17
0120 #define HDMI_RX_PLL_VCOCAL_REG      0x1A
0121 #define HDMI_RX_EQ_DATA0_REG        0x22
0122 #define HDMI_RX_EQ_DATA1_REG        0x23
0123 #define HDMI_RX_EQ_DATA2_REG        0x24
0124 #define HDMI_RX_EQ_DATA3_REG        0x25
0125 #define HDMI_RX_EQ_DATA4_REG        0x26
0126 #define HDMI_RX_TMDS_ZONE_CTRL_REG  0x4C
0127 #define HDMI_RX_TMDS_MODE_CTRL_REG  0x4D
0128 
0129 /* CBUS registers */
0130 #define CBUS_INT_STATUS_1_REG       0x08
0131 #define CBUS_INTR1_ENABLE_REG       0x09
0132 #define CBUS_MSC_REQ_ABORT_REASON_REG   0x0D
0133 #define CBUS_INT_STATUS_2_REG       0x1E
0134 #define CBUS_INTR2_ENABLE_REG       0x1F
0135 #define CBUS_LINK_CONTROL_2_REG     0x31
0136 #define CBUS_MHL_STATUS_REG_0       0xB0
0137 #define CBUS_MHL_STATUS_REG_1       0xB1
0138 
0139 #define BIT_CBUS_RESET          BIT(3)
0140 #define SET_HPD_DOWNSTREAM      BIT(6)
0141 
0142 /* TPI registers */
0143 #define TPI_DPD_REG         0x3D
0144 
0145 /* Timeouts in msec */
0146 #define T_SRC_VBUS_CBUS_TO_STABLE   200
0147 #define T_SRC_CBUS_FLOAT        100
0148 #define T_SRC_CBUS_DEGLITCH     2
0149 #define T_SRC_RXSENSE_DEGLITCH      110
0150 
0151 #define MHL1_MAX_CLK            75000 /* in kHz */
0152 
0153 #define I2C_TPI_ADDR            0x3D
0154 #define I2C_HDMI_ADDR           0x49
0155 #define I2C_CBUS_ADDR           0x64
0156 
0157 enum sii9234_state {
0158     ST_OFF,
0159     ST_D3,
0160     ST_RGND_INIT,
0161     ST_RGND_1K,
0162     ST_RSEN_HIGH,
0163     ST_MHL_ESTABLISHED,
0164     ST_FAILURE_DISCOVERY,
0165     ST_FAILURE,
0166 };
0167 
0168 struct sii9234 {
0169     struct i2c_client *client[4];
0170     struct drm_bridge bridge;
0171     struct device *dev;
0172     struct gpio_desc *gpio_reset;
0173     int i2c_error;
0174     struct regulator_bulk_data supplies[4];
0175 
0176     struct mutex lock; /* Protects fields below and device registers */
0177     enum sii9234_state state;
0178 };
0179 
0180 enum sii9234_client_id {
0181     I2C_MHL,
0182     I2C_TPI,
0183     I2C_HDMI,
0184     I2C_CBUS,
0185 };
0186 
0187 static const char * const sii9234_client_name[] = {
0188     [I2C_MHL] = "MHL",
0189     [I2C_TPI] = "TPI",
0190     [I2C_HDMI] = "HDMI",
0191     [I2C_CBUS] = "CBUS",
0192 };
0193 
0194 static int sii9234_writeb(struct sii9234 *ctx, int id, int offset,
0195               int value)
0196 {
0197     int ret;
0198     struct i2c_client *client = ctx->client[id];
0199 
0200     if (ctx->i2c_error)
0201         return ctx->i2c_error;
0202 
0203     ret = i2c_smbus_write_byte_data(client, offset, value);
0204     if (ret < 0)
0205         dev_err(ctx->dev, "writeb: %4s[0x%02x] <- 0x%02x\n",
0206             sii9234_client_name[id], offset, value);
0207     ctx->i2c_error = ret;
0208 
0209     return ret;
0210 }
0211 
0212 static int sii9234_writebm(struct sii9234 *ctx, int id, int offset,
0213                int value, int mask)
0214 {
0215     int ret;
0216     struct i2c_client *client = ctx->client[id];
0217 
0218     if (ctx->i2c_error)
0219         return ctx->i2c_error;
0220 
0221     ret = i2c_smbus_write_byte(client, offset);
0222     if (ret < 0) {
0223         dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
0224             sii9234_client_name[id], offset, value);
0225         ctx->i2c_error = ret;
0226         return ret;
0227     }
0228 
0229     ret = i2c_smbus_read_byte(client);
0230     if (ret < 0) {
0231         dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
0232             sii9234_client_name[id], offset, value);
0233         ctx->i2c_error = ret;
0234         return ret;
0235     }
0236 
0237     value = (value & mask) | (ret & ~mask);
0238 
0239     ret = i2c_smbus_write_byte_data(client, offset, value);
0240     if (ret < 0) {
0241         dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
0242             sii9234_client_name[id], offset, value);
0243         ctx->i2c_error = ret;
0244     }
0245 
0246     return ret;
0247 }
0248 
0249 static int sii9234_readb(struct sii9234 *ctx, int id, int offset)
0250 {
0251     int ret;
0252     struct i2c_client *client = ctx->client[id];
0253 
0254     if (ctx->i2c_error)
0255         return ctx->i2c_error;
0256 
0257     ret = i2c_smbus_write_byte(client, offset);
0258     if (ret < 0) {
0259         dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
0260             sii9234_client_name[id], offset);
0261         ctx->i2c_error = ret;
0262         return ret;
0263     }
0264 
0265     ret = i2c_smbus_read_byte(client);
0266     if (ret < 0) {
0267         dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
0268             sii9234_client_name[id], offset);
0269         ctx->i2c_error = ret;
0270     }
0271 
0272     return ret;
0273 }
0274 
0275 static int sii9234_clear_error(struct sii9234 *ctx)
0276 {
0277     int ret = ctx->i2c_error;
0278 
0279     ctx->i2c_error = 0;
0280 
0281     return ret;
0282 }
0283 
0284 #define mhl_tx_writeb(sii9234, offset, value) \
0285     sii9234_writeb(sii9234, I2C_MHL, offset, value)
0286 #define mhl_tx_writebm(sii9234, offset, value, mask) \
0287     sii9234_writebm(sii9234, I2C_MHL, offset, value, mask)
0288 #define mhl_tx_readb(sii9234, offset) \
0289     sii9234_readb(sii9234, I2C_MHL, offset)
0290 #define cbus_writeb(sii9234, offset, value) \
0291     sii9234_writeb(sii9234, I2C_CBUS, offset, value)
0292 #define cbus_writebm(sii9234, offset, value, mask) \
0293     sii9234_writebm(sii9234, I2C_CBUS, offset, value, mask)
0294 #define cbus_readb(sii9234, offset) \
0295     sii9234_readb(sii9234, I2C_CBUS, offset)
0296 #define hdmi_writeb(sii9234, offset, value) \
0297     sii9234_writeb(sii9234, I2C_HDMI, offset, value)
0298 #define hdmi_writebm(sii9234, offset, value, mask) \
0299     sii9234_writebm(sii9234, I2C_HDMI, offset, value, mask)
0300 #define hdmi_readb(sii9234, offset) \
0301     sii9234_readb(sii9234, I2C_HDMI, offset)
0302 #define tpi_writeb(sii9234, offset, value) \
0303     sii9234_writeb(sii9234, I2C_TPI, offset, value)
0304 #define tpi_writebm(sii9234, offset, value, mask) \
0305     sii9234_writebm(sii9234, I2C_TPI, offset, value, mask)
0306 #define tpi_readb(sii9234, offset) \
0307     sii9234_readb(sii9234, I2C_TPI, offset)
0308 
0309 static u8 sii9234_tmds_control(struct sii9234 *ctx, bool enable)
0310 {
0311     mhl_tx_writebm(ctx, MHL_TX_TMDS_CCTRL, enable ? ~0 : 0,
0312                BIT_TMDS_CCTRL_TMDS_OE);
0313     mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, enable ? ~0 : 0,
0314                MHL_HPD_OUT_OVR_EN | MHL_HPD_OUT_OVR_VAL);
0315     return sii9234_clear_error(ctx);
0316 }
0317 
0318 static int sii9234_cbus_reset(struct sii9234 *ctx)
0319 {
0320     int i;
0321 
0322     mhl_tx_writebm(ctx, MHL_TX_SRST, ~0, BIT_CBUS_RESET);
0323     msleep(T_SRC_CBUS_DEGLITCH);
0324     mhl_tx_writebm(ctx, MHL_TX_SRST, 0, BIT_CBUS_RESET);
0325 
0326     for (i = 0; i < 4; i++) {
0327         /*
0328          * Enable WRITE_STAT interrupt for writes to all
0329          * 4 MSC Status registers.
0330          */
0331         cbus_writeb(ctx, 0xE0 + i, 0xF2);
0332         /*
0333          * Enable SET_INT interrupt for writes to all
0334          * 4 MSC Interrupt registers.
0335          */
0336         cbus_writeb(ctx, 0xF0 + i, 0xF2);
0337     }
0338 
0339     return sii9234_clear_error(ctx);
0340 }
0341 
0342 /* Require to chek mhl imformation of samsung in cbus_init_register */
0343 static int sii9234_cbus_init(struct sii9234 *ctx)
0344 {
0345     cbus_writeb(ctx, 0x07, 0xF2);
0346     cbus_writeb(ctx, 0x40, 0x03);
0347     cbus_writeb(ctx, 0x42, 0x06);
0348     cbus_writeb(ctx, 0x36, 0x0C);
0349     cbus_writeb(ctx, 0x3D, 0xFD);
0350     cbus_writeb(ctx, 0x1C, 0x01);
0351     cbus_writeb(ctx, 0x1D, 0x0F);
0352     cbus_writeb(ctx, 0x44, 0x02);
0353     /* Setup our devcap */
0354     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEV_STATE, 0x00);
0355     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_MHL_VERSION,
0356             SII9234_MHL_VERSION);
0357     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_CAT,
0358             MHL_DCAP_CAT_SOURCE);
0359     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_H, 0x01);
0360     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_L, 0x41);
0361     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VID_LINK_MODE,
0362             MHL_DCAP_VID_LINK_RGB444 | MHL_DCAP_VID_LINK_YCBCR444);
0363     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VIDEO_TYPE,
0364             MHL_DCAP_VT_GRAPHICS);
0365     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_LOG_DEV_MAP,
0366             MHL_DCAP_LD_GUI);
0367     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_BANDWIDTH, 0x0F);
0368     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_FEATURE_FLAG,
0369             MHL_DCAP_FEATURE_RCP_SUPPORT | MHL_DCAP_FEATURE_RAP_SUPPORT
0370             | MHL_DCAP_FEATURE_SP_SUPPORT);
0371     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_H, 0x0);
0372     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_L, 0x0);
0373     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_SCRATCHPAD_SIZE,
0374             SII9234_SCRATCHPAD_SIZE);
0375     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_INT_STAT_SIZE,
0376             SII9234_INT_STAT_SIZE);
0377     cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_RESERVED, 0);
0378     cbus_writebm(ctx, 0x31, 0x0C, 0x0C);
0379     cbus_writeb(ctx, 0x30, 0x01);
0380     cbus_writebm(ctx, 0x3C, 0x30, 0x38);
0381     cbus_writebm(ctx, 0x22, 0x0D, 0x0F);
0382     cbus_writebm(ctx, 0x2E, 0x15, 0x15);
0383     cbus_writeb(ctx, CBUS_INTR1_ENABLE_REG, 0);
0384     cbus_writeb(ctx, CBUS_INTR2_ENABLE_REG, 0);
0385 
0386     return sii9234_clear_error(ctx);
0387 }
0388 
0389 static void force_usb_id_switch_open(struct sii9234 *ctx)
0390 {
0391     /* Disable CBUS discovery */
0392     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0, 0x01);
0393     /* Force USB ID switch to open */
0394     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
0395     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
0396     /* Force upstream HPD to 0 when not in MHL mode. */
0397     mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x30);
0398 }
0399 
0400 static void release_usb_id_switch_open(struct sii9234 *ctx)
0401 {
0402     msleep(T_SRC_CBUS_FLOAT);
0403     /* Clear USB ID switch to open */
0404     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0, USB_ID_OVR);
0405     /* Enable CBUS discovery */
0406     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 0x01);
0407 }
0408 
0409 static int sii9234_power_init(struct sii9234 *ctx)
0410 {
0411     /* Force the SiI9234 into the D0 state. */
0412     tpi_writeb(ctx, TPI_DPD_REG, 0x3F);
0413     /* Enable TxPLL Clock */
0414     hdmi_writeb(ctx, HDMI_RX_TMDS_CLK_EN_REG, 0x01);
0415     /* Enable Tx Clock Path & Equalizer */
0416     hdmi_writeb(ctx, HDMI_RX_TMDS_CH_EN_REG, 0x15);
0417     /* Power Up TMDS */
0418     mhl_tx_writeb(ctx, 0x08, 0x35);
0419     return sii9234_clear_error(ctx);
0420 }
0421 
0422 static int sii9234_hdmi_init(struct sii9234 *ctx)
0423 {
0424     hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
0425     hdmi_writeb(ctx, HDMI_RX_PLL_CALREFSEL_REG, 0x03);
0426     hdmi_writeb(ctx, HDMI_RX_PLL_VCOCAL_REG, 0x20);
0427     hdmi_writeb(ctx, HDMI_RX_EQ_DATA0_REG, 0x8A);
0428     hdmi_writeb(ctx, HDMI_RX_EQ_DATA1_REG, 0x6A);
0429     hdmi_writeb(ctx, HDMI_RX_EQ_DATA2_REG, 0xAA);
0430     hdmi_writeb(ctx, HDMI_RX_EQ_DATA3_REG, 0xCA);
0431     hdmi_writeb(ctx, HDMI_RX_EQ_DATA4_REG, 0xEA);
0432     hdmi_writeb(ctx, HDMI_RX_TMDS_ZONE_CTRL_REG, 0xA0);
0433     hdmi_writeb(ctx, HDMI_RX_TMDS_MODE_CTRL_REG, 0x00);
0434     mhl_tx_writeb(ctx, MHL_TX_TMDS_CCTRL, 0x34);
0435     hdmi_writeb(ctx, 0x45, 0x44);
0436     hdmi_writeb(ctx, 0x31, 0x0A);
0437     hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
0438 
0439     return sii9234_clear_error(ctx);
0440 }
0441 
0442 static int sii9234_mhl_tx_ctl_int(struct sii9234 *ctx)
0443 {
0444     mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0xD0);
0445     mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL2_REG, 0xFC);
0446     mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL4_REG, 0xEB);
0447     mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL7_REG, 0x0C);
0448 
0449     return sii9234_clear_error(ctx);
0450 }
0451 
0452 static int sii9234_reset(struct sii9234 *ctx)
0453 {
0454     int ret;
0455 
0456     sii9234_clear_error(ctx);
0457 
0458     ret = sii9234_power_init(ctx);
0459     if (ret < 0)
0460         return ret;
0461     ret = sii9234_cbus_reset(ctx);
0462     if (ret < 0)
0463         return ret;
0464     ret = sii9234_hdmi_init(ctx);
0465     if (ret < 0)
0466         return ret;
0467     ret = sii9234_mhl_tx_ctl_int(ctx);
0468     if (ret < 0)
0469         return ret;
0470 
0471     /* Enable HDCP Compliance safety */
0472     mhl_tx_writeb(ctx, 0x2B, 0x01);
0473     /* CBUS discovery cycle time for each drive and float = 150us */
0474     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0x04, 0x06);
0475     /* Clear bit 6 (reg_skip_rgnd) */
0476     mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL2_REG, (1 << 7) /* Reserved */
0477               | 2 << ATT_THRESH_SHIFT | DEGLITCH_TIME_50MS);
0478     /*
0479      * Changed from 66 to 65 for 94[1:0] = 01 = 5k reg_cbusmhl_pup_sel
0480      * 1.8V CBUS VTH & GND threshold
0481      * to meet CTS 3.3.7.2 spec
0482      */
0483     mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
0484     cbus_writebm(ctx, CBUS_LINK_CONTROL_2_REG, ~0, MHL_INIT_TIMEOUT);
0485     mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL6_REG, 0xA0);
0486     /* RGND & single discovery attempt (RGND blocking) */
0487     mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL6_REG, BLOCK_RGND_INT |
0488               DVRFLT_SEL | SINGLE_ATT);
0489     /* Use VBUS path of discovery state machine */
0490     mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL8_REG, 0);
0491     /* 0x92[3] sets the CBUS / ID switch */
0492     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
0493     /*
0494      * To allow RGND engine to operate correctly.
0495      * When moving the chip from D2 to D0 (power up, init regs)
0496      * the values should be
0497      * 94[1:0] = 01  reg_cbusmhl_pup_sel[1:0] should be set for 5k
0498      * 93[7:6] = 10  reg_cbusdisc_pup_sel[1:0] should be
0499      * set for 10k (default)
0500      * 93[5:4] = 00  reg_cbusidle_pup_sel[1:0] = open (default)
0501      */
0502     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
0503     /*
0504      * Change from CC to 8C to match 5K
0505      * to meet CTS 3.3.72 spec
0506      */
0507     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
0508     /* Configure the interrupt as active high */
0509     mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x06);
0510 
0511     msleep(25);
0512 
0513     /* Release usb_id switch */
0514     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0,  USB_ID_OVR);
0515     mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL1_REG, 0x27);
0516 
0517     ret = sii9234_clear_error(ctx);
0518     if (ret < 0)
0519         return ret;
0520     ret = sii9234_cbus_init(ctx);
0521     if (ret < 0)
0522         return ret;
0523 
0524     /* Enable Auto soft reset on SCDT = 0 */
0525     mhl_tx_writeb(ctx, 0x05, 0x04);
0526     /* HDMI Transcode mode enable */
0527     mhl_tx_writeb(ctx, 0x0D, 0x1C);
0528     mhl_tx_writeb(ctx, MHL_TX_INTR4_ENABLE_REG,
0529               RGND_READY_MASK | CBUS_LKOUT_MASK
0530             | MHL_DISC_FAIL_MASK | MHL_EST_MASK);
0531     mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG, 0x60);
0532 
0533     /* This point is very important before measure RGND impedance */
0534     force_usb_id_switch_open(ctx);
0535     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, 0, 0xF0);
0536     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL5_REG, 0, 0x03);
0537     release_usb_id_switch_open(ctx);
0538 
0539     /* Force upstream HPD to 0 when not in MHL mode */
0540     mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 1 << 5);
0541     mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, ~0, 1 << 4);
0542 
0543     return sii9234_clear_error(ctx);
0544 }
0545 
0546 static int sii9234_goto_d3(struct sii9234 *ctx)
0547 {
0548     int ret;
0549 
0550     dev_dbg(ctx->dev, "sii9234: detection started d3\n");
0551 
0552     ret = sii9234_reset(ctx);
0553     if (ret < 0)
0554         goto exit;
0555 
0556     hdmi_writeb(ctx, 0x01, 0x03);
0557     tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
0558     /* I2C above is expected to fail because power goes down */
0559     sii9234_clear_error(ctx);
0560 
0561     ctx->state = ST_D3;
0562 
0563     return 0;
0564  exit:
0565     dev_err(ctx->dev, "%s failed\n", __func__);
0566     return -1;
0567 }
0568 
0569 static int sii9234_hw_on(struct sii9234 *ctx)
0570 {
0571     return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0572 }
0573 
0574 static void sii9234_hw_off(struct sii9234 *ctx)
0575 {
0576     gpiod_set_value(ctx->gpio_reset, 1);
0577     msleep(20);
0578     regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
0579 }
0580 
0581 static void sii9234_hw_reset(struct sii9234 *ctx)
0582 {
0583     gpiod_set_value(ctx->gpio_reset, 1);
0584     msleep(20);
0585     gpiod_set_value(ctx->gpio_reset, 0);
0586 }
0587 
0588 static void sii9234_cable_in(struct sii9234 *ctx)
0589 {
0590     int ret;
0591 
0592     mutex_lock(&ctx->lock);
0593     if (ctx->state != ST_OFF)
0594         goto unlock;
0595     ret = sii9234_hw_on(ctx);
0596     if (ret < 0)
0597         goto unlock;
0598 
0599     sii9234_hw_reset(ctx);
0600     sii9234_goto_d3(ctx);
0601     /* To avoid irq storm, when hw is in meta state */
0602     enable_irq(to_i2c_client(ctx->dev)->irq);
0603 
0604 unlock:
0605     mutex_unlock(&ctx->lock);
0606 }
0607 
0608 static void sii9234_cable_out(struct sii9234 *ctx)
0609 {
0610     mutex_lock(&ctx->lock);
0611 
0612     if (ctx->state == ST_OFF)
0613         goto unlock;
0614 
0615     disable_irq(to_i2c_client(ctx->dev)->irq);
0616     tpi_writeb(ctx, TPI_DPD_REG, 0);
0617     /* Turn on&off hpd festure for only QCT HDMI */
0618     sii9234_hw_off(ctx);
0619 
0620     ctx->state = ST_OFF;
0621 
0622 unlock:
0623     mutex_unlock(&ctx->lock);
0624 }
0625 
0626 static enum sii9234_state sii9234_rgnd_ready_irq(struct sii9234 *ctx)
0627 {
0628     int value;
0629 
0630     if (ctx->state == ST_D3) {
0631         int ret;
0632 
0633         dev_dbg(ctx->dev, "RGND_READY_INT\n");
0634         sii9234_hw_reset(ctx);
0635 
0636         ret = sii9234_reset(ctx);
0637         if (ret < 0) {
0638             dev_err(ctx->dev, "sii9234_reset() failed\n");
0639             return ST_FAILURE;
0640         }
0641 
0642         return ST_RGND_INIT;
0643     }
0644 
0645     /* Got interrupt in inappropriate state */
0646     if (ctx->state != ST_RGND_INIT)
0647         return ST_FAILURE;
0648 
0649     value = mhl_tx_readb(ctx, MHL_TX_STAT2_REG);
0650     if (sii9234_clear_error(ctx))
0651         return ST_FAILURE;
0652 
0653     if ((value & RGND_INTP_MASK) != RGND_INTP_1K) {
0654         dev_warn(ctx->dev, "RGND is not 1k\n");
0655         return ST_RGND_INIT;
0656     }
0657     dev_dbg(ctx->dev, "RGND 1K!!\n");
0658     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
0659     mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
0660     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, 0x05);
0661     if (sii9234_clear_error(ctx))
0662         return ST_FAILURE;
0663 
0664     msleep(T_SRC_VBUS_CBUS_TO_STABLE);
0665     return ST_RGND_1K;
0666 }
0667 
0668 static enum sii9234_state sii9234_mhl_established(struct sii9234 *ctx)
0669 {
0670     dev_dbg(ctx->dev, "mhl est interrupt\n");
0671 
0672     /* Discovery override */
0673     mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0x10);
0674     /* Increase DDC translation layer timer (byte mode) */
0675     cbus_writeb(ctx, 0x07, 0x32);
0676     cbus_writebm(ctx, 0x44, ~0, 1 << 1);
0677     /* Keep the discovery enabled. Need RGND interrupt */
0678     mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 1);
0679     mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG,
0680               RSEN_CHANGE_INT_MASK | HPD_CHANGE_INT_MASK);
0681 
0682     if (sii9234_clear_error(ctx))
0683         return ST_FAILURE;
0684 
0685     return ST_MHL_ESTABLISHED;
0686 }
0687 
0688 static enum sii9234_state sii9234_hpd_change(struct sii9234 *ctx)
0689 {
0690     int value;
0691 
0692     value = cbus_readb(ctx, CBUS_MSC_REQ_ABORT_REASON_REG);
0693     if (sii9234_clear_error(ctx))
0694         return ST_FAILURE;
0695 
0696     if (value & SET_HPD_DOWNSTREAM) {
0697         /* Downstream HPD High, Enable TMDS */
0698         sii9234_tmds_control(ctx, true);
0699     } else {
0700         /* Downstream HPD Low, Disable TMDS */
0701         sii9234_tmds_control(ctx, false);
0702     }
0703 
0704     return ctx->state;
0705 }
0706 
0707 static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx)
0708 {
0709     int value;
0710 
0711     /* Work_around code to handle wrong interrupt */
0712     if (ctx->state != ST_RGND_1K) {
0713         dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n");
0714         return ST_FAILURE;
0715     }
0716     value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
0717     if (value < 0)
0718         return ST_FAILURE;
0719 
0720     if (value & RSEN_STATUS) {
0721         dev_dbg(ctx->dev, "MHL cable connected.. RSEN High\n");
0722         return ST_RSEN_HIGH;
0723     }
0724     dev_dbg(ctx->dev, "RSEN lost\n");
0725     /*
0726      * Once RSEN loss is confirmed,we need to check
0727      * based on cable status and chip power status,whether
0728      * it is SINK Loss(HDMI cable not connected, TV Off)
0729      * or MHL cable disconnection
0730      * TODO: Define the below mhl_disconnection()
0731      */
0732     msleep(T_SRC_RXSENSE_DEGLITCH);
0733     value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
0734     if (value < 0)
0735         return ST_FAILURE;
0736     dev_dbg(ctx->dev, "sys_stat: %x\n", value);
0737 
0738     if (value & RSEN_STATUS) {
0739         dev_dbg(ctx->dev, "RSEN recovery\n");
0740         return ST_RSEN_HIGH;
0741     }
0742     dev_dbg(ctx->dev, "RSEN Really LOW\n");
0743     /* To meet CTS 3.3.22.2 spec */
0744     sii9234_tmds_control(ctx, false);
0745     force_usb_id_switch_open(ctx);
0746     release_usb_id_switch_open(ctx);
0747 
0748     return ST_FAILURE;
0749 }
0750 
0751 static irqreturn_t sii9234_irq_thread(int irq, void *data)
0752 {
0753     struct sii9234 *ctx = data;
0754     int intr1, intr4;
0755     int intr1_en, intr4_en;
0756     int cbus_intr1, cbus_intr2;
0757 
0758     dev_dbg(ctx->dev, "%s\n", __func__);
0759 
0760     mutex_lock(&ctx->lock);
0761 
0762     intr1 = mhl_tx_readb(ctx, MHL_TX_INTR1_REG);
0763     intr4 = mhl_tx_readb(ctx, MHL_TX_INTR4_REG);
0764     intr1_en = mhl_tx_readb(ctx, MHL_TX_INTR1_ENABLE_REG);
0765     intr4_en = mhl_tx_readb(ctx, MHL_TX_INTR4_ENABLE_REG);
0766     cbus_intr1 = cbus_readb(ctx, CBUS_INT_STATUS_1_REG);
0767     cbus_intr2 = cbus_readb(ctx, CBUS_INT_STATUS_2_REG);
0768 
0769     if (sii9234_clear_error(ctx))
0770         goto done;
0771 
0772     dev_dbg(ctx->dev, "irq %02x/%02x %02x/%02x %02x/%02x\n",
0773         intr1, intr1_en, intr4, intr4_en, cbus_intr1, cbus_intr2);
0774 
0775     if (intr4 & RGND_READY_INT)
0776         ctx->state = sii9234_rgnd_ready_irq(ctx);
0777     if (intr1 & RSEN_CHANGE_INT)
0778         ctx->state = sii9234_rsen_change(ctx);
0779     if (intr4 & MHL_EST_INT)
0780         ctx->state = sii9234_mhl_established(ctx);
0781     if (intr1 & HPD_CHANGE_INT)
0782         ctx->state = sii9234_hpd_change(ctx);
0783     if (intr4 & CBUS_LKOUT_INT)
0784         ctx->state = ST_FAILURE;
0785     if (intr4 & MHL_DISC_FAIL_INT)
0786         ctx->state = ST_FAILURE_DISCOVERY;
0787 
0788  done:
0789     /* Clean interrupt status and pending flags */
0790     mhl_tx_writeb(ctx, MHL_TX_INTR1_REG, intr1);
0791     mhl_tx_writeb(ctx, MHL_TX_INTR4_REG, intr4);
0792     cbus_writeb(ctx, CBUS_MHL_STATUS_REG_0, 0xFF);
0793     cbus_writeb(ctx, CBUS_MHL_STATUS_REG_1, 0xFF);
0794     cbus_writeb(ctx, CBUS_INT_STATUS_1_REG, cbus_intr1);
0795     cbus_writeb(ctx, CBUS_INT_STATUS_2_REG, cbus_intr2);
0796 
0797     sii9234_clear_error(ctx);
0798 
0799     if (ctx->state == ST_FAILURE) {
0800         dev_dbg(ctx->dev, "try to reset after failure\n");
0801         sii9234_hw_reset(ctx);
0802         sii9234_goto_d3(ctx);
0803     }
0804 
0805     if (ctx->state == ST_FAILURE_DISCOVERY) {
0806         dev_err(ctx->dev, "discovery failed, no power for MHL?\n");
0807         tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
0808         ctx->state = ST_D3;
0809     }
0810 
0811     mutex_unlock(&ctx->lock);
0812 
0813     return IRQ_HANDLED;
0814 }
0815 
0816 static int sii9234_init_resources(struct sii9234 *ctx,
0817                   struct i2c_client *client)
0818 {
0819     struct i2c_adapter *adapter = client->adapter;
0820     int ret;
0821 
0822     if (!ctx->dev->of_node) {
0823         dev_err(ctx->dev, "not DT device\n");
0824         return -ENODEV;
0825     }
0826 
0827     ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW);
0828     if (IS_ERR(ctx->gpio_reset)) {
0829         dev_err(ctx->dev, "failed to get reset gpio from DT\n");
0830         return PTR_ERR(ctx->gpio_reset);
0831     }
0832 
0833     ctx->supplies[0].supply = "avcc12";
0834     ctx->supplies[1].supply = "avcc33";
0835     ctx->supplies[2].supply = "iovcc18";
0836     ctx->supplies[3].supply = "cvcc12";
0837     ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies);
0838     if (ret) {
0839         if (ret != -EPROBE_DEFER)
0840             dev_err(ctx->dev, "regulator_bulk failed\n");
0841         return ret;
0842     }
0843 
0844     ctx->client[I2C_MHL] = client;
0845 
0846     ctx->client[I2C_TPI] = devm_i2c_new_dummy_device(&client->dev, adapter,
0847                              I2C_TPI_ADDR);
0848     if (IS_ERR(ctx->client[I2C_TPI])) {
0849         dev_err(ctx->dev, "failed to create TPI client\n");
0850         return PTR_ERR(ctx->client[I2C_TPI]);
0851     }
0852 
0853     ctx->client[I2C_HDMI] = devm_i2c_new_dummy_device(&client->dev, adapter,
0854                               I2C_HDMI_ADDR);
0855     if (IS_ERR(ctx->client[I2C_HDMI])) {
0856         dev_err(ctx->dev, "failed to create HDMI RX client\n");
0857         return PTR_ERR(ctx->client[I2C_HDMI]);
0858     }
0859 
0860     ctx->client[I2C_CBUS] = devm_i2c_new_dummy_device(&client->dev, adapter,
0861                               I2C_CBUS_ADDR);
0862     if (IS_ERR(ctx->client[I2C_CBUS])) {
0863         dev_err(ctx->dev, "failed to create CBUS client\n");
0864         return PTR_ERR(ctx->client[I2C_CBUS]);
0865     }
0866 
0867     return 0;
0868 }
0869 
0870 static inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge)
0871 {
0872     return container_of(bridge, struct sii9234, bridge);
0873 }
0874 
0875 static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge,
0876                      const struct drm_display_info *info,
0877                      const struct drm_display_mode *mode)
0878 {
0879     if (mode->clock > MHL1_MAX_CLK)
0880         return MODE_CLOCK_HIGH;
0881 
0882     return MODE_OK;
0883 }
0884 
0885 static const struct drm_bridge_funcs sii9234_bridge_funcs = {
0886     .mode_valid = sii9234_mode_valid,
0887 };
0888 
0889 static int sii9234_probe(struct i2c_client *client,
0890              const struct i2c_device_id *id)
0891 {
0892     struct i2c_adapter *adapter = client->adapter;
0893     struct sii9234 *ctx;
0894     struct device *dev = &client->dev;
0895     int ret;
0896 
0897     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0898     if (!ctx)
0899         return -ENOMEM;
0900 
0901     ctx->dev = dev;
0902     mutex_init(&ctx->lock);
0903 
0904     if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
0905         dev_err(dev, "I2C adapter lacks SMBUS feature\n");
0906         return -EIO;
0907     }
0908 
0909     if (!client->irq) {
0910         dev_err(dev, "no irq provided\n");
0911         return -EINVAL;
0912     }
0913 
0914     irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
0915     ret = devm_request_threaded_irq(dev, client->irq, NULL,
0916                     sii9234_irq_thread,
0917                     IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
0918                     "sii9234", ctx);
0919     if (ret < 0) {
0920         dev_err(dev, "failed to install IRQ handler\n");
0921         return ret;
0922     }
0923 
0924     ret = sii9234_init_resources(ctx, client);
0925     if (ret < 0)
0926         return ret;
0927 
0928     i2c_set_clientdata(client, ctx);
0929 
0930     ctx->bridge.funcs = &sii9234_bridge_funcs;
0931     ctx->bridge.of_node = dev->of_node;
0932     drm_bridge_add(&ctx->bridge);
0933 
0934     sii9234_cable_in(ctx);
0935 
0936     return 0;
0937 }
0938 
0939 static int sii9234_remove(struct i2c_client *client)
0940 {
0941     struct sii9234 *ctx = i2c_get_clientdata(client);
0942 
0943     sii9234_cable_out(ctx);
0944     drm_bridge_remove(&ctx->bridge);
0945 
0946     return 0;
0947 }
0948 
0949 static const struct of_device_id sii9234_dt_match[] = {
0950     { .compatible = "sil,sii9234" },
0951     { },
0952 };
0953 MODULE_DEVICE_TABLE(of, sii9234_dt_match);
0954 
0955 static const struct i2c_device_id sii9234_id[] = {
0956     { "SII9234", 0 },
0957     { },
0958 };
0959 MODULE_DEVICE_TABLE(i2c, sii9234_id);
0960 
0961 static struct i2c_driver sii9234_driver = {
0962     .driver = {
0963         .name   = "sii9234",
0964         .of_match_table = sii9234_dt_match,
0965     },
0966     .probe = sii9234_probe,
0967     .remove = sii9234_remove,
0968     .id_table = sii9234_id,
0969 };
0970 
0971 module_i2c_driver(sii9234_driver);
0972 MODULE_LICENSE("GPL");