linux/drivers/gpu/drm/i915/display/dvo_tfp410.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2007 Dave Mueller
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21 * IN THE SOFTWARE.
  22 *
  23 * Authors:
  24 *    Dave Mueller <dave.mueller@gmx.ch>
  25 *
  26 */
  27
  28#include "intel_drv.h"
  29#include "intel_dvo_dev.h"
  30
  31/* register definitions according to the TFP410 data sheet */
  32#define TFP410_VID              0x014C
  33#define TFP410_DID              0x0410
  34
  35#define TFP410_VID_LO           0x00
  36#define TFP410_VID_HI           0x01
  37#define TFP410_DID_LO           0x02
  38#define TFP410_DID_HI           0x03
  39#define TFP410_REV              0x04
  40
  41#define TFP410_CTL_1            0x08
  42#define TFP410_CTL_1_TDIS       (1<<6)
  43#define TFP410_CTL_1_VEN        (1<<5)
  44#define TFP410_CTL_1_HEN        (1<<4)
  45#define TFP410_CTL_1_DSEL       (1<<3)
  46#define TFP410_CTL_1_BSEL       (1<<2)
  47#define TFP410_CTL_1_EDGE       (1<<1)
  48#define TFP410_CTL_1_PD         (1<<0)
  49
  50#define TFP410_CTL_2            0x09
  51#define TFP410_CTL_2_VLOW       (1<<7)
  52#define TFP410_CTL_2_MSEL_MASK  (0x7<<4)
  53#define TFP410_CTL_2_MSEL       (1<<4)
  54#define TFP410_CTL_2_TSEL       (1<<3)
  55#define TFP410_CTL_2_RSEN       (1<<2)
  56#define TFP410_CTL_2_HTPLG      (1<<1)
  57#define TFP410_CTL_2_MDI        (1<<0)
  58
  59#define TFP410_CTL_3            0x0A
  60#define TFP410_CTL_3_DK_MASK    (0x7<<5)
  61#define TFP410_CTL_3_DK         (1<<5)
  62#define TFP410_CTL_3_DKEN       (1<<4)
  63#define TFP410_CTL_3_CTL_MASK   (0x7<<1)
  64#define TFP410_CTL_3_CTL        (1<<1)
  65
  66#define TFP410_USERCFG          0x0B
  67
  68#define TFP410_DE_DLY           0x32
  69
  70#define TFP410_DE_CTL           0x33
  71#define TFP410_DE_CTL_DEGEN     (1<<6)
  72#define TFP410_DE_CTL_VSPOL     (1<<5)
  73#define TFP410_DE_CTL_HSPOL     (1<<4)
  74#define TFP410_DE_CTL_DEDLY8    (1<<0)
  75
  76#define TFP410_DE_TOP           0x34
  77
  78#define TFP410_DE_CNT_LO        0x36
  79#define TFP410_DE_CNT_HI        0x37
  80
  81#define TFP410_DE_LIN_LO        0x38
  82#define TFP410_DE_LIN_HI        0x39
  83
  84#define TFP410_H_RES_LO         0x3A
  85#define TFP410_H_RES_HI         0x3B
  86
  87#define TFP410_V_RES_LO         0x3C
  88#define TFP410_V_RES_HI         0x3D
  89
  90struct tfp410_priv {
  91        bool quiet;
  92};
  93
  94static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, u8 *ch)
  95{
  96        struct tfp410_priv *tfp = dvo->dev_priv;
  97        struct i2c_adapter *adapter = dvo->i2c_bus;
  98        u8 out_buf[2];
  99        u8 in_buf[2];
 100
 101        struct i2c_msg msgs[] = {
 102                {
 103                        .addr = dvo->slave_addr,
 104                        .flags = 0,
 105                        .len = 1,
 106                        .buf = out_buf,
 107                },
 108                {
 109                        .addr = dvo->slave_addr,
 110                        .flags = I2C_M_RD,
 111                        .len = 1,
 112                        .buf = in_buf,
 113                }
 114        };
 115
 116        out_buf[0] = addr;
 117        out_buf[1] = 0;
 118
 119        if (i2c_transfer(adapter, msgs, 2) == 2) {
 120                *ch = in_buf[0];
 121                return true;
 122        }
 123
 124        if (!tfp->quiet) {
 125                DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
 126                          addr, adapter->name, dvo->slave_addr);
 127        }
 128        return false;
 129}
 130
 131static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, u8 ch)
 132{
 133        struct tfp410_priv *tfp = dvo->dev_priv;
 134        struct i2c_adapter *adapter = dvo->i2c_bus;
 135        u8 out_buf[2];
 136        struct i2c_msg msg = {
 137                .addr = dvo->slave_addr,
 138                .flags = 0,
 139                .len = 2,
 140                .buf = out_buf,
 141        };
 142
 143        out_buf[0] = addr;
 144        out_buf[1] = ch;
 145
 146        if (i2c_transfer(adapter, &msg, 1) == 1)
 147                return true;
 148
 149        if (!tfp->quiet) {
 150                DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
 151                          addr, adapter->name, dvo->slave_addr);
 152        }
 153
 154        return false;
 155}
 156
 157static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
 158{
 159        u8 ch1, ch2;
 160
 161        if (tfp410_readb(dvo, addr+0, &ch1) &&
 162            tfp410_readb(dvo, addr+1, &ch2))
 163                return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);
 164
 165        return -1;
 166}
 167
 168/* Ti TFP410 driver for chip on i2c bus */
 169static bool tfp410_init(struct intel_dvo_device *dvo,
 170                        struct i2c_adapter *adapter)
 171{
 172        /* this will detect the tfp410 chip on the specified i2c bus */
 173        struct tfp410_priv *tfp;
 174        int id;
 175
 176        tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
 177        if (tfp == NULL)
 178                return false;
 179
 180        dvo->i2c_bus = adapter;
 181        dvo->dev_priv = tfp;
 182        tfp->quiet = true;
 183
 184        if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
 185                DRM_DEBUG_KMS("tfp410 not detected got VID %X: from %s "
 186                                "Slave %d.\n",
 187                          id, adapter->name, dvo->slave_addr);
 188                goto out;
 189        }
 190
 191        if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
 192                DRM_DEBUG_KMS("tfp410 not detected got DID %X: from %s "
 193                                "Slave %d.\n",
 194                          id, adapter->name, dvo->slave_addr);
 195                goto out;
 196        }
 197        tfp->quiet = false;
 198        return true;
 199out:
 200        kfree(tfp);
 201        return false;
 202}
 203
 204static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)
 205{
 206        enum drm_connector_status ret = connector_status_disconnected;
 207        u8 ctl2;
 208
 209        if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {
 210                if (ctl2 & TFP410_CTL_2_RSEN)
 211                        ret = connector_status_connected;
 212                else
 213                        ret = connector_status_disconnected;
 214        }
 215
 216        return ret;
 217}
 218
 219static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
 220                                              struct drm_display_mode *mode)
 221{
 222        return MODE_OK;
 223}
 224
 225static void tfp410_mode_set(struct intel_dvo_device *dvo,
 226                            const struct drm_display_mode *mode,
 227                            const struct drm_display_mode *adjusted_mode)
 228{
 229        /* As long as the basics are set up, since we don't have clock dependencies
 230        * in the mode setup, we can just leave the registers alone and everything
 231        * will work fine.
 232        */
 233        /* don't do much */
 234        return;
 235}
 236
 237/* set the tfp410 power state */
 238static void tfp410_dpms(struct intel_dvo_device *dvo, bool enable)
 239{
 240        u8 ctl1;
 241
 242        if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
 243                return;
 244
 245        if (enable)
 246                ctl1 |= TFP410_CTL_1_PD;
 247        else
 248                ctl1 &= ~TFP410_CTL_1_PD;
 249
 250        tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
 251}
 252
 253static bool tfp410_get_hw_state(struct intel_dvo_device *dvo)
 254{
 255        u8 ctl1;
 256
 257        if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
 258                return false;
 259
 260        if (ctl1 & TFP410_CTL_1_PD)
 261                return true;
 262        else
 263                return false;
 264}
 265
 266static void tfp410_dump_regs(struct intel_dvo_device *dvo)
 267{
 268        u8 val, val2;
 269
 270        tfp410_readb(dvo, TFP410_REV, &val);
 271        DRM_DEBUG_KMS("TFP410_REV: 0x%02X\n", val);
 272        tfp410_readb(dvo, TFP410_CTL_1, &val);
 273        DRM_DEBUG_KMS("TFP410_CTL1: 0x%02X\n", val);
 274        tfp410_readb(dvo, TFP410_CTL_2, &val);
 275        DRM_DEBUG_KMS("TFP410_CTL2: 0x%02X\n", val);
 276        tfp410_readb(dvo, TFP410_CTL_3, &val);
 277        DRM_DEBUG_KMS("TFP410_CTL3: 0x%02X\n", val);
 278        tfp410_readb(dvo, TFP410_USERCFG, &val);
 279        DRM_DEBUG_KMS("TFP410_USERCFG: 0x%02X\n", val);
 280        tfp410_readb(dvo, TFP410_DE_DLY, &val);
 281        DRM_DEBUG_KMS("TFP410_DE_DLY: 0x%02X\n", val);
 282        tfp410_readb(dvo, TFP410_DE_CTL, &val);
 283        DRM_DEBUG_KMS("TFP410_DE_CTL: 0x%02X\n", val);
 284        tfp410_readb(dvo, TFP410_DE_TOP, &val);
 285        DRM_DEBUG_KMS("TFP410_DE_TOP: 0x%02X\n", val);
 286        tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);
 287        tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);
 288        DRM_DEBUG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
 289        tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);
 290        tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);
 291        DRM_DEBUG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
 292        tfp410_readb(dvo, TFP410_H_RES_LO, &val);
 293        tfp410_readb(dvo, TFP410_H_RES_HI, &val2);
 294        DRM_DEBUG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val);
 295        tfp410_readb(dvo, TFP410_V_RES_LO, &val);
 296        tfp410_readb(dvo, TFP410_V_RES_HI, &val2);
 297        DRM_DEBUG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);
 298}
 299
 300static void tfp410_destroy(struct intel_dvo_device *dvo)
 301{
 302        struct tfp410_priv *tfp = dvo->dev_priv;
 303
 304        if (tfp) {
 305                kfree(tfp);
 306                dvo->dev_priv = NULL;
 307        }
 308}
 309
 310const struct intel_dvo_dev_ops tfp410_ops = {
 311        .init = tfp410_init,
 312        .detect = tfp410_detect,
 313        .mode_valid = tfp410_mode_valid,
 314        .mode_set = tfp410_mode_set,
 315        .dpms = tfp410_dpms,
 316        .get_hw_state = tfp410_get_hw_state,
 317        .dump_regs = tfp410_dump_regs,
 318        .destroy = tfp410_destroy,
 319};
 320