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