linux/drivers/gpu/drm/i915/display/dvo_sil164.c
<<
>>
Prefs
   1/**************************************************************************
   2
   3Copyright © 2006 Dave Airlie
   4
   5All Rights Reserved.
   6
   7Permission is hereby granted, free of charge, to any person obtaining a
   8copy of this software and associated documentation files (the
   9"Software"), to deal in the Software without restriction, including
  10without limitation the rights to use, copy, modify, merge, publish,
  11distribute, sub license, and/or sell copies of the Software, and to
  12permit persons to whom the Software is furnished to do so, subject to
  13the following conditions:
  14
  15The above copyright notice and this permission notice (including the
  16next paragraph) shall be included in all copies or substantial portions
  17of the Software.
  18
  19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26
  27**************************************************************************/
  28
  29#include "intel_display_types.h"
  30#include "intel_dvo_dev.h"
  31
  32#define SIL164_VID 0x0001
  33#define SIL164_DID 0x0006
  34
  35#define SIL164_VID_LO 0x00
  36#define SIL164_VID_HI 0x01
  37#define SIL164_DID_LO 0x02
  38#define SIL164_DID_HI 0x03
  39#define SIL164_REV    0x04
  40#define SIL164_RSVD   0x05
  41#define SIL164_FREQ_LO 0x06
  42#define SIL164_FREQ_HI 0x07
  43
  44#define SIL164_REG8 0x08
  45#define SIL164_8_VEN (1<<5)
  46#define SIL164_8_HEN (1<<4)
  47#define SIL164_8_DSEL (1<<3)
  48#define SIL164_8_BSEL (1<<2)
  49#define SIL164_8_EDGE (1<<1)
  50#define SIL164_8_PD   (1<<0)
  51
  52#define SIL164_REG9 0x09
  53#define SIL164_9_VLOW (1<<7)
  54#define SIL164_9_MSEL_MASK (0x7<<4)
  55#define SIL164_9_TSEL (1<<3)
  56#define SIL164_9_RSEN (1<<2)
  57#define SIL164_9_HTPLG (1<<1)
  58#define SIL164_9_MDI (1<<0)
  59
  60#define SIL164_REGC 0x0c
  61
  62struct sil164_priv {
  63        //I2CDevRec d;
  64        bool quiet;
  65};
  66
  67#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
  68
  69static bool sil164_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
  70{
  71        struct sil164_priv *sil = dvo->dev_priv;
  72        struct i2c_adapter *adapter = dvo->i2c_bus;
  73        u8 out_buf[2];
  74        u8 in_buf[2];
  75
  76        struct i2c_msg msgs[] = {
  77                {
  78                        .addr = dvo->slave_addr,
  79                        .flags = 0,
  80                        .len = 1,
  81                        .buf = out_buf,
  82                },
  83                {
  84                        .addr = dvo->slave_addr,
  85                        .flags = I2C_M_RD,
  86                        .len = 1,
  87                        .buf = in_buf,
  88                }
  89        };
  90
  91        out_buf[0] = addr;
  92        out_buf[1] = 0;
  93
  94        if (i2c_transfer(adapter, msgs, 2) == 2) {
  95                *ch = in_buf[0];
  96                return true;
  97        }
  98
  99        if (!sil->quiet) {
 100                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
 101                          addr, adapter->name, dvo->slave_addr);
 102        }
 103        return false;
 104}
 105
 106static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
 107{
 108        struct sil164_priv *sil = dvo->dev_priv;
 109        struct i2c_adapter *adapter = dvo->i2c_bus;
 110        u8 out_buf[2];
 111        struct i2c_msg msg = {
 112                .addr = dvo->slave_addr,
 113                .flags = 0,
 114                .len = 2,
 115                .buf = out_buf,
 116        };
 117
 118        out_buf[0] = addr;
 119        out_buf[1] = ch;
 120
 121        if (i2c_transfer(adapter, &msg, 1) == 1)
 122                return true;
 123
 124        if (!sil->quiet) {
 125                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
 126                          addr, adapter->name, dvo->slave_addr);
 127        }
 128
 129        return false;
 130}
 131
 132/* Silicon Image 164 driver for chip on i2c bus */
 133static bool sil164_init(struct intel_dvo_device *dvo,
 134                        struct i2c_adapter *adapter)
 135{
 136        /* this will detect the SIL164 chip on the specified i2c bus */
 137        struct sil164_priv *sil;
 138        unsigned char ch;
 139
 140        sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
 141        if (sil == NULL)
 142                return false;
 143
 144        dvo->i2c_bus = adapter;
 145        dvo->dev_priv = sil;
 146        sil->quiet = true;
 147
 148        if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
 149                goto out;
 150
 151        if (ch != (SIL164_VID & 0xff)) {
 152                DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
 153                          ch, adapter->name, dvo->slave_addr);
 154                goto out;
 155        }
 156
 157        if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
 158                goto out;
 159
 160        if (ch != (SIL164_DID & 0xff)) {
 161                DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
 162                          ch, adapter->name, dvo->slave_addr);
 163                goto out;
 164        }
 165        sil->quiet = false;
 166
 167        DRM_DEBUG_KMS("init sil164 dvo controller successfully!\n");
 168        return true;
 169
 170out:
 171        kfree(sil);
 172        return false;
 173}
 174
 175static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
 176{
 177        u8 reg9;
 178
 179        sil164_readb(dvo, SIL164_REG9, &reg9);
 180
 181        if (reg9 & SIL164_9_HTPLG)
 182                return connector_status_connected;
 183        else
 184                return connector_status_disconnected;
 185}
 186
 187static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
 188                                              struct drm_display_mode *mode)
 189{
 190        return MODE_OK;
 191}
 192
 193static void sil164_mode_set(struct intel_dvo_device *dvo,
 194                            const struct drm_display_mode *mode,
 195                            const struct drm_display_mode *adjusted_mode)
 196{
 197        /* As long as the basics are set up, since we don't have clock
 198         * dependencies in the mode setup, we can just leave the
 199         * registers alone and everything will work fine.
 200         */
 201        /* recommended programming sequence from doc */
 202        /*sil164_writeb(sil, 0x08, 0x30);
 203          sil164_writeb(sil, 0x09, 0x00);
 204          sil164_writeb(sil, 0x0a, 0x90);
 205          sil164_writeb(sil, 0x0c, 0x89);
 206          sil164_writeb(sil, 0x08, 0x31);*/
 207        /* don't do much */
 208        return;
 209}
 210
 211/* set the SIL164 power state */
 212static void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
 213{
 214        int ret;
 215        unsigned char ch;
 216
 217        ret = sil164_readb(dvo, SIL164_REG8, &ch);
 218        if (ret == false)
 219                return;
 220
 221        if (enable)
 222                ch |= SIL164_8_PD;
 223        else
 224                ch &= ~SIL164_8_PD;
 225
 226        sil164_writeb(dvo, SIL164_REG8, ch);
 227        return;
 228}
 229
 230static bool sil164_get_hw_state(struct intel_dvo_device *dvo)
 231{
 232        int ret;
 233        unsigned char ch;
 234
 235        ret = sil164_readb(dvo, SIL164_REG8, &ch);
 236        if (ret == false)
 237                return false;
 238
 239        if (ch & SIL164_8_PD)
 240                return true;
 241        else
 242                return false;
 243}
 244
 245static void sil164_dump_regs(struct intel_dvo_device *dvo)
 246{
 247        u8 val;
 248
 249        sil164_readb(dvo, SIL164_FREQ_LO, &val);
 250        DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
 251        sil164_readb(dvo, SIL164_FREQ_HI, &val);
 252        DRM_DEBUG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
 253        sil164_readb(dvo, SIL164_REG8, &val);
 254        DRM_DEBUG_KMS("SIL164_REG8: 0x%02x\n", val);
 255        sil164_readb(dvo, SIL164_REG9, &val);
 256        DRM_DEBUG_KMS("SIL164_REG9: 0x%02x\n", val);
 257        sil164_readb(dvo, SIL164_REGC, &val);
 258        DRM_DEBUG_KMS("SIL164_REGC: 0x%02x\n", val);
 259}
 260
 261static void sil164_destroy(struct intel_dvo_device *dvo)
 262{
 263        struct sil164_priv *sil = dvo->dev_priv;
 264
 265        if (sil) {
 266                kfree(sil);
 267                dvo->dev_priv = NULL;
 268        }
 269}
 270
 271const struct intel_dvo_dev_ops sil164_ops = {
 272        .init = sil164_init,
 273        .detect = sil164_detect,
 274        .mode_valid = sil164_mode_valid,
 275        .mode_set = sil164_mode_set,
 276        .dpms = sil164_dpms,
 277        .get_hw_state = sil164_get_hw_state,
 278        .dump_regs = sil164_dump_regs,
 279        .destroy = sil164_destroy,
 280};
 281