/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/hdmi.h>
#include <linux/module.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_encoder_slave.h>
#include <drm/drm_edid.h>
#include <drm/i2c/tda998x.h>
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
struct tda998x_priv {
struct i2c_client *cec;
uint16_t rev;
uint8_t current_page;
int dpms;
bool is_hdmi_sink;
u8 vip_cntrl_0;
u8 vip_cntrl_1;
u8 vip_cntrl_2;
struct tda998x_encoder_params params;
};
#define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv)
/* The TDA9988 series of devices use a paged register scheme.. to simplify
* things we encode the page # in upper bits of the register #. To read/
* write a given register, we need to make sure CURPAGE register is set
* appropriately. Which implies reads/writes are not atomic. Fun!
*/
#define REG(page, addr) (((page) << 8) | (addr))
#define REG2ADDR(reg) ((reg) & 0xff)
#define REG2PAGE(reg) (((reg) >> 8) & 0xff)
#define REG_CURPAGE 0xff /* write */
/* Page 00h: General Control */
#define REG_VERSION_LSB REG(0x00, 0x00) /* read */
#define REG_MAIN_CNTRL0 REG(0x00, 0x01) /* read/write */
# define MAIN_CNTRL0_SR (1 << 0)
# define MAIN_CNTRL0_DECS (1 << 1)
# define MAIN_CNTRL0_DEHS (1 << 2)
# define MAIN_CNTRL0_CECS (1 << 3)
# define MAIN_CNTRL0_CEHS (1 << 4)
# define MAIN_CNTRL0_SCALER (1 << 7)
#define REG_VERSION_MSB REG(0x00, 0x02) /* read */
#define REG_SOFTRESET REG(0x00, 0x0a) /* write */
# define SOFTRESET_AUDIO (1 << 0)
# define SOFTRESET_I2C_MASTER (1 << 1)
#define REG_DDC_DISABLE REG(0x00, 0x0b) /* read/write */
#define REG_CCLK_ON REG(0x00, 0x0c) /* read/write */
#define REG_I2C_MASTER REG(0x00, 0x0d) /* read/write */
# define I2C_MASTER_DIS_MM (1 << 0)
# define I2C_MASTER_DIS_FILT (1 << 1)
# define I2C_MASTER_APP_STRT_LAT (1 << 2)
#define REG_FEAT_POWERDOWN REG(0x00, 0x0e) /* read/write */
# define FEAT_POWERDOWN_SPDIF (1 << 3)
#define REG_INT_FLAGS_0 REG(0x00, 0x0f) /* read/write */
#define REG_INT_FLAGS_1 REG(0x00, 0x10) /* read/write */
#define REG_INT_FLAGS_2 REG(0x00, 0x11) /* read/write */
# define INT_FLAGS_2_EDID_BLK_RD (1 << 1)
#define REG_ENA_ACLK REG(0x00, 0x16) /* read/write */
#define REG_ENA_VP_0 REG(0x00, 0x18) /* read/write */
#define REG_ENA_VP_1 REG(0x00, 0x19) /* read/write */
#define REG_ENA_VP_2 REG(0x00, 0x1a) /* read/write */
#define REG_ENA_AP REG(0x00, 0x1e) /* read/write */
#define REG_VIP_CNTRL_0 REG(0x00, 0x20) /* write */
# define VIP_CNTRL_0_MIRR_A (1 << 7)
# define VIP_CNTRL_0_SWAP_A(x) (((x) & 7) << 4)
# define VIP_CNTRL_0_MIRR_B (1 << 3)
# define VIP_CNTRL_0_SWAP_B(x) (((x) & 7) << 0)
#define REG_VIP_CNTRL_1 REG(0x00, 0x21) /* write */
# define VIP_CNTRL_1_MIRR_C (1 << 7)
# define VIP_CNTRL_1_SWAP_C(x) (((x) & 7) << 4)
# define VIP_CNTRL_1_MIRR_D (1 << 3)
# define VIP_CNTRL_1_SWAP_D(x) (((x) & 7) << 0)
#define REG_VIP_CNTRL_2 REG(0x00, 0x22) /* write */
# define VIP_CNTRL_2_MIRR_E (1 << 7)
# define VIP_CNTRL_2_SWAP_E(x) (((x) & 7) << 4)
# define VIP_CNTRL_2_MIRR_F (1 << 3)
# define VIP_CNTRL_2_SWAP_F(x) (((x) & 7) << 0)
#define REG_VIP_CNTRL_3 REG(0x00, 0x23) /* write */
# define VIP_CNTRL_3_X_TGL (1 << 0)
# define VIP_CNTRL_3_H_TGL (1 << 1)
# define VIP_CNTRL_3_V_TGL (1 << 2)
# define VIP_CNTRL_3_EMB (1 << 3)
# define VIP_CNTRL_3_SYNC_DE (1 << 4)
# define VIP_CNTRL_3_SYNC_HS (1 << 5)
# define VIP_CNTRL_3_DE_INT (1 << 6)
# define VIP_CNTRL_3_EDGE (1 << 7)
#define REG_VIP_CNTRL_4 REG(0x00, 0x24) /* write */
# define VIP_CNTRL_4_BLC(x) (((x) & 3) << 0)
# define VIP_CNTRL_4_BLANKIT(x) (((x) & 3) << 2)
# define VIP_CNTRL_4_CCIR656 (1 << 4)
# define VIP_CNTRL_4_656_ALT (1 << 5)
# define VIP_CNTRL_4_TST_656 (1 << 6)
# define VIP_CNTRL_4_TST_PAT (1 << 7)
#define REG_VIP_CNTRL_5 REG(0x00, 0x25) /* write */
# define VIP_CNTRL_5_CKCASE (1 << 0)
# define VIP_CNTRL_5_SP_CNT(x) (((x) & 3) << 1)
#define REG_MUX_AP REG(0x00, 0x26) /* read/write */
#define REG_MUX_VP_VIP_OUT REG(0x00, 0x27) /* read/write */
#define REG_MAT_CONTRL REG(0x00, 0x80) /* write */
# define MAT_CONTRL_MAT_SC(x) (((x) & 3) << 0)
# define MAT_CONTRL_MAT_BP (1 << 2)
#define REG_VIDFORMAT REG(0x00, 0xa0) /* write */
#define REG_REFPIX_MSB REG(0x00, 0xa1) /* write */
#define REG_REFPIX_LSB REG(0x00, 0xa2) /* write */
#define REG_REFLINE_MSB REG(0x00, 0xa3) /* write */
#define REG_REFLINE_LSB REG(0x00, 0xa4) /* write */
#define REG_NPIX_MSB REG(0x00, 0xa5) /* write */
#define REG_NPIX_LSB REG(0x00, 0xa6) /* write */
#define REG_NLINE_MSB REG(0x00, 0xa7) /* write */
#define REG_NLINE_LSB REG(0x00, 0xa8) /* write */
#define REG_VS_LINE_STRT_1_MSB REG(0x00, 0xa9) /* write */
#define REG_VS_LINE_STRT_1_LSB REG(0x00, 0xaa) /* write */
#define REG_VS_PIX_STRT_1_MSB REG(0x00, 0xab) /* write */
#define REG_VS_PIX_STRT_1_LSB REG(0x00, 0xac) /* write */
#define REG_VS_LINE_END_1_MSB REG(0x00, 0xad) /* write */
#define REG_VS_LINE_END_1_LSB REG(0x00, 0xae) /* write */
#define REG_VS_PIX_END_1_MSB REG(0x00, 0xaf) /* write */
#define REG_VS_PIX_END_1_LSB REG(0x00, 0xb0) /* write */
#define REG_VS_LINE_STRT_2_MSB REG(0x00, 0xb1) /* write */
#define REG_VS_LINE_STRT_2_LSB REG(0x00, 0xb2) /* write */
#define REG_VS_PIX_STRT_2_MSB REG(0x00, 0xb3) /* write */
#define REG_VS_PIX_STRT_2_LSB REG(0x00, 0xb4) /* write */
#define REG_VS_LINE_END_2_MSB REG(0x00, 0xb5) /* write */
#define REG_VS_LINE_END_2_LSB REG(0x00, 0xb6) /* write */
#define REG_VS_PIX_END_2_MSB REG(0x00, 0xb7) /* write */
#define REG_VS_PIX_END_2_LSB REG(0x00, 0xb8) /* write */
#define REG_HS_PIX_START_MSB REG(0x00, 0xb9) /* write */
#define REG_HS_PIX_START_LSB REG(0x00, 0xba) /* write */
#define REG_HS_PIX_STOP_MSB REG(0x00, 0xbb) /* write */
#define REG_HS_PIX_STOP_LSB REG(0x00, 0xbc) /* write */
#define REG_VWIN_START_1_MSB REG(