linux/drivers/gpu/drm/bridge/sii9234.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2017 Samsung Electronics
   4 *
   5 * Authors:
   6 *    Tomasz Stanislawski <t.stanislaws@samsung.com>
   7 *    Maciej Purski <m.purski@samsung.com>
   8 *
   9 * Based on sii9234 driver created by:
  10 *    Adam Hampson <ahampson@sta.samsung.com>
  11 *    Erik Gilling <konkers@android.com>
  12 *    Shankar Bandal <shankar.b@samsung.com>
  13 *    Dharam Kumar <dharam.kr@samsung.com>
  14 */
  15#include <drm/bridge/mhl.h>
  16#include <drm/drm_bridge.h>
  17#include <drm/drm_crtc.h>
  18#include <drm/drm_edid.h>
  19
  20#include <linux/delay.h>
  21#include <linux/err.h>
  22#include <linux/gpio/consumer.h>
  23#include <linux/i2c.h>
  24#include <linux/interrupt.h>
  25#include <linux/irq.h>
  26#include <linux/kernel.h>
  27#include <linux/module.h>
  28#include <linux/mutex.h>
  29#include <linux/regulator/consumer.h>
  30#include <linux/slab.h>
  31
  32#define CBUS_DEVCAP_OFFSET              0x80
  33
  34#define SII9234_MHL_VERSION             0x11
  35#define SII9234_SCRATCHPAD_SIZE         0x10
  36#define SII9234_INT_STAT_SIZE           0x33
  37
  38#define BIT_TMDS_CCTRL_TMDS_OE          BIT(4)
  39#define MHL_HPD_OUT_OVR_EN              BIT(4)
  40#define MHL_HPD_OUT_OVR_VAL             BIT(5)
  41#define MHL_INIT_TIMEOUT                0x0C
  42
  43/* MHL Tx registers and bits */
  44#define MHL_TX_SRST                     0x05
  45#define MHL_TX_SYSSTAT_REG              0x09
  46#define MHL_TX_INTR1_REG                0x71
  47#define MHL_TX_INTR4_REG                0x74
  48#define MHL_TX_INTR1_ENABLE_REG         0x75
  49#define MHL_TX_INTR4_ENABLE_REG         0x78
  50#define MHL_TX_INT_CTRL_REG             0x79
  51#define MHL_TX_TMDS_CCTRL               0x80
  52#define MHL_TX_DISC_CTRL1_REG           0x90
  53#define MHL_TX_DISC_CTRL2_REG           0x91
  54#define MHL_TX_DISC_CTRL3_REG           0x92
  55#define MHL_TX_DISC_CTRL4_REG           0x93
  56#define MHL_TX_DISC_CTRL5_REG           0x94
  57#define MHL_TX_DISC_CTRL6_REG           0x95
  58#define MHL_TX_DISC_CTRL7_REG           0x96
  59#define MHL_TX_DISC_CTRL8_REG           0x97
  60#define MHL_TX_STAT2_REG                0x99
  61#define MHL_TX_MHLTX_CTL1_REG           0xA0
  62#define MHL_TX_MHLTX_CTL2_REG           0xA1
  63#define MHL_TX_MHLTX_CTL4_REG           0xA3
  64#define MHL_TX_MHLTX_CTL6_REG           0xA5
  65#define MHL_TX_MHLTX_CTL7_REG           0xA6
  66
  67#define RSEN_STATUS                     BIT(2)
  68#define HPD_CHANGE_INT                  BIT(6)
  69#define RSEN_CHANGE_INT                 BIT(5)
  70#define RGND_READY_INT                  BIT(6)
  71#define VBUS_LOW_INT                    BIT(5)
  72#define CBUS_LKOUT_INT                  BIT(4)
  73#define MHL_DISC_FAIL_INT               BIT(3)
  74#define MHL_EST_INT                     BIT(2)
  75#define HPD_CHANGE_INT_MASK             BIT(6)
  76#define RSEN_CHANGE_INT_MASK            BIT(5)
  77
  78#define RGND_READY_MASK                 BIT(6)
  79#define CBUS_LKOUT_MASK                 BIT(4)
  80#define MHL_DISC_FAIL_MASK              BIT(3)
  81#define MHL_EST_MASK                    BIT(2)
  82
  83#define SKIP_GND                        BIT(6)
  84
  85#define ATT_THRESH_SHIFT                0x04
  86#define ATT_THRESH_MASK                 (0x03 << ATT_THRESH_SHIFT)
  87#define USB_D_OEN                       BIT(3)
  88#define DEGLITCH_TIME_MASK              0x07
  89#define DEGLITCH_TIME_2MS               0
  90#define DEGLITCH_TIME_4MS               1
  91#define DEGLITCH_TIME_8MS               2
  92#define DEGLITCH_TIME_16MS              3
  93#define DEGLITCH_TIME_40MS              4
  94#define DEGLITCH_TIME_50MS              5
  95#define DEGLITCH_TIME_60MS              6
  96#define DEGLITCH_TIME_128MS             7
  97
  98#define USB_D_OVR                       BIT(7)
  99#define USB_ID_OVR                      BIT(6)
 100#define DVRFLT_SEL                      BIT(5)
 101#define BLOCK_RGND_INT                  BIT(4)
 102#define SKIP_DEG                        BIT(3)
 103#define CI2CA_POL                       BIT(2)
 104#define CI2CA_WKUP                      BIT(1)
 105#define SINGLE_ATT                      BIT(0)
 106
 107#define USB_D_ODN                       BIT(5)
 108#define VBUS_CHECK                      BIT(2)
 109#define RGND_INTP_MASK                  0x03
 110#define RGND_INTP_OPEN                  0
 111#define RGND_INTP_2K                    1
 112#define RGND_INTP_1K                    2
 113#define RGND_INTP_SHORT                 3
 114
 115/* HDMI registers */
 116#define HDMI_RX_TMDS0_CCTRL1_REG        0x10
 117#define HDMI_RX_TMDS_CLK_EN_REG         0x11
 118#define HDMI_RX_TMDS_CH_EN_REG          0x12
 119#define HDMI_RX_PLL_CALREFSEL_REG       0x17
 120#define HDMI_RX_PLL_VCOCAL_REG          0x1A
 121#define HDMI_RX_EQ_DATA0_REG            0x22
 122#define HDMI_RX_EQ_DATA1_REG            0x23
 123#define HDMI_RX_EQ_DATA2_REG            0x24
 124#define HDMI_RX_EQ_DATA3_REG            0x25
 125#define HDMI_RX_EQ_DATA4_REG            0x26
 126#define HDMI_RX_TMDS_ZONE_CTRL_REG      0x4C
 127#define HDMI_RX_TMDS_MODE_CTRL_REG      0x4D
 128
 129/* CBUS registers */
 130#define CBUS_INT_STATUS_1_REG           0x08
 131#define CBUS_INTR1_ENABLE_REG           0x09
 132#define CBUS_MSC_REQ_ABORT_REASON_REG   0x0D
 133#define CBUS_INT_STATUS_2_REG           0x1E
 134#define CBUS_INTR2_ENABLE_REG           0x1F
 135#define CBUS_LINK_CONTROL_2_REG         0x31
 136#define CBUS_MHL_STATUS_REG_0           0xB0
 137#define CBUS_MHL_STATUS_REG_1           0xB1
 138
 139#define BIT_CBUS_RESET                  BIT(3)
 140#define SET_HPD_DOWNSTREAM              BIT(6)
 141
 142/* TPI registers */
 143#define TPI_DPD_REG                     0x3D
 144
 145/* Timeouts in msec */
 146#define T_SRC_VBUS_CBUS_TO_STABLE       200
 147#define T_SRC_CBUS_FLOAT                100
 148#define T_SRC_CBUS_DEGLITCH             2
 149#define T_SRC_RXSENSE_DEGLITCH          110
 150
 151#define MHL1_MAX_CLK                    75000 /* in kHz */
 152
 153#define I2C_TPI_ADDR                    0x3D
 154#define I2C_HDMI_ADDR                   0x49
 155#define I2C_CBUS_ADDR                   0x64
 156
 157enum sii9234_state {
 158        ST_OFF,
 159        ST_D3,
 160        ST_RGND_INIT,
 161        ST_RGND_1K,
 162        ST_RSEN_HIGH,
 163        ST_MHL_ESTABLISHED,
 164        ST_FAILURE_DISCOVERY,
 165        ST_FAILURE,
 166};
 167
 168struct sii9234 {
 169        struct i2c_client *client[4];
 170        struct drm_bridge bridge;
 171        struct device *dev;
 172        struct gpio_desc *gpio_reset;
 173        int i2c_error;
 174        struct regulator_bulk_data supplies[4];
 175
 176        struct mutex lock; /* Protects fields below and device registers */
 177        enum sii9234_state state;
 178};
 179
 180enum sii9234_client_id {
 181        I2C_MHL,
 182        I2C_TPI,
 183        I2C_HDMI,
 184        I2C_CBUS,
 185};
 186
 187static const char * const sii9234_client_name[] = {
 188        [I2C_MHL] = "MHL",
 189        [I2C_TPI] = "TPI",
 190        [I2C_HDMI] = "HDMI",
 191        [I2C_CBUS] = "CBUS",
 192};
 193
 194static int sii9234_writeb(struct sii9234 *ctx, int id, int offset,
 195                          int value)
 196{
 197        int ret;
 198        struct i2c_client *client = ctx->client[id];
 199
 200        if (ctx->i2c_error)
 201                return ctx->i2c_error;
 202
 203        ret = i2c_smbus_write_byte_data(client, offset, value);
 204        if (ret < 0)
 205                dev_err(ctx->dev, "writeb: %4s[0x%02x] <- 0x%02x\n",
 206                        sii9234_client_name[id], offset, value);
 207        ctx->i2c_error = ret;
 208
 209        return ret;
 210}
 211
 212static int sii9234_writebm(struct sii9234 *ctx, int id, int offset,
 213                           int value, int mask)
 214{
 215        int ret;
 216        struct i2c_client *client = ctx->client[id];
 217
 218        if (ctx->i2c_error)
 219                return ctx->i2c_error;
 220
 221        ret = i2c_smbus_write_byte(client, offset);
 222        if (ret < 0) {
 223                dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
 224                        sii9234_client_name[id], offset, value);
 225                ctx->i2c_error = ret;
 226                return ret;
 227        }
 228
 229        ret = i2c_smbus_read_byte(client);
 230        if (ret < 0) {
 231                dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
 232                        sii9234_client_name[id], offset, value);
 233                ctx->i2c_error = ret;
 234                return ret;
 235        }
 236
 237        value = (value & mask) | (ret & ~mask);
 238
 239        ret = i2c_smbus_write_byte_data(client, offset, value);
 240        if (ret < 0) {
 241                dev_err(ctx->dev, "writebm: %4s[0x%02x] <- 0x%02x\n",
 242                        sii9234_client_name[id], offset, value);
 243                ctx->i2c_error = ret;
 244        }
 245
 246        return ret;
 247}
 248
 249static int sii9234_readb(struct sii9234 *ctx, int id, int offset)
 250{
 251        int ret;
 252        struct i2c_client *client = ctx->client[id];
 253
 254        if (ctx->i2c_error)
 255                return ctx->i2c_error;
 256
 257        ret = i2c_smbus_write_byte(client, offset);
 258        if (ret < 0) {
 259                dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
 260                        sii9234_client_name[id], offset);
 261                ctx->i2c_error = ret;
 262                return ret;
 263        }
 264
 265        ret = i2c_smbus_read_byte(client);
 266        if (ret < 0) {
 267                dev_err(ctx->dev, "readb: %4s[0x%02x]\n",
 268                        sii9234_client_name[id], offset);
 269                ctx->i2c_error = ret;
 270        }
 271
 272        return ret;
 273}
 274
 275static int sii9234_clear_error(struct sii9234 *ctx)
 276{
 277        int ret = ctx->i2c_error;
 278
 279        ctx->i2c_error = 0;
 280
 281        return ret;
 282}
 283
 284#define mhl_tx_writeb(sii9234, offset, value) \
 285        sii9234_writeb(sii9234, I2C_MHL, offset, value)
 286#define mhl_tx_writebm(sii9234, offset, value, mask) \
 287        sii9234_writebm(sii9234, I2C_MHL, offset, value, mask)
 288#define mhl_tx_readb(sii9234, offset) \
 289        sii9234_readb(sii9234, I2C_MHL, offset)
 290#define cbus_writeb(sii9234, offset, value) \
 291        sii9234_writeb(sii9234, I2C_CBUS, offset, value)
 292#define cbus_writebm(sii9234, offset, value, mask) \
 293        sii9234_writebm(sii9234, I2C_CBUS, offset, value, mask)
 294#define cbus_readb(sii9234, offset) \
 295        sii9234_readb(sii9234, I2C_CBUS, offset)
 296#define hdmi_writeb(sii9234, offset, value) \
 297        sii9234_writeb(sii9234, I2C_HDMI, offset, value)
 298#define hdmi_writebm(sii9234, offset, value, mask) \
 299        sii9234_writebm(sii9234, I2C_HDMI, offset, value, mask)
 300#define hdmi_readb(sii9234, offset) \
 301        sii9234_readb(sii9234, I2C_HDMI, offset)
 302#define tpi_writeb(sii9234, offset, value) \
 303        sii9234_writeb(sii9234, I2C_TPI, offset, value)
 304#define tpi_writebm(sii9234, offset, value, mask) \
 305        sii9234_writebm(sii9234, I2C_TPI, offset, value, mask)
 306#define tpi_readb(sii9234, offset) \
 307        sii9234_readb(sii9234, I2C_TPI, offset)
 308
 309static u8 sii9234_tmds_control(struct sii9234 *ctx, bool enable)
 310{
 311        mhl_tx_writebm(ctx, MHL_TX_TMDS_CCTRL, enable ? ~0 : 0,
 312                       BIT_TMDS_CCTRL_TMDS_OE);
 313        mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, enable ? ~0 : 0,
 314                       MHL_HPD_OUT_OVR_EN | MHL_HPD_OUT_OVR_VAL);
 315        return sii9234_clear_error(ctx);
 316}
 317
 318static int sii9234_cbus_reset(struct sii9234 *ctx)
 319{
 320        int i;
 321
 322        mhl_tx_writebm(ctx, MHL_TX_SRST, ~0, BIT_CBUS_RESET);
 323        msleep(T_SRC_CBUS_DEGLITCH);
 324        mhl_tx_writebm(ctx, MHL_TX_SRST, 0, BIT_CBUS_RESET);
 325
 326        for (i = 0; i < 4; i++) {
 327                /*
 328                 * Enable WRITE_STAT interrupt for writes to all
 329                 * 4 MSC Status registers.
 330                 */
 331                cbus_writeb(ctx, 0xE0 + i, 0xF2);
 332                /*
 333                 * Enable SET_INT interrupt for writes to all
 334                 * 4 MSC Interrupt registers.
 335                 */
 336                cbus_writeb(ctx, 0xF0 + i, 0xF2);
 337        }
 338
 339        return sii9234_clear_error(ctx);
 340}
 341
 342/* Require to chek mhl imformation of samsung in cbus_init_register */
 343static int sii9234_cbus_init(struct sii9234 *ctx)
 344{
 345        cbus_writeb(ctx, 0x07, 0xF2);
 346        cbus_writeb(ctx, 0x40, 0x03);
 347        cbus_writeb(ctx, 0x42, 0x06);
 348        cbus_writeb(ctx, 0x36, 0x0C);
 349        cbus_writeb(ctx, 0x3D, 0xFD);
 350        cbus_writeb(ctx, 0x1C, 0x01);
 351        cbus_writeb(ctx, 0x1D, 0x0F);
 352        cbus_writeb(ctx, 0x44, 0x02);
 353        /* Setup our devcap */
 354        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEV_STATE, 0x00);
 355        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_MHL_VERSION,
 356                    SII9234_MHL_VERSION);
 357        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_CAT,
 358                    MHL_DCAP_CAT_SOURCE);
 359        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_H, 0x01);
 360        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_ADOPTER_ID_L, 0x41);
 361        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VID_LINK_MODE,
 362                    MHL_DCAP_VID_LINK_RGB444 | MHL_DCAP_VID_LINK_YCBCR444);
 363        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_VIDEO_TYPE,
 364                    MHL_DCAP_VT_GRAPHICS);
 365        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_LOG_DEV_MAP,
 366                    MHL_DCAP_LD_GUI);
 367        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_BANDWIDTH, 0x0F);
 368        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_FEATURE_FLAG,
 369                    MHL_DCAP_FEATURE_RCP_SUPPORT | MHL_DCAP_FEATURE_RAP_SUPPORT
 370                        | MHL_DCAP_FEATURE_SP_SUPPORT);
 371        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_H, 0x0);
 372        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_DEVICE_ID_L, 0x0);
 373        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_SCRATCHPAD_SIZE,
 374                    SII9234_SCRATCHPAD_SIZE);
 375        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_INT_STAT_SIZE,
 376                    SII9234_INT_STAT_SIZE);
 377        cbus_writeb(ctx, CBUS_DEVCAP_OFFSET + MHL_DCAP_RESERVED, 0);
 378        cbus_writebm(ctx, 0x31, 0x0C, 0x0C);
 379        cbus_writeb(ctx, 0x30, 0x01);
 380        cbus_writebm(ctx, 0x3C, 0x30, 0x38);
 381        cbus_writebm(ctx, 0x22, 0x0D, 0x0F);
 382        cbus_writebm(ctx, 0x2E, 0x15, 0x15);
 383        cbus_writeb(ctx, CBUS_INTR1_ENABLE_REG, 0);
 384        cbus_writeb(ctx, CBUS_INTR2_ENABLE_REG, 0);
 385
 386        return sii9234_clear_error(ctx);
 387}
 388
 389static void force_usb_id_switch_open(struct sii9234 *ctx)
 390{
 391        /* Disable CBUS discovery */
 392        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0, 0x01);
 393        /* Force USB ID switch to open */
 394        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
 395        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
 396        /* Force upstream HPD to 0 when not in MHL mode. */
 397        mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x30);
 398}
 399
 400static void release_usb_id_switch_open(struct sii9234 *ctx)
 401{
 402        msleep(T_SRC_CBUS_FLOAT);
 403        /* Clear USB ID switch to open */
 404        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0, USB_ID_OVR);
 405        /* Enable CBUS discovery */
 406        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 0x01);
 407}
 408
 409static int sii9234_power_init(struct sii9234 *ctx)
 410{
 411        /* Force the SiI9234 into the D0 state. */
 412        tpi_writeb(ctx, TPI_DPD_REG, 0x3F);
 413        /* Enable TxPLL Clock */
 414        hdmi_writeb(ctx, HDMI_RX_TMDS_CLK_EN_REG, 0x01);
 415        /* Enable Tx Clock Path & Equalizer */
 416        hdmi_writeb(ctx, HDMI_RX_TMDS_CH_EN_REG, 0x15);
 417        /* Power Up TMDS */
 418        mhl_tx_writeb(ctx, 0x08, 0x35);
 419        return sii9234_clear_error(ctx);
 420}
 421
 422static int sii9234_hdmi_init(struct sii9234 *ctx)
 423{
 424        hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
 425        hdmi_writeb(ctx, HDMI_RX_PLL_CALREFSEL_REG, 0x03);
 426        hdmi_writeb(ctx, HDMI_RX_PLL_VCOCAL_REG, 0x20);
 427        hdmi_writeb(ctx, HDMI_RX_EQ_DATA0_REG, 0x8A);
 428        hdmi_writeb(ctx, HDMI_RX_EQ_DATA1_REG, 0x6A);
 429        hdmi_writeb(ctx, HDMI_RX_EQ_DATA2_REG, 0xAA);
 430        hdmi_writeb(ctx, HDMI_RX_EQ_DATA3_REG, 0xCA);
 431        hdmi_writeb(ctx, HDMI_RX_EQ_DATA4_REG, 0xEA);
 432        hdmi_writeb(ctx, HDMI_RX_TMDS_ZONE_CTRL_REG, 0xA0);
 433        hdmi_writeb(ctx, HDMI_RX_TMDS_MODE_CTRL_REG, 0x00);
 434        mhl_tx_writeb(ctx, MHL_TX_TMDS_CCTRL, 0x34);
 435        hdmi_writeb(ctx, 0x45, 0x44);
 436        hdmi_writeb(ctx, 0x31, 0x0A);
 437        hdmi_writeb(ctx, HDMI_RX_TMDS0_CCTRL1_REG, 0xC1);
 438
 439        return sii9234_clear_error(ctx);
 440}
 441
 442static int sii9234_mhl_tx_ctl_int(struct sii9234 *ctx)
 443{
 444        mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0xD0);
 445        mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL2_REG, 0xFC);
 446        mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL4_REG, 0xEB);
 447        mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL7_REG, 0x0C);
 448
 449        return sii9234_clear_error(ctx);
 450}
 451
 452static int sii9234_reset(struct sii9234 *ctx)
 453{
 454        int ret;
 455
 456        sii9234_clear_error(ctx);
 457
 458        ret = sii9234_power_init(ctx);
 459        if (ret < 0)
 460                return ret;
 461        ret = sii9234_cbus_reset(ctx);
 462        if (ret < 0)
 463                return ret;
 464        ret = sii9234_hdmi_init(ctx);
 465        if (ret < 0)
 466                return ret;
 467        ret = sii9234_mhl_tx_ctl_int(ctx);
 468        if (ret < 0)
 469                return ret;
 470
 471        /* Enable HDCP Compliance safety */
 472        mhl_tx_writeb(ctx, 0x2B, 0x01);
 473        /* CBUS discovery cycle time for each drive and float = 150us */
 474        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0x04, 0x06);
 475        /* Clear bit 6 (reg_skip_rgnd) */
 476        mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL2_REG, (1 << 7) /* Reserved */
 477                      | 2 << ATT_THRESH_SHIFT | DEGLITCH_TIME_50MS);
 478        /*
 479         * Changed from 66 to 65 for 94[1:0] = 01 = 5k reg_cbusmhl_pup_sel
 480         * 1.8V CBUS VTH & GND threshold
 481         * to meet CTS 3.3.7.2 spec
 482         */
 483        mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
 484        cbus_writebm(ctx, CBUS_LINK_CONTROL_2_REG, ~0, MHL_INIT_TIMEOUT);
 485        mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL6_REG, 0xA0);
 486        /* RGND & single discovery attempt (RGND blocking) */
 487        mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL6_REG, BLOCK_RGND_INT |
 488                      DVRFLT_SEL | SINGLE_ATT);
 489        /* Use VBUS path of discovery state machine */
 490        mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL8_REG, 0);
 491        /* 0x92[3] sets the CBUS / ID switch */
 492        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
 493        /*
 494         * To allow RGND engine to operate correctly.
 495         * When moving the chip from D2 to D0 (power up, init regs)
 496         * the values should be
 497         * 94[1:0] = 01  reg_cbusmhl_pup_sel[1:0] should be set for 5k
 498         * 93[7:6] = 10  reg_cbusdisc_pup_sel[1:0] should be
 499         * set for 10k (default)
 500         * 93[5:4] = 00  reg_cbusidle_pup_sel[1:0] = open (default)
 501         */
 502        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86);
 503        /*
 504         * Change from CC to 8C to match 5K
 505         * to meet CTS 3.3.72 spec
 506         */
 507        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
 508        /* Configure the interrupt as active high */
 509        mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x06);
 510
 511        msleep(25);
 512
 513        /* Release usb_id switch */
 514        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0,  USB_ID_OVR);
 515        mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL1_REG, 0x27);
 516
 517        ret = sii9234_clear_error(ctx);
 518        if (ret < 0)
 519                return ret;
 520        ret = sii9234_cbus_init(ctx);
 521        if (ret < 0)
 522                return ret;
 523
 524        /* Enable Auto soft reset on SCDT = 0 */
 525        mhl_tx_writeb(ctx, 0x05, 0x04);
 526        /* HDMI Transcode mode enable */
 527        mhl_tx_writeb(ctx, 0x0D, 0x1C);
 528        mhl_tx_writeb(ctx, MHL_TX_INTR4_ENABLE_REG,
 529                      RGND_READY_MASK | CBUS_LKOUT_MASK
 530                        | MHL_DISC_FAIL_MASK | MHL_EST_MASK);
 531        mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG, 0x60);
 532
 533        /* This point is very important before measure RGND impedance */
 534        force_usb_id_switch_open(ctx);
 535        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, 0, 0xF0);
 536        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL5_REG, 0, 0x03);
 537        release_usb_id_switch_open(ctx);
 538
 539        /* Force upstream HPD to 0 when not in MHL mode */
 540        mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 1 << 5);
 541        mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, ~0, 1 << 4);
 542
 543        return sii9234_clear_error(ctx);
 544}
 545
 546static int sii9234_goto_d3(struct sii9234 *ctx)
 547{
 548        int ret;
 549
 550        dev_dbg(ctx->dev, "sii9234: detection started d3\n");
 551
 552        ret = sii9234_reset(ctx);
 553        if (ret < 0)
 554                goto exit;
 555
 556        hdmi_writeb(ctx, 0x01, 0x03);
 557        tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
 558        /* I2C above is expected to fail because power goes down */
 559        sii9234_clear_error(ctx);
 560
 561        ctx->state = ST_D3;
 562
 563        return 0;
 564 exit:
 565        dev_err(ctx->dev, "%s failed\n", __func__);
 566        return -1;
 567}
 568
 569static int sii9234_hw_on(struct sii9234 *ctx)
 570{
 571        return regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 572}
 573
 574static void sii9234_hw_off(struct sii9234 *ctx)
 575{
 576        gpiod_set_value(ctx->gpio_reset, 1);
 577        msleep(20);
 578        regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 579}
 580
 581static void sii9234_hw_reset(struct sii9234 *ctx)
 582{
 583        gpiod_set_value(ctx->gpio_reset, 1);
 584        msleep(20);
 585        gpiod_set_value(ctx->gpio_reset, 0);
 586}
 587
 588static void sii9234_cable_in(struct sii9234 *ctx)
 589{
 590        int ret;
 591
 592        mutex_lock(&ctx->lock);
 593        if (ctx->state != ST_OFF)
 594                goto unlock;
 595        ret = sii9234_hw_on(ctx);
 596        if (ret < 0)
 597                goto unlock;
 598
 599        sii9234_hw_reset(ctx);
 600        sii9234_goto_d3(ctx);
 601        /* To avoid irq storm, when hw is in meta state */
 602        enable_irq(to_i2c_client(ctx->dev)->irq);
 603
 604unlock:
 605        mutex_unlock(&ctx->lock);
 606}
 607
 608static void sii9234_cable_out(struct sii9234 *ctx)
 609{
 610        mutex_lock(&ctx->lock);
 611
 612        if (ctx->state == ST_OFF)
 613                goto unlock;
 614
 615        disable_irq(to_i2c_client(ctx->dev)->irq);
 616        tpi_writeb(ctx, TPI_DPD_REG, 0);
 617        /* Turn on&off hpd festure for only QCT HDMI */
 618        sii9234_hw_off(ctx);
 619
 620        ctx->state = ST_OFF;
 621
 622unlock:
 623        mutex_unlock(&ctx->lock);
 624}
 625
 626static enum sii9234_state sii9234_rgnd_ready_irq(struct sii9234 *ctx)
 627{
 628        int value;
 629
 630        if (ctx->state == ST_D3) {
 631                int ret;
 632
 633                dev_dbg(ctx->dev, "RGND_READY_INT\n");
 634                sii9234_hw_reset(ctx);
 635
 636                ret = sii9234_reset(ctx);
 637                if (ret < 0) {
 638                        dev_err(ctx->dev, "sii9234_reset() failed\n");
 639                        return ST_FAILURE;
 640                }
 641
 642                return ST_RGND_INIT;
 643        }
 644
 645        /* Got interrupt in inappropriate state */
 646        if (ctx->state != ST_RGND_INIT)
 647                return ST_FAILURE;
 648
 649        value = mhl_tx_readb(ctx, MHL_TX_STAT2_REG);
 650        if (sii9234_clear_error(ctx))
 651                return ST_FAILURE;
 652
 653        if ((value & RGND_INTP_MASK) != RGND_INTP_1K) {
 654                dev_warn(ctx->dev, "RGND is not 1k\n");
 655                return ST_RGND_INIT;
 656        }
 657        dev_dbg(ctx->dev, "RGND 1K!!\n");
 658        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C);
 659        mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
 660        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, 0x05);
 661        if (sii9234_clear_error(ctx))
 662                return ST_FAILURE;
 663
 664        msleep(T_SRC_VBUS_CBUS_TO_STABLE);
 665        return ST_RGND_1K;
 666}
 667
 668static enum sii9234_state sii9234_mhl_established(struct sii9234 *ctx)
 669{
 670        dev_dbg(ctx->dev, "mhl est interrupt\n");
 671
 672        /* Discovery override */
 673        mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL1_REG, 0x10);
 674        /* Increase DDC translation layer timer (byte mode) */
 675        cbus_writeb(ctx, 0x07, 0x32);
 676        cbus_writebm(ctx, 0x44, ~0, 1 << 1);
 677        /* Keep the discovery enabled. Need RGND interrupt */
 678        mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 1);
 679        mhl_tx_writeb(ctx, MHL_TX_INTR1_ENABLE_REG,
 680                      RSEN_CHANGE_INT_MASK | HPD_CHANGE_INT_MASK);
 681
 682        if (sii9234_clear_error(ctx))
 683                return ST_FAILURE;
 684
 685        return ST_MHL_ESTABLISHED;
 686}
 687
 688static enum sii9234_state sii9234_hpd_change(struct sii9234 *ctx)
 689{
 690        int value;
 691
 692        value = cbus_readb(ctx, CBUS_MSC_REQ_ABORT_REASON_REG);
 693        if (sii9234_clear_error(ctx))
 694                return ST_FAILURE;
 695
 696        if (value & SET_HPD_DOWNSTREAM) {
 697                /* Downstream HPD High, Enable TMDS */
 698                sii9234_tmds_control(ctx, true);
 699        } else {
 700                /* Downstream HPD Low, Disable TMDS */
 701                sii9234_tmds_control(ctx, false);
 702        }
 703
 704        return ctx->state;
 705}
 706
 707static enum sii9234_state sii9234_rsen_change(struct sii9234 *ctx)
 708{
 709        int value;
 710
 711        /* Work_around code to handle wrong interrupt */
 712        if (ctx->state != ST_RGND_1K) {
 713                dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n");
 714                return ST_FAILURE;
 715        }
 716        value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
 717        if (value < 0)
 718                return ST_FAILURE;
 719
 720        if (value & RSEN_STATUS) {
 721                dev_dbg(ctx->dev, "MHL cable connected.. RSEN High\n");
 722                return ST_RSEN_HIGH;
 723        }
 724        dev_dbg(ctx->dev, "RSEN lost\n");
 725        /*
 726         * Once RSEN loss is confirmed,we need to check
 727         * based on cable status and chip power status,whether
 728         * it is SINK Loss(HDMI cable not connected, TV Off)
 729         * or MHL cable disconnection
 730         * TODO: Define the below mhl_disconnection()
 731         */
 732        msleep(T_SRC_RXSENSE_DEGLITCH);
 733        value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG);
 734        if (value < 0)
 735                return ST_FAILURE;
 736        dev_dbg(ctx->dev, "sys_stat: %x\n", value);
 737
 738        if (value & RSEN_STATUS) {
 739                dev_dbg(ctx->dev, "RSEN recovery\n");
 740                return ST_RSEN_HIGH;
 741        }
 742        dev_dbg(ctx->dev, "RSEN Really LOW\n");
 743        /* To meet CTS 3.3.22.2 spec */
 744        sii9234_tmds_control(ctx, false);
 745        force_usb_id_switch_open(ctx);
 746        release_usb_id_switch_open(ctx);
 747
 748        return ST_FAILURE;
 749}
 750
 751static irqreturn_t sii9234_irq_thread(int irq, void *data)
 752{
 753        struct sii9234 *ctx = data;
 754        int intr1, intr4;
 755        int intr1_en, intr4_en;
 756        int cbus_intr1, cbus_intr2;
 757
 758        dev_dbg(ctx->dev, "%s\n", __func__);
 759
 760        mutex_lock(&ctx->lock);
 761
 762        intr1 = mhl_tx_readb(ctx, MHL_TX_INTR1_REG);
 763        intr4 = mhl_tx_readb(ctx, MHL_TX_INTR4_REG);
 764        intr1_en = mhl_tx_readb(ctx, MHL_TX_INTR1_ENABLE_REG);
 765        intr4_en = mhl_tx_readb(ctx, MHL_TX_INTR4_ENABLE_REG);
 766        cbus_intr1 = cbus_readb(ctx, CBUS_INT_STATUS_1_REG);
 767        cbus_intr2 = cbus_readb(ctx, CBUS_INT_STATUS_2_REG);
 768
 769        if (sii9234_clear_error(ctx))
 770                goto done;
 771
 772        dev_dbg(ctx->dev, "irq %02x/%02x %02x/%02x %02x/%02x\n",
 773                intr1, intr1_en, intr4, intr4_en, cbus_intr1, cbus_intr2);
 774
 775        if (intr4 & RGND_READY_INT)
 776                ctx->state = sii9234_rgnd_ready_irq(ctx);
 777        if (intr1 & RSEN_CHANGE_INT)
 778                ctx->state = sii9234_rsen_change(ctx);
 779        if (intr4 & MHL_EST_INT)
 780                ctx->state = sii9234_mhl_established(ctx);
 781        if (intr1 & HPD_CHANGE_INT)
 782                ctx->state = sii9234_hpd_change(ctx);
 783        if (intr4 & CBUS_LKOUT_INT)
 784                ctx->state = ST_FAILURE;
 785        if (intr4 & MHL_DISC_FAIL_INT)
 786                ctx->state = ST_FAILURE_DISCOVERY;
 787
 788 done:
 789        /* Clean interrupt status and pending flags */
 790        mhl_tx_writeb(ctx, MHL_TX_INTR1_REG, intr1);
 791        mhl_tx_writeb(ctx, MHL_TX_INTR4_REG, intr4);
 792        cbus_writeb(ctx, CBUS_MHL_STATUS_REG_0, 0xFF);
 793        cbus_writeb(ctx, CBUS_MHL_STATUS_REG_1, 0xFF);
 794        cbus_writeb(ctx, CBUS_INT_STATUS_1_REG, cbus_intr1);
 795        cbus_writeb(ctx, CBUS_INT_STATUS_2_REG, cbus_intr2);
 796
 797        sii9234_clear_error(ctx);
 798
 799        if (ctx->state == ST_FAILURE) {
 800                dev_dbg(ctx->dev, "try to reset after failure\n");
 801                sii9234_hw_reset(ctx);
 802                sii9234_goto_d3(ctx);
 803        }
 804
 805        if (ctx->state == ST_FAILURE_DISCOVERY) {
 806                dev_err(ctx->dev, "discovery failed, no power for MHL?\n");
 807                tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
 808                ctx->state = ST_D3;
 809        }
 810
 811        mutex_unlock(&ctx->lock);
 812
 813        return IRQ_HANDLED;
 814}
 815
 816static int sii9234_init_resources(struct sii9234 *ctx,
 817                                  struct i2c_client *client)
 818{
 819        struct i2c_adapter *adapter = client->adapter;
 820        int ret;
 821
 822        if (!ctx->dev->of_node) {
 823                dev_err(ctx->dev, "not DT device\n");
 824                return -ENODEV;
 825        }
 826
 827        ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW);
 828        if (IS_ERR(ctx->gpio_reset)) {
 829                dev_err(ctx->dev, "failed to get reset gpio from DT\n");
 830                return PTR_ERR(ctx->gpio_reset);
 831        }
 832
 833        ctx->supplies[0].supply = "avcc12";
 834        ctx->supplies[1].supply = "avcc33";
 835        ctx->supplies[2].supply = "iovcc18";
 836        ctx->supplies[3].supply = "cvcc12";
 837        ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies);
 838        if (ret) {
 839                if (ret != -EPROBE_DEFER)
 840                        dev_err(ctx->dev, "regulator_bulk failed\n");
 841                return ret;
 842        }
 843
 844        ctx->client[I2C_MHL] = client;
 845
 846        ctx->client[I2C_TPI] = devm_i2c_new_dummy_device(&client->dev, adapter,
 847                                                         I2C_TPI_ADDR);
 848        if (IS_ERR(ctx->client[I2C_TPI])) {
 849                dev_err(ctx->dev, "failed to create TPI client\n");
 850                return PTR_ERR(ctx->client[I2C_TPI]);
 851        }
 852
 853        ctx->client[I2C_HDMI] = devm_i2c_new_dummy_device(&client->dev, adapter,
 854                                                          I2C_HDMI_ADDR);
 855        if (IS_ERR(ctx->client[I2C_HDMI])) {
 856                dev_err(ctx->dev, "failed to create HDMI RX client\n");
 857                return PTR_ERR(ctx->client[I2C_HDMI]);
 858        }
 859
 860        ctx->client[I2C_CBUS] = devm_i2c_new_dummy_device(&client->dev, adapter,
 861                                                          I2C_CBUS_ADDR);
 862        if (IS_ERR(ctx->client[I2C_CBUS])) {
 863                dev_err(ctx->dev, "failed to create CBUS client\n");
 864                return PTR_ERR(ctx->client[I2C_CBUS]);
 865        }
 866
 867        return 0;
 868}
 869
 870static inline struct sii9234 *bridge_to_sii9234(struct drm_bridge *bridge)
 871{
 872        return container_of(bridge, struct sii9234, bridge);
 873}
 874
 875static enum drm_mode_status sii9234_mode_valid(struct drm_bridge *bridge,
 876                                         const struct drm_display_info *info,
 877                                         const struct drm_display_mode *mode)
 878{
 879        if (mode->clock > MHL1_MAX_CLK)
 880                return MODE_CLOCK_HIGH;
 881
 882        return MODE_OK;
 883}
 884
 885static const struct drm_bridge_funcs sii9234_bridge_funcs = {
 886        .mode_valid = sii9234_mode_valid,
 887};
 888
 889static int sii9234_probe(struct i2c_client *client,
 890                         const struct i2c_device_id *id)
 891{
 892        struct i2c_adapter *adapter = client->adapter;
 893        struct sii9234 *ctx;
 894        struct device *dev = &client->dev;
 895        int ret;
 896
 897        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 898        if (!ctx)
 899                return -ENOMEM;
 900
 901        ctx->dev = dev;
 902        mutex_init(&ctx->lock);
 903
 904        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
 905                dev_err(dev, "I2C adapter lacks SMBUS feature\n");
 906                return -EIO;
 907        }
 908
 909        if (!client->irq) {
 910                dev_err(dev, "no irq provided\n");
 911                return -EINVAL;
 912        }
 913
 914        irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
 915        ret = devm_request_threaded_irq(dev, client->irq, NULL,
 916                                        sii9234_irq_thread,
 917                                        IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 918                                        "sii9234", ctx);
 919        if (ret < 0) {
 920                dev_err(dev, "failed to install IRQ handler\n");
 921                return ret;
 922        }
 923
 924        ret = sii9234_init_resources(ctx, client);
 925        if (ret < 0)
 926                return ret;
 927
 928        i2c_set_clientdata(client, ctx);
 929
 930        ctx->bridge.funcs = &sii9234_bridge_funcs;
 931        ctx->bridge.of_node = dev->of_node;
 932        drm_bridge_add(&ctx->bridge);
 933
 934        sii9234_cable_in(ctx);
 935
 936        return 0;
 937}
 938
 939static int sii9234_remove(struct i2c_client *client)
 940{
 941        struct sii9234 *ctx = i2c_get_clientdata(client);
 942
 943        sii9234_cable_out(ctx);
 944        drm_bridge_remove(&ctx->bridge);
 945
 946        return 0;
 947}
 948
 949static const struct of_device_id sii9234_dt_match[] = {
 950        { .compatible = "sil,sii9234" },
 951        { },
 952};
 953MODULE_DEVICE_TABLE(of, sii9234_dt_match);
 954
 955static const struct i2c_device_id sii9234_id[] = {
 956        { "SII9234", 0 },
 957        { },
 958};
 959MODULE_DEVICE_TABLE(i2c, sii9234_id);
 960
 961static struct i2c_driver sii9234_driver = {
 962        .driver = {
 963                .name   = "sii9234",
 964                .of_match_table = sii9234_dt_match,
 965        },
 966        .probe = sii9234_probe,
 967        .remove = sii9234_remove,
 968        .id_table = sii9234_id,
 969};
 970
 971module_i2c_driver(sii9234_driver);
 972MODULE_LICENSE("GPL");
 973