1450N/A/*
1450N/A * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
1450N/A */
1450N/A/*
1450N/A * Copyright (c) 2012, 2013, Intel Corporation. All rights reserved.
1450N/A */
1450N/A/**************************************************************************
1450N/A
1450N/ACopyright © 2006 Dave Airlie
1450N/A
1450N/AAll Rights Reserved.
1450N/A
1450N/APermission is hereby granted, free of charge, to any person obtaining a
1450N/Acopy of this software and associated documentation files (the
1450N/A"Software"), to deal in the Software without restriction, including
1450N/Awithout limitation the rights to use, copy, modify, merge, publish,
1450N/Adistribute, sub license, and/or sell copies of the Software, and to
1450N/Apermit persons to whom the Software is furnished to do so, subject to
1450N/Athe following conditions:
1450N/A
1450N/AThe above copyright notice and this permission notice (including the
1450N/Anext paragraph) shall be included in all copies or substantial portions
1450N/Aof the Software.
1450N/A
1450N/ATHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1450N/AOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1450N/AMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
1450N/AIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1450N/AANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1450N/ATORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1450N/ASOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1450N/A
1450N/A**************************************************************************/
1450N/A
1450N/A#include "dvo.h"
1450N/A
1450N/A#define SIL164_VID 0x0001
1450N/A#define SIL164_DID 0x0006
1450N/A
1450N/A#define SIL164_VID_LO 0x00
1450N/A#define SIL164_VID_HI 0x01
1450N/A#define SIL164_DID_LO 0x02
1450N/A#define SIL164_DID_HI 0x03
1450N/A#define SIL164_REV 0x04
1450N/A#define SIL164_RSVD 0x05
1450N/A#define SIL164_FREQ_LO 0x06
1450N/A#define SIL164_FREQ_HI 0x07
1450N/A
1450N/A#define SIL164_REG8 0x08
1450N/A#define SIL164_8_VEN (1<<5)
1450N/A#define SIL164_8_HEN (1<<4)
1450N/A#define SIL164_8_DSEL (1<<3)
1450N/A#define SIL164_8_BSEL (1<<2)
1450N/A#define SIL164_8_EDGE (1<<1)
1450N/A#define SIL164_8_PD (1<<0)
1450N/A
1450N/A#define SIL164_REG9 0x09
1450N/A#define SIL164_9_VLOW (1<<7)
1450N/A#define SIL164_9_MSEL_MASK (0x7<<4)
1450N/A#define SIL164_9_TSEL (1<<3)
1450N/A#define SIL164_9_RSEN (1<<2)
1450N/A#define SIL164_9_HTPLG (1<<1)
1450N/A#define SIL164_9_MDI (1<<0)
1450N/A
1450N/A#define SIL164_REGC 0x0c
1450N/A
1450N/Astruct sil164_priv {
1450N/A //I2CDevRec d;
1450N/A bool quiet;
1450N/A};
1450N/A
1450N/A#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
1450N/A
1450N/Astatic bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
1450N/A{
1450N/A struct sil164_priv *sil = dvo->dev_priv;
1450N/A struct i2c_adapter *adapter = dvo->i2c_bus;
1450N/A u8 out_buf[2];
1450N/A u8 in_buf[2];
1450N/A
1450N/A struct i2c_msg msgs[] = {
1450N/A {
1450N/A .addr = dvo->slave_addr,
1450N/A .flags = 0,
1450N/A .len = 1,
1450N/A .buf = out_buf,
1450N/A },
1450N/A {
1450N/A .addr = dvo->slave_addr,
1450N/A .flags = I2C_M_RD,
1450N/A .len = 1,
1450N/A .buf = in_buf,
1450N/A }
1450N/A };
1450N/A
1450N/A out_buf[0] = (u8) addr;
1450N/A out_buf[1] = 0;
1450N/A
1450N/A if (i2c_transfer(adapter, msgs, 2) == 2) {
1450N/A *ch = in_buf[0];
1450N/A return true;
1450N/A };
1450N/A
1450N/A if (!sil->quiet) {
1450N/A DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
1450N/A addr, adapter->name, dvo->slave_addr);
1450N/A }
1450N/A return false;
1450N/A}
1450N/A
1450N/Astatic bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
1450N/A{
1450N/A struct sil164_priv *sil= dvo->dev_priv;
1450N/A struct i2c_adapter *adapter = dvo->i2c_bus;
1450N/A uint8_t out_buf[2];
1450N/A struct i2c_msg msg = {
1450N/A .addr = dvo->slave_addr,
1450N/A .flags = 0,
1450N/A .len = 2,
1450N/A .buf = out_buf,
1450N/A };
1450N/A
1450N/A out_buf[0] = (uint8_t) addr;
1450N/A out_buf[1] = ch;
1450N/A
1450N/A if (i2c_transfer(adapter, &msg, 1) == 1)
1450N/A return true;
1450N/A
1450N/A if (!sil->quiet) {
1450N/A DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
1450N/A addr, adapter->name, dvo->slave_addr);
1450N/A }
1450N/A
1450N/A return false;
1450N/A}
1450N/A
1450N/A/* Silicon Image 164 driver for chip on i2c bus */
1450N/Astatic bool sil164_init(struct intel_dvo_device *dvo,
1450N/A struct i2c_adapter *adapter)
1450N/A{
1450N/A /* this will detect the SIL164 chip on the specified i2c bus */
1450N/A struct sil164_priv *sil;
1450N/A unsigned char ch;
1450N/A
1450N/A sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
1450N/A if (sil == NULL)
1450N/A return false;
1450N/A
1450N/A dvo->i2c_bus = adapter;
1450N/A dvo->dev_priv = sil;
1450N/A sil->quiet = true;
1450N/A
1450N/A if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
1450N/A goto out;
1450N/A
1450N/A if (ch != (SIL164_VID & 0xff)) {
1450N/A DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
1450N/A ch, adapter->name, dvo->slave_addr);
1450N/A goto out;
1450N/A }
1450N/A
1450N/A if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
1450N/A goto out;
1450N/A
1450N/A if (ch != (SIL164_DID & 0xff)) {
1450N/A DRM_DEBUG_KMS("sil164 not detected got %d: from %s Slave %d.\n",
1450N/A ch, adapter->name, dvo->slave_addr);
1450N/A goto out;
1450N/A }
1450N/A sil->quiet = false;
1450N/A
1450N/A DRM_DEBUG_KMS("init sil164 dvo controller successfully!\n");
1450N/A return true;
1450N/A
1450N/Aout:
1450N/A kfree(sil, sizeof(struct sil164_priv));
1450N/A return false;
1450N/A}
1450N/A
1450N/Astatic enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
1450N/A{
1450N/A uint8_t reg9;
1450N/A
1450N/A (void) sil164_readb(dvo, SIL164_REG9, &reg9);
1450N/A
1450N/A if (reg9 & SIL164_9_HTPLG)
1450N/A return connector_status_connected;
1450N/A else
1450N/A return connector_status_disconnected;
1450N/A}
1450N/A
1450N/A/* LINTED */
1450N/Astatic int sil164_mode_valid(struct intel_dvo_device *dvo,
1450N/A /* LINTED */
1450N/A struct drm_display_mode *mode)
1450N/A{
1450N/A return MODE_OK;
1450N/A}
1450N/A
1450N/A/* LINTED */
1450N/Astatic void sil164_mode_set(struct intel_dvo_device *dvo,
1450N/A /* LINTED */
1450N/A struct drm_display_mode *mode,
1450N/A /* LINTED */
1450N/A struct drm_display_mode *adjusted_mode)
1450N/A{
1450N/A /* As long as the basics are set up, since we don't have clock
1450N/A * dependencies in the mode setup, we can just leave the
1450N/A * registers alone and everything will work fine.
1450N/A */
1450N/A /* recommended programming sequence from doc */
1450N/A /*sil164_writeb(sil, 0x08, 0x30);
1450N/A sil164_writeb(sil, 0x09, 0x00);
1450N/A sil164_writeb(sil, 0x0a, 0x90);
1450N/A sil164_writeb(sil, 0x0c, 0x89);
1450N/A sil164_writeb(sil, 0x08, 0x31);*/
1450N/A /* don't do much */
1450N/A return;
1450N/A}
1450N/A
1450N/A/* set the SIL164 power state */
1450N/Astatic void sil164_dpms(struct intel_dvo_device *dvo, bool enable)
1450N/A{
1450N/A int ret;
1450N/A unsigned char ch;
1450N/A
1450N/A ret = sil164_readb(dvo, SIL164_REG8, &ch);
1450N/A if (ret == false)
1450N/A return;
1450N/A
1450N/A if (enable)
1450N/A ch |= SIL164_8_PD;
1450N/A else
1450N/A ch &= ~SIL164_8_PD;
1450N/A
1450N/A (void) sil164_writeb(dvo, SIL164_REG8, ch);
1450N/A return;
1450N/A}
1450N/A
1450N/Astatic bool sil164_get_hw_state(struct intel_dvo_device *dvo)
1450N/A{
1450N/A int ret;
1450N/A unsigned char ch;
1450N/A
1450N/A ret = sil164_readb(dvo, SIL164_REG8, &ch);
1450N/A if (ret == false)
1450N/A return false;
1450N/A
1450N/A if (ch & SIL164_8_PD)
1450N/A return true;
1450N/A else
1450N/A return false;
1450N/A}
1450N/Astatic void sil164_dump_regs(struct intel_dvo_device *dvo)
1450N/A{
1450N/A uint8_t val;
1450N/A
1450N/A (void) sil164_readb(dvo, SIL164_FREQ_LO, &val);
1450N/A DRM_LOG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
1450N/A (void) sil164_readb(dvo, SIL164_FREQ_HI, &val);
1450N/A DRM_LOG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
1450N/A (void) sil164_readb(dvo, SIL164_REG8, &val);
1450N/A DRM_LOG_KMS("SIL164_REG8: 0x%02x\n", val);
1450N/A (void) sil164_readb(dvo, SIL164_REG9, &val);
1450N/A DRM_LOG_KMS("SIL164_REG9: 0x%02x\n", val);
1450N/A (void) sil164_readb(dvo, SIL164_REGC, &val);
1450N/A DRM_LOG_KMS("SIL164_REGC: 0x%02x\n", val);
1450N/A}
1450N/A
1450N/Astatic void sil164_destroy(struct intel_dvo_device *dvo)
1450N/A{
1450N/A struct sil164_priv *sil = dvo->dev_priv;
1450N/A
1450N/A if (sil) {
1450N/A kfree(sil, sizeof (struct sil164_priv));
1450N/A dvo->dev_priv = NULL;
1450N/A }
1450N/A}
1450N/A
1450N/Astruct intel_dvo_dev_ops sil164_ops = {
1450N/A .init = sil164_init,
1450N/A .detect = sil164_detect,
1450N/A .mode_valid = sil164_mode_valid,
1450N/A .mode_set = sil164_mode_set,
1450N/A .dpms = sil164_dpms,
1450N/A .get_hw_state = sil164_get_hw_state,
1450N/A .dump_regs = sil164_dump_regs,
1450N/A .destroy = sil164_destroy,
1450N/A};