Path: blob/master/drivers/gpu/drm/i915/dvo_tfp410.c
15113 views
/*1* Copyright © 2007 Dave Mueller2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*22* Authors:23* Dave Mueller <[email protected]>24*25*/2627#include "dvo.h"2829/* register definitions according to the TFP410 data sheet */30#define TFP410_VID 0x014C31#define TFP410_DID 0x04103233#define TFP410_VID_LO 0x0034#define TFP410_VID_HI 0x0135#define TFP410_DID_LO 0x0236#define TFP410_DID_HI 0x0337#define TFP410_REV 0x043839#define TFP410_CTL_1 0x0840#define TFP410_CTL_1_TDIS (1<<6)41#define TFP410_CTL_1_VEN (1<<5)42#define TFP410_CTL_1_HEN (1<<4)43#define TFP410_CTL_1_DSEL (1<<3)44#define TFP410_CTL_1_BSEL (1<<2)45#define TFP410_CTL_1_EDGE (1<<1)46#define TFP410_CTL_1_PD (1<<0)4748#define TFP410_CTL_2 0x0949#define TFP410_CTL_2_VLOW (1<<7)50#define TFP410_CTL_2_MSEL_MASK (0x7<<4)51#define TFP410_CTL_2_MSEL (1<<4)52#define TFP410_CTL_2_TSEL (1<<3)53#define TFP410_CTL_2_RSEN (1<<2)54#define TFP410_CTL_2_HTPLG (1<<1)55#define TFP410_CTL_2_MDI (1<<0)5657#define TFP410_CTL_3 0x0A58#define TFP410_CTL_3_DK_MASK (0x7<<5)59#define TFP410_CTL_3_DK (1<<5)60#define TFP410_CTL_3_DKEN (1<<4)61#define TFP410_CTL_3_CTL_MASK (0x7<<1)62#define TFP410_CTL_3_CTL (1<<1)6364#define TFP410_USERCFG 0x0B6566#define TFP410_DE_DLY 0x326768#define TFP410_DE_CTL 0x3369#define TFP410_DE_CTL_DEGEN (1<<6)70#define TFP410_DE_CTL_VSPOL (1<<5)71#define TFP410_DE_CTL_HSPOL (1<<4)72#define TFP410_DE_CTL_DEDLY8 (1<<0)7374#define TFP410_DE_TOP 0x347576#define TFP410_DE_CNT_LO 0x3677#define TFP410_DE_CNT_HI 0x377879#define TFP410_DE_LIN_LO 0x3880#define TFP410_DE_LIN_HI 0x398182#define TFP410_H_RES_LO 0x3A83#define TFP410_H_RES_HI 0x3B8485#define TFP410_V_RES_LO 0x3C86#define TFP410_V_RES_HI 0x3D8788struct tfp410_priv {89bool quiet;90};9192static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)93{94struct tfp410_priv *tfp = dvo->dev_priv;95struct i2c_adapter *adapter = dvo->i2c_bus;96u8 out_buf[2];97u8 in_buf[2];9899struct i2c_msg msgs[] = {100{101.addr = dvo->slave_addr,102.flags = 0,103.len = 1,104.buf = out_buf,105},106{107.addr = dvo->slave_addr,108.flags = I2C_M_RD,109.len = 1,110.buf = in_buf,111}112};113114out_buf[0] = addr;115out_buf[1] = 0;116117if (i2c_transfer(adapter, msgs, 2) == 2) {118*ch = in_buf[0];119return true;120};121122if (!tfp->quiet) {123DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",124addr, adapter->name, dvo->slave_addr);125}126return false;127}128129static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)130{131struct tfp410_priv *tfp = dvo->dev_priv;132struct i2c_adapter *adapter = dvo->i2c_bus;133uint8_t out_buf[2];134struct i2c_msg msg = {135.addr = dvo->slave_addr,136.flags = 0,137.len = 2,138.buf = out_buf,139};140141out_buf[0] = addr;142out_buf[1] = ch;143144if (i2c_transfer(adapter, &msg, 1) == 1)145return true;146147if (!tfp->quiet) {148DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",149addr, adapter->name, dvo->slave_addr);150}151152return false;153}154155static int tfp410_getid(struct intel_dvo_device *dvo, int addr)156{157uint8_t ch1, ch2;158159if (tfp410_readb(dvo, addr+0, &ch1) &&160tfp410_readb(dvo, addr+1, &ch2))161return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);162163return -1;164}165166/* Ti TFP410 driver for chip on i2c bus */167static bool tfp410_init(struct intel_dvo_device *dvo,168struct i2c_adapter *adapter)169{170/* this will detect the tfp410 chip on the specified i2c bus */171struct tfp410_priv *tfp;172int id;173174tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);175if (tfp == NULL)176return false;177178dvo->i2c_bus = adapter;179dvo->dev_priv = tfp;180tfp->quiet = true;181182if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {183DRM_DEBUG_KMS("tfp410 not detected got VID %X: from %s "184"Slave %d.\n",185id, adapter->name, dvo->slave_addr);186goto out;187}188189if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {190DRM_DEBUG_KMS("tfp410 not detected got DID %X: from %s "191"Slave %d.\n",192id, adapter->name, dvo->slave_addr);193goto out;194}195tfp->quiet = false;196return true;197out:198kfree(tfp);199return false;200}201202static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)203{204enum drm_connector_status ret = connector_status_disconnected;205uint8_t ctl2;206207if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {208if (ctl2 & TFP410_CTL_2_RSEN)209ret = connector_status_connected;210else211ret = connector_status_disconnected;212}213214return ret;215}216217static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,218struct drm_display_mode *mode)219{220return MODE_OK;221}222223static void tfp410_mode_set(struct intel_dvo_device *dvo,224struct drm_display_mode *mode,225struct drm_display_mode *adjusted_mode)226{227/* As long as the basics are set up, since we don't have clock dependencies228* in the mode setup, we can just leave the registers alone and everything229* will work fine.230*/231/* don't do much */232return;233}234235/* set the tfp410 power state */236static void tfp410_dpms(struct intel_dvo_device *dvo, int mode)237{238uint8_t ctl1;239240if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))241return;242243if (mode == DRM_MODE_DPMS_ON)244ctl1 |= TFP410_CTL_1_PD;245else246ctl1 &= ~TFP410_CTL_1_PD;247248tfp410_writeb(dvo, TFP410_CTL_1, ctl1);249}250251static void tfp410_dump_regs(struct intel_dvo_device *dvo)252{253uint8_t val, val2;254255tfp410_readb(dvo, TFP410_REV, &val);256DRM_LOG_KMS("TFP410_REV: 0x%02X\n", val);257tfp410_readb(dvo, TFP410_CTL_1, &val);258DRM_LOG_KMS("TFP410_CTL1: 0x%02X\n", val);259tfp410_readb(dvo, TFP410_CTL_2, &val);260DRM_LOG_KMS("TFP410_CTL2: 0x%02X\n", val);261tfp410_readb(dvo, TFP410_CTL_3, &val);262DRM_LOG_KMS("TFP410_CTL3: 0x%02X\n", val);263tfp410_readb(dvo, TFP410_USERCFG, &val);264DRM_LOG_KMS("TFP410_USERCFG: 0x%02X\n", val);265tfp410_readb(dvo, TFP410_DE_DLY, &val);266DRM_LOG_KMS("TFP410_DE_DLY: 0x%02X\n", val);267tfp410_readb(dvo, TFP410_DE_CTL, &val);268DRM_LOG_KMS("TFP410_DE_CTL: 0x%02X\n", val);269tfp410_readb(dvo, TFP410_DE_TOP, &val);270DRM_LOG_KMS("TFP410_DE_TOP: 0x%02X\n", val);271tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);272tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);273DRM_LOG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);274tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);275tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);276DRM_LOG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);277tfp410_readb(dvo, TFP410_H_RES_LO, &val);278tfp410_readb(dvo, TFP410_H_RES_HI, &val2);279DRM_LOG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val);280tfp410_readb(dvo, TFP410_V_RES_LO, &val);281tfp410_readb(dvo, TFP410_V_RES_HI, &val2);282DRM_LOG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);283}284285static void tfp410_destroy(struct intel_dvo_device *dvo)286{287struct tfp410_priv *tfp = dvo->dev_priv;288289if (tfp) {290kfree(tfp);291dvo->dev_priv = NULL;292}293}294295struct intel_dvo_dev_ops tfp410_ops = {296.init = tfp410_init,297.detect = tfp410_detect,298.mode_valid = tfp410_mode_valid,299.mode_set = tfp410_mode_set,300.dpms = tfp410_dpms,301.dump_regs = tfp410_dump_regs,302.destroy = tfp410_destroy,303};304305306