From 7af0f84305d7b4604df746994a639065a6991bbd Mon Sep 17 00:00:00 2001 From: Jeremy Thorpe Date: Thu, 2 May 2013 10:52:12 -0700 Subject: [PATCH] CHROMIUM: drm/anx7808: Add Aux channel reading. Adds register writing functions and helper functions for setting and clearing bits. Adds aux channel read function. Adds DPCD read function. Adds a code to print the firmware version of an HDMI dongle, when debugging is on. BUG=chrome-os-partner:16196 TEST=With verbose logging, see "ANX7730 Firmware version 0x0d." Change-Id: I71f0778b9226685d0645234466517818330e61f3 Signed-off-by: Jeremy Thorpe Reviewed-on: https://gerrit.chromium.org/gerrit/48861 --- drivers/gpu/drm/bridge/anx7808.c | 118 ++++++++++++++++++++++++++- drivers/gpu/drm/bridge/anx7808regs.h | 5 ++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/anx7808.c b/drivers/gpu/drm/bridge/anx7808.c index cd999eeed218..b5e6f6bf115e 100644 --- a/drivers/gpu/drm/bridge/anx7808.c +++ b/drivers/gpu/drm/bridge/anx7808.c @@ -26,6 +26,8 @@ #include "anx7808regs.h" #define ANX7808_DEVICE_ID 0x7808 +#define AUX_WAIT_MS 100 +#define AUX_BUFFER_SIZE 0x10 struct anx7808_data { int pd_gpio; @@ -73,7 +75,7 @@ static int anx7808_read_reg(struct anx7808_data *anx7808, uint16_t addr, return -EINVAL; } - ret = i2c_smbus_read_byte_data(client, addr & 0xff); + ret = i2c_smbus_read_byte_data(client, addr & 0xFF); if (ret < 0) { DRM_ERROR("Failed to read i2c addr=%04x.\n", addr); *value = 0; @@ -83,6 +85,45 @@ static int anx7808_read_reg(struct anx7808_data *anx7808, uint16_t addr, return 0; } +static int anx7808_write_reg(struct anx7808_data *anx7808, uint16_t addr, + uint8_t value) +{ + int ret = 0; + struct i2c_client *client = anx7808_addr_to_client(anx7808, addr); + + if (client == NULL) + return -EINVAL; + + ret = i2c_smbus_write_byte_data(client, addr & 0xFF, value); + if (ret < 0) { + DRM_ERROR("Failed to write i2c addr=%04x.\n", addr); + return -EIO; + } + return 0; +} + +static int anx7808_set_bits(struct anx7808_data *anx7808, uint16_t addr, + uint8_t bits) +{ + uint8_t c; + int ret = 0; + ret = anx7808_read_reg(anx7808, addr, &c); + if (ret) + return ret; + return anx7808_write_reg(anx7808, addr, c | bits); +} + +static int anx7808_clear_bits(struct anx7808_data *anx7808, uint16_t addr, + uint8_t bits) +{ + uint8_t c; + int ret = 0; + ret = anx7808_read_reg(anx7808, addr, &c); + if (ret) + return ret; + return anx7808_write_reg(anx7808, addr, c & (~bits)); +} + static int anx7808_power_on(struct anx7808_data *anx7808) { int ret = 0; @@ -140,10 +181,85 @@ static int anx7808_chip_located(struct anx7808_data *anx7808) return 0; } +static int anx7808_aux_wait(struct anx7808_data *anx7808) +{ + int err; + uint8_t status; + unsigned long start = jiffies; + + while ((jiffies - start) <= msecs_to_jiffies(AUX_WAIT_MS)) { + err = anx7808_read_reg(anx7808, SP_TX_AUX_STATUS, &status); + if (err) + return err; + if (!(status & AUX_BUSY)) + break; + usleep_range(100, 200); + } + + if (status) { + DRM_ERROR("Failed to read AUX channel: 0x%02x\n", status); + return -EIO; + } + return 0; +} + +static int anx7808_aux_read(struct anx7808_data *anx7808, uint32_t addr, + uint8_t cmd, uint8_t count, uint8_t *pBuf) +{ + int i; + int err = 0; + int addrl = (addr >> 0) & 0xFF; + int addrm = (addr >> 8) & 0xFF; + int addrh = (addr >> 16) & 0x0F; + + if (count > AUX_BUFFER_SIZE) + return -EINVAL; + + err |= anx7808_write_reg(anx7808, SP_TX_BUF_DATA_COUNT_REG, 0x80); + err |= anx7808_write_reg(anx7808, SP_TX_AUX_CTRL_REG, + ((count - 1) << 4) | cmd); + err |= anx7808_write_reg(anx7808, SP_TX_AUX_ADDR_7_0_REG, addrl); + err |= anx7808_write_reg(anx7808, SP_TX_AUX_ADDR_15_8_REG, addrm); + err |= anx7808_write_reg(anx7808, SP_TX_AUX_ADDR_19_16_REG, addrh); + err |= anx7808_set_bits(anx7808, SP_TX_AUX_CTRL_REG2, AUX_OP_EN); + if (err) + return -EIO; + usleep_range(2000, 4000); + + err = anx7808_aux_wait(anx7808); + if (err) + return err; + + for (i = 0; i < count; i++) + err |= anx7808_read_reg(anx7808, SP_TX_BUF_DATA_0_REG + i, + pBuf + i); + if (err) + return -EIO; + + return 0; +} + +static int anx7808_aux_dpcd_read(struct anx7808_data *anx7808, uint32_t addr, + uint8_t count, uint8_t *pBuf) +{ + return anx7808_aux_read(anx7808, addr, AUX_DPCD, count, pBuf); +} + static irqreturn_t anx7808_cable_det_isr(int irq, void *data) { + struct anx7808_data *anx7808 = data; + uint8_t version; + DRM_INFO("Detected cable insertion.\n"); + anx7808_power_on(anx7808); + anx7808_clear_bits(anx7808, SP_POWERD_CTRL_REG, REGISTER_PD); + anx7808_clear_bits(anx7808, SP_POWERD_CTRL_REG, TOTAL_PD); + anx7808_clear_bits(anx7808, SP_TX_VID_CTRL1_REG, VIDEO_MUTE); + + anx7808_aux_dpcd_read(anx7808, US_COMM_2, 1, &version); + DRM_DEBUG_KMS("ANX7730 Firmware version 0x%02x.\n", (version & 0x7f)); + return IRQ_HANDLED; } diff --git a/drivers/gpu/drm/bridge/anx7808regs.h b/drivers/gpu/drm/bridge/anx7808regs.h index fe1549bdcd1e..ff1aa5796573 100644 --- a/drivers/gpu/drm/bridge/anx7808regs.h +++ b/drivers/gpu/drm/bridge/anx7808regs.h @@ -645,6 +645,11 @@ #define SP_TX_AUD_INTERFACE_CTRL5 0x7A68 #define SP_TX_AUD_INTERFACE_CTRL6 0x7A69 +/***************************************************************/ +/*AUX channel*/ + +#define AUX_DPCD 0x09 + /***************************************************************/ /*Definition of DPCD*/ -- 2.20.1