/*
* Copyright(c) 2016, Analogix Semiconductor.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Based on anx7808 driver obtained from chromeos with copyright:
* Copyright(c) 2013, Google Inc.
*
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/types.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_edid.h>
#include "analogix-anx78xx.h"
#define I2C_NUM_ADDRESSES 5
#define I2C_IDX_TX_P0 0
#define I2C_IDX_TX_P1 1
#define I2C_IDX_TX_P2 2
#define I2C_IDX_RX_P0 3
#define I2C_IDX_RX_P1 4
#define XTAL_CLK 270 /* 27M */
#define AUX_CH_BUFFER_SIZE 16
#define AUX_WAIT_TIMEOUT_MS 15
static const u8 anx78xx_i2c_addresses[] = {
[I2C_IDX_TX_P0] = TX_P0,
[I2C_IDX_TX_P1] = TX_P1,
[I2C_IDX_TX_P2] = TX_P2,
[I2C_IDX_RX_P0] = RX_P0,
[I2C_IDX_RX_P1] = RX_P1,
};
struct anx78xx_platform_data {
struct regulator *dvdd10;
struct gpio_desc *gpiod_hpd;
struct gpio_desc *gpiod_pd;
struct gpio_desc *gpiod_reset;
int hpd_irq;
int intp_irq;
};
struct anx78xx {
struct drm_dp_aux aux;
struct drm_bridge bridge;
struct i2c_client *client;
struct edid *edid;
struct drm_connector connector;
struct drm_dp_link link;
struct anx78xx_platform_data pdata;
struct mutex lock;
/*
* I2C Slave addresses of ANX7814 are mapped as TX_P0, TX_P1, TX_P2,
* RX_P0 and RX_P1.
*/
struct i2c_client *i2c_dummy[I2C_NUM_ADDRESSES];
struct regmap *map[I2C_NUM_ADDRESSES];
u16 chipid;
u8 dpcd[DP_RECEIVER_CAP_SIZE];
bool powered;
};
static inline struct anx78xx *connector_to_anx78xx(struct drm_connector *c)
{
return container_of(c, struct anx78xx, connector);
}
static inline struct anx78xx *bridge_to_anx78xx(struct drm_bridge *bridge)
{
return container_of(bridge, struct anx78xx, bridge);
}
static int anx78xx_set_bits(struct regmap *map, u8 reg, u8 mask)
{
return regmap_update_bits(map, reg, mask, mask);
}
static int anx78xx_clear_bits(struct regmap *map, u8 reg, u8 mask)
{
return regmap_update_bits(map, reg, mask, 0);
}
static bool anx78xx_aux_op_finished(struct anx78xx *anx78xx)
{
unsigned int value;
int err;
err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL2_REG,
&value);
if (err < 0)
return false;
return (value & SP_AUX_EN) == 0;
}
static int anx78xx_aux_wait(struct anx78xx *anx78xx)
{
unsigned long timeout;
unsigned int status;
int err;
timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
while (!anx78xx_aux_op_finished(anx78xx)) {
if (time_after(jiffies, timeout)) {
if (!anx78xx_aux_op_finished(anx78xx)) {
DRM_ERROR("Timed out waiting AUX to finish\n");
return -ETIMEDOUT;
}
break;
}
usleep_range(1000, 2000);
}
/* Read the AUX channel access status */
err = regmap_read(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_CH_STATUS_REG,
&status);
if (err < 0) {
DRM_ERROR("Failed to read from AUX channel: %d\n", err);
return err;
}
if (status & SP_AUX_STATUS) {
DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n",
status);
return -ETIMEDOUT;
}
return 0;
}
static int anx78xx_aux_address(struct anx78xx *anx78xx, unsigned int addr)
{
int err;
err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_7_0_REG,
addr & 0xff);
if (err)
return err;
err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_AUX_ADDR_15_8_REG,
(addr & 0xff00) >> 8);
if (err)
return err;
/*
* DP AUX CH Address Register #2, only update bits[3:0]
* [7:4] RESERVED
* [3:0] AUX_ADDR[19:16], Register control AUX CH address.
*/
err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0],
SP_AUX_ADDR_19_16_REG,
SP_AUX_ADDR_19_16_MASK,
(addr & 0xf0000) >> 16);
if (err)
return err;
return 0;
}
static ssize_t anx78xx_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
struct anx78xx *anx78xx = container_of(aux, struct anx78xx, aux);
u8 ctrl1 = msg->request;
u8 ctrl2 = SP_AUX_EN;
u8 *buffer = msg->buffer;
int err;
/* The DP AUX transmit and receive buffer has 16 bytes. */
if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
return -E2BIG;
/* Zero-sized messages specify address-only transactions. */
if (msg->size < 1)
ctrl2 |= SP_ADDR_ONLY;
else /* For non-zero-sized set the length field. */
ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;
if ((msg->request & DP_AUX_I2C_READ) == 0) {
/* When WRITE | MOT write values to data buffer */
err = regmap_bulk_write(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_BUF_DATA0_REG, buffer,
msg->size);
if (err)
return err;
}
/* Write address and request */
err = anx78xx_aux_address(anx78xx, msg->address);
if (err)
return err;
err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], SP_DP_AUX_CH_CTRL1_REG,
ctrl1);
if (err)
return err;
/* Start transaction */
err = regmap_update_bits(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY |
SP_AUX_EN, ctrl2);
if (err)
return err;
err = anx78xx_aux_wait(anx78xx);
if (err)
return err;
msg->reply = DP_AUX_I2C_REPLY_ACK;
if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
/* Read values from data buffer */
err = regmap_bulk_read(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_BUF_DATA0_REG, buffer,
msg->size);
if (err)
return err;
}
err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P0],
SP_DP_AUX_CH_CTRL2_REG, SP_ADDR_ONLY);
if (err)
return err;
return msg->size;
}
static int anx78xx_set_hpd(struct anx78xx *anx78xx)
{
int err;
err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_RX_P0],
SP_TMDS_CTRL_BASE + 7, SP_PD_RT);
if (err)
return err;
err = anx78xx_set_bits(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL3_REG,
SP_HPD_OUT);
if (err)
return err;
return 0;
}
static int anx78xx_clear_hpd(struct anx78xx *anx78xx)
{
int err;
err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_TX_P2], SP_VID_CTRL3_REG,
SP_HPD_OUT);
if (err)
return err;
err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
SP_TMDS_CTRL_BASE + 7, SP_PD_RT);
if (err)
return err;
return 0;
}
static const struct reg_sequence tmds_phy_initialization[] = {
{ SP_TMDS_CTRL_BASE + 1, 0x90 },
{ SP_TMDS_CTRL_BASE + 2, 0xa9 },
{ SP_TMDS_CTRL_BASE + 6, 0x92 },
{ SP_TMDS_CTRL_BASE + 7, 0x80 },
{ SP_TMDS_CTRL_BASE + 20, 0xf2 },
{ SP_TMDS_CTRL_BASE + 22, 0xc4 },
{ SP_TMDS_CTRL_BASE + 23, 0x18 },
};
static int anx78xx_rx_initialization(struct anx78xx *anx78xx)
{
int err;
err = regmap_write(anx78xx->map[I2C_IDX_RX_P0], SP_HDMI_MUTE_CTRL_REG,
SP_AUD_MUTE | SP_VID_MUTE);
if (err)
return err;
err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0], SP_CHIP_CTRL_REG,
SP_MAN_HDMI5V_DET | SP_PLLLOCK_CKDT_EN |
SP_DIGITAL_CKDT_EN);
if (err)
return err;
err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
SP_SOFTWARE_RESET1_REG, SP_HDCP_MAN_RST |
SP_SW_MAN_RST | SP_TMDS_RST | SP_VIDEO_RST);
if (err)
return err;
err = anx78xx_clear_bits(anx78xx->map[I2C_IDX_RX_P0],
SP_SOFTWARE_RESET1_REG, SP_HDCP_MAN_RST |
SP_SW_MAN_RST | SP_TMDS_RST | SP_VIDEO_RST);
if (err)
return err;
/* Sync detect change, GP set mute */
err = anx78xx_set_bits(anx78xx->map[I2C_IDX_RX_P0],
SP_AUD_EXCEPTION_ENABLE_BASE + 1, BI
|