162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012 Texas Instruments
462306a36Sopenharmony_ci * Author: Rob Clark <robdclark@gmail.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/component.h>
862306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
962306a36Sopenharmony_ci#include <linux/hdmi.h>
1062306a36Sopenharmony_ci#include <linux/i2c.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/platform_data/tda9950.h>
1362306a36Sopenharmony_ci#include <linux/irq.h>
1462306a36Sopenharmony_ci#include <sound/asoundef.h>
1562306a36Sopenharmony_ci#include <sound/hdmi-codec.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h>
1862306a36Sopenharmony_ci#include <drm/drm_bridge.h>
1962306a36Sopenharmony_ci#include <drm/drm_edid.h>
2062306a36Sopenharmony_ci#include <drm/drm_of.h>
2162306a36Sopenharmony_ci#include <drm/drm_print.h>
2262306a36Sopenharmony_ci#include <drm/drm_probe_helper.h>
2362306a36Sopenharmony_ci#include <drm/drm_simple_kms_helper.h>
2462306a36Sopenharmony_ci#include <drm/i2c/tda998x.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <media/cec-notifier.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cienum {
3162306a36Sopenharmony_ci	AUDIO_ROUTE_I2S,
3262306a36Sopenharmony_ci	AUDIO_ROUTE_SPDIF,
3362306a36Sopenharmony_ci	AUDIO_ROUTE_NUM
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct tda998x_audio_route {
3762306a36Sopenharmony_ci	u8 ena_aclk;
3862306a36Sopenharmony_ci	u8 mux_ap;
3962306a36Sopenharmony_ci	u8 aip_clksel;
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistruct tda998x_audio_settings {
4362306a36Sopenharmony_ci	const struct tda998x_audio_route *route;
4462306a36Sopenharmony_ci	struct hdmi_audio_infoframe cea;
4562306a36Sopenharmony_ci	unsigned int sample_rate;
4662306a36Sopenharmony_ci	u8 status[5];
4762306a36Sopenharmony_ci	u8 ena_ap;
4862306a36Sopenharmony_ci	u8 i2s_format;
4962306a36Sopenharmony_ci	u8 cts_n;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistruct tda998x_priv {
5362306a36Sopenharmony_ci	struct i2c_client *cec;
5462306a36Sopenharmony_ci	struct i2c_client *hdmi;
5562306a36Sopenharmony_ci	struct mutex mutex;
5662306a36Sopenharmony_ci	u16 rev;
5762306a36Sopenharmony_ci	u8 cec_addr;
5862306a36Sopenharmony_ci	u8 current_page;
5962306a36Sopenharmony_ci	bool is_on;
6062306a36Sopenharmony_ci	bool supports_infoframes;
6162306a36Sopenharmony_ci	bool sink_has_audio;
6262306a36Sopenharmony_ci	enum hdmi_quantization_range rgb_quant_range;
6362306a36Sopenharmony_ci	u8 vip_cntrl_0;
6462306a36Sopenharmony_ci	u8 vip_cntrl_1;
6562306a36Sopenharmony_ci	u8 vip_cntrl_2;
6662306a36Sopenharmony_ci	unsigned long tmds_clock;
6762306a36Sopenharmony_ci	struct tda998x_audio_settings audio;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	struct platform_device *audio_pdev;
7062306a36Sopenharmony_ci	struct mutex audio_mutex;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	struct mutex edid_mutex;
7362306a36Sopenharmony_ci	wait_queue_head_t wq_edid;
7462306a36Sopenharmony_ci	volatile int wq_edid_wait;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	struct work_struct detect_work;
7762306a36Sopenharmony_ci	struct timer_list edid_delay_timer;
7862306a36Sopenharmony_ci	wait_queue_head_t edid_delay_waitq;
7962306a36Sopenharmony_ci	bool edid_delay_active;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	struct drm_encoder encoder;
8262306a36Sopenharmony_ci	struct drm_bridge bridge;
8362306a36Sopenharmony_ci	struct drm_connector connector;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	u8 audio_port_enable[AUDIO_ROUTE_NUM];
8662306a36Sopenharmony_ci	struct tda9950_glue cec_glue;
8762306a36Sopenharmony_ci	struct gpio_desc *calib;
8862306a36Sopenharmony_ci	struct cec_notifier *cec_notify;
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define conn_to_tda998x_priv(x) \
9262306a36Sopenharmony_ci	container_of(x, struct tda998x_priv, connector)
9362306a36Sopenharmony_ci#define enc_to_tda998x_priv(x) \
9462306a36Sopenharmony_ci	container_of(x, struct tda998x_priv, encoder)
9562306a36Sopenharmony_ci#define bridge_to_tda998x_priv(x) \
9662306a36Sopenharmony_ci	container_of(x, struct tda998x_priv, bridge)
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* The TDA9988 series of devices use a paged register scheme.. to simplify
9962306a36Sopenharmony_ci * things we encode the page # in upper bits of the register #.  To read/
10062306a36Sopenharmony_ci * write a given register, we need to make sure CURPAGE register is set
10162306a36Sopenharmony_ci * appropriately.  Which implies reads/writes are not atomic.  Fun!
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define REG(page, addr) (((page) << 8) | (addr))
10562306a36Sopenharmony_ci#define REG2ADDR(reg)   ((reg) & 0xff)
10662306a36Sopenharmony_ci#define REG2PAGE(reg)   (((reg) >> 8) & 0xff)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define REG_CURPAGE               0xff                /* write */
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/* Page 00h: General Control */
11262306a36Sopenharmony_ci#define REG_VERSION_LSB           REG(0x00, 0x00)     /* read */
11362306a36Sopenharmony_ci#define REG_MAIN_CNTRL0           REG(0x00, 0x01)     /* read/write */
11462306a36Sopenharmony_ci# define MAIN_CNTRL0_SR           (1 << 0)
11562306a36Sopenharmony_ci# define MAIN_CNTRL0_DECS         (1 << 1)
11662306a36Sopenharmony_ci# define MAIN_CNTRL0_DEHS         (1 << 2)
11762306a36Sopenharmony_ci# define MAIN_CNTRL0_CECS         (1 << 3)
11862306a36Sopenharmony_ci# define MAIN_CNTRL0_CEHS         (1 << 4)
11962306a36Sopenharmony_ci# define MAIN_CNTRL0_SCALER       (1 << 7)
12062306a36Sopenharmony_ci#define REG_VERSION_MSB           REG(0x00, 0x02)     /* read */
12162306a36Sopenharmony_ci#define REG_SOFTRESET             REG(0x00, 0x0a)     /* write */
12262306a36Sopenharmony_ci# define SOFTRESET_AUDIO          (1 << 0)
12362306a36Sopenharmony_ci# define SOFTRESET_I2C_MASTER     (1 << 1)
12462306a36Sopenharmony_ci#define REG_DDC_DISABLE           REG(0x00, 0x0b)     /* read/write */
12562306a36Sopenharmony_ci#define REG_CCLK_ON               REG(0x00, 0x0c)     /* read/write */
12662306a36Sopenharmony_ci#define REG_I2C_MASTER            REG(0x00, 0x0d)     /* read/write */
12762306a36Sopenharmony_ci# define I2C_MASTER_DIS_MM        (1 << 0)
12862306a36Sopenharmony_ci# define I2C_MASTER_DIS_FILT      (1 << 1)
12962306a36Sopenharmony_ci# define I2C_MASTER_APP_STRT_LAT  (1 << 2)
13062306a36Sopenharmony_ci#define REG_FEAT_POWERDOWN        REG(0x00, 0x0e)     /* read/write */
13162306a36Sopenharmony_ci# define FEAT_POWERDOWN_PREFILT   BIT(0)
13262306a36Sopenharmony_ci# define FEAT_POWERDOWN_CSC       BIT(1)
13362306a36Sopenharmony_ci# define FEAT_POWERDOWN_SPDIF     (1 << 3)
13462306a36Sopenharmony_ci#define REG_INT_FLAGS_0           REG(0x00, 0x0f)     /* read/write */
13562306a36Sopenharmony_ci#define REG_INT_FLAGS_1           REG(0x00, 0x10)     /* read/write */
13662306a36Sopenharmony_ci#define REG_INT_FLAGS_2           REG(0x00, 0x11)     /* read/write */
13762306a36Sopenharmony_ci# define INT_FLAGS_2_EDID_BLK_RD  (1 << 1)
13862306a36Sopenharmony_ci#define REG_ENA_ACLK              REG(0x00, 0x16)     /* read/write */
13962306a36Sopenharmony_ci#define REG_ENA_VP_0              REG(0x00, 0x18)     /* read/write */
14062306a36Sopenharmony_ci#define REG_ENA_VP_1              REG(0x00, 0x19)     /* read/write */
14162306a36Sopenharmony_ci#define REG_ENA_VP_2              REG(0x00, 0x1a)     /* read/write */
14262306a36Sopenharmony_ci#define REG_ENA_AP                REG(0x00, 0x1e)     /* read/write */
14362306a36Sopenharmony_ci#define REG_VIP_CNTRL_0           REG(0x00, 0x20)     /* write */
14462306a36Sopenharmony_ci# define VIP_CNTRL_0_MIRR_A       (1 << 7)
14562306a36Sopenharmony_ci# define VIP_CNTRL_0_SWAP_A(x)    (((x) & 7) << 4)
14662306a36Sopenharmony_ci# define VIP_CNTRL_0_MIRR_B       (1 << 3)
14762306a36Sopenharmony_ci# define VIP_CNTRL_0_SWAP_B(x)    (((x) & 7) << 0)
14862306a36Sopenharmony_ci#define REG_VIP_CNTRL_1           REG(0x00, 0x21)     /* write */
14962306a36Sopenharmony_ci# define VIP_CNTRL_1_MIRR_C       (1 << 7)
15062306a36Sopenharmony_ci# define VIP_CNTRL_1_SWAP_C(x)    (((x) & 7) << 4)
15162306a36Sopenharmony_ci# define VIP_CNTRL_1_MIRR_D       (1 << 3)
15262306a36Sopenharmony_ci# define VIP_CNTRL_1_SWAP_D(x)    (((x) & 7) << 0)
15362306a36Sopenharmony_ci#define REG_VIP_CNTRL_2           REG(0x00, 0x22)     /* write */
15462306a36Sopenharmony_ci# define VIP_CNTRL_2_MIRR_E       (1 << 7)
15562306a36Sopenharmony_ci# define VIP_CNTRL_2_SWAP_E(x)    (((x) & 7) << 4)
15662306a36Sopenharmony_ci# define VIP_CNTRL_2_MIRR_F       (1 << 3)
15762306a36Sopenharmony_ci# define VIP_CNTRL_2_SWAP_F(x)    (((x) & 7) << 0)
15862306a36Sopenharmony_ci#define REG_VIP_CNTRL_3           REG(0x00, 0x23)     /* write */
15962306a36Sopenharmony_ci# define VIP_CNTRL_3_X_TGL        (1 << 0)
16062306a36Sopenharmony_ci# define VIP_CNTRL_3_H_TGL        (1 << 1)
16162306a36Sopenharmony_ci# define VIP_CNTRL_3_V_TGL        (1 << 2)
16262306a36Sopenharmony_ci# define VIP_CNTRL_3_EMB          (1 << 3)
16362306a36Sopenharmony_ci# define VIP_CNTRL_3_SYNC_DE      (1 << 4)
16462306a36Sopenharmony_ci# define VIP_CNTRL_3_SYNC_HS      (1 << 5)
16562306a36Sopenharmony_ci# define VIP_CNTRL_3_DE_INT       (1 << 6)
16662306a36Sopenharmony_ci# define VIP_CNTRL_3_EDGE         (1 << 7)
16762306a36Sopenharmony_ci#define REG_VIP_CNTRL_4           REG(0x00, 0x24)     /* write */
16862306a36Sopenharmony_ci# define VIP_CNTRL_4_BLC(x)       (((x) & 3) << 0)
16962306a36Sopenharmony_ci# define VIP_CNTRL_4_BLANKIT(x)   (((x) & 3) << 2)
17062306a36Sopenharmony_ci# define VIP_CNTRL_4_CCIR656      (1 << 4)
17162306a36Sopenharmony_ci# define VIP_CNTRL_4_656_ALT      (1 << 5)
17262306a36Sopenharmony_ci# define VIP_CNTRL_4_TST_656      (1 << 6)
17362306a36Sopenharmony_ci# define VIP_CNTRL_4_TST_PAT      (1 << 7)
17462306a36Sopenharmony_ci#define REG_VIP_CNTRL_5           REG(0x00, 0x25)     /* write */
17562306a36Sopenharmony_ci# define VIP_CNTRL_5_CKCASE       (1 << 0)
17662306a36Sopenharmony_ci# define VIP_CNTRL_5_SP_CNT(x)    (((x) & 3) << 1)
17762306a36Sopenharmony_ci#define REG_MUX_AP                REG(0x00, 0x26)     /* read/write */
17862306a36Sopenharmony_ci# define MUX_AP_SELECT_I2S	  0x64
17962306a36Sopenharmony_ci# define MUX_AP_SELECT_SPDIF	  0x40
18062306a36Sopenharmony_ci#define REG_MUX_VP_VIP_OUT        REG(0x00, 0x27)     /* read/write */
18162306a36Sopenharmony_ci#define REG_MAT_CONTRL            REG(0x00, 0x80)     /* write */
18262306a36Sopenharmony_ci# define MAT_CONTRL_MAT_SC(x)     (((x) & 3) << 0)
18362306a36Sopenharmony_ci# define MAT_CONTRL_MAT_BP        (1 << 2)
18462306a36Sopenharmony_ci#define REG_VIDFORMAT             REG(0x00, 0xa0)     /* write */
18562306a36Sopenharmony_ci#define REG_REFPIX_MSB            REG(0x00, 0xa1)     /* write */
18662306a36Sopenharmony_ci#define REG_REFPIX_LSB            REG(0x00, 0xa2)     /* write */
18762306a36Sopenharmony_ci#define REG_REFLINE_MSB           REG(0x00, 0xa3)     /* write */
18862306a36Sopenharmony_ci#define REG_REFLINE_LSB           REG(0x00, 0xa4)     /* write */
18962306a36Sopenharmony_ci#define REG_NPIX_MSB              REG(0x00, 0xa5)     /* write */
19062306a36Sopenharmony_ci#define REG_NPIX_LSB              REG(0x00, 0xa6)     /* write */
19162306a36Sopenharmony_ci#define REG_NLINE_MSB             REG(0x00, 0xa7)     /* write */
19262306a36Sopenharmony_ci#define REG_NLINE_LSB             REG(0x00, 0xa8)     /* write */
19362306a36Sopenharmony_ci#define REG_VS_LINE_STRT_1_MSB    REG(0x00, 0xa9)     /* write */
19462306a36Sopenharmony_ci#define REG_VS_LINE_STRT_1_LSB    REG(0x00, 0xaa)     /* write */
19562306a36Sopenharmony_ci#define REG_VS_PIX_STRT_1_MSB     REG(0x00, 0xab)     /* write */
19662306a36Sopenharmony_ci#define REG_VS_PIX_STRT_1_LSB     REG(0x00, 0xac)     /* write */
19762306a36Sopenharmony_ci#define REG_VS_LINE_END_1_MSB     REG(0x00, 0xad)     /* write */
19862306a36Sopenharmony_ci#define REG_VS_LINE_END_1_LSB     REG(0x00, 0xae)     /* write */
19962306a36Sopenharmony_ci#define REG_VS_PIX_END_1_MSB      REG(0x00, 0xaf)     /* write */
20062306a36Sopenharmony_ci#define REG_VS_PIX_END_1_LSB      REG(0x00, 0xb0)     /* write */
20162306a36Sopenharmony_ci#define REG_VS_LINE_STRT_2_MSB    REG(0x00, 0xb1)     /* write */
20262306a36Sopenharmony_ci#define REG_VS_LINE_STRT_2_LSB    REG(0x00, 0xb2)     /* write */
20362306a36Sopenharmony_ci#define REG_VS_PIX_STRT_2_MSB     REG(0x00, 0xb3)     /* write */
20462306a36Sopenharmony_ci#define REG_VS_PIX_STRT_2_LSB     REG(0x00, 0xb4)     /* write */
20562306a36Sopenharmony_ci#define REG_VS_LINE_END_2_MSB     REG(0x00, 0xb5)     /* write */
20662306a36Sopenharmony_ci#define REG_VS_LINE_END_2_LSB     REG(0x00, 0xb6)     /* write */
20762306a36Sopenharmony_ci#define REG_VS_PIX_END_2_MSB      REG(0x00, 0xb7)     /* write */
20862306a36Sopenharmony_ci#define REG_VS_PIX_END_2_LSB      REG(0x00, 0xb8)     /* write */
20962306a36Sopenharmony_ci#define REG_HS_PIX_START_MSB      REG(0x00, 0xb9)     /* write */
21062306a36Sopenharmony_ci#define REG_HS_PIX_START_LSB      REG(0x00, 0xba)     /* write */
21162306a36Sopenharmony_ci#define REG_HS_PIX_STOP_MSB       REG(0x00, 0xbb)     /* write */
21262306a36Sopenharmony_ci#define REG_HS_PIX_STOP_LSB       REG(0x00, 0xbc)     /* write */
21362306a36Sopenharmony_ci#define REG_VWIN_START_1_MSB      REG(0x00, 0xbd)     /* write */
21462306a36Sopenharmony_ci#define REG_VWIN_START_1_LSB      REG(0x00, 0xbe)     /* write */
21562306a36Sopenharmony_ci#define REG_VWIN_END_1_MSB        REG(0x00, 0xbf)     /* write */
21662306a36Sopenharmony_ci#define REG_VWIN_END_1_LSB        REG(0x00, 0xc0)     /* write */
21762306a36Sopenharmony_ci#define REG_VWIN_START_2_MSB      REG(0x00, 0xc1)     /* write */
21862306a36Sopenharmony_ci#define REG_VWIN_START_2_LSB      REG(0x00, 0xc2)     /* write */
21962306a36Sopenharmony_ci#define REG_VWIN_END_2_MSB        REG(0x00, 0xc3)     /* write */
22062306a36Sopenharmony_ci#define REG_VWIN_END_2_LSB        REG(0x00, 0xc4)     /* write */
22162306a36Sopenharmony_ci#define REG_DE_START_MSB          REG(0x00, 0xc5)     /* write */
22262306a36Sopenharmony_ci#define REG_DE_START_LSB          REG(0x00, 0xc6)     /* write */
22362306a36Sopenharmony_ci#define REG_DE_STOP_MSB           REG(0x00, 0xc7)     /* write */
22462306a36Sopenharmony_ci#define REG_DE_STOP_LSB           REG(0x00, 0xc8)     /* write */
22562306a36Sopenharmony_ci#define REG_TBG_CNTRL_0           REG(0x00, 0xca)     /* write */
22662306a36Sopenharmony_ci# define TBG_CNTRL_0_TOP_TGL      (1 << 0)
22762306a36Sopenharmony_ci# define TBG_CNTRL_0_TOP_SEL      (1 << 1)
22862306a36Sopenharmony_ci# define TBG_CNTRL_0_DE_EXT       (1 << 2)
22962306a36Sopenharmony_ci# define TBG_CNTRL_0_TOP_EXT      (1 << 3)
23062306a36Sopenharmony_ci# define TBG_CNTRL_0_FRAME_DIS    (1 << 5)
23162306a36Sopenharmony_ci# define TBG_CNTRL_0_SYNC_MTHD    (1 << 6)
23262306a36Sopenharmony_ci# define TBG_CNTRL_0_SYNC_ONCE    (1 << 7)
23362306a36Sopenharmony_ci#define REG_TBG_CNTRL_1           REG(0x00, 0xcb)     /* write */
23462306a36Sopenharmony_ci# define TBG_CNTRL_1_H_TGL        (1 << 0)
23562306a36Sopenharmony_ci# define TBG_CNTRL_1_V_TGL        (1 << 1)
23662306a36Sopenharmony_ci# define TBG_CNTRL_1_TGL_EN       (1 << 2)
23762306a36Sopenharmony_ci# define TBG_CNTRL_1_X_EXT        (1 << 3)
23862306a36Sopenharmony_ci# define TBG_CNTRL_1_H_EXT        (1 << 4)
23962306a36Sopenharmony_ci# define TBG_CNTRL_1_V_EXT        (1 << 5)
24062306a36Sopenharmony_ci# define TBG_CNTRL_1_DWIN_DIS     (1 << 6)
24162306a36Sopenharmony_ci#define REG_ENABLE_SPACE          REG(0x00, 0xd6)     /* write */
24262306a36Sopenharmony_ci#define REG_HVF_CNTRL_0           REG(0x00, 0xe4)     /* write */
24362306a36Sopenharmony_ci# define HVF_CNTRL_0_SM           (1 << 7)
24462306a36Sopenharmony_ci# define HVF_CNTRL_0_RWB          (1 << 6)
24562306a36Sopenharmony_ci# define HVF_CNTRL_0_PREFIL(x)    (((x) & 3) << 2)
24662306a36Sopenharmony_ci# define HVF_CNTRL_0_INTPOL(x)    (((x) & 3) << 0)
24762306a36Sopenharmony_ci#define REG_HVF_CNTRL_1           REG(0x00, 0xe5)     /* write */
24862306a36Sopenharmony_ci# define HVF_CNTRL_1_FOR          (1 << 0)
24962306a36Sopenharmony_ci# define HVF_CNTRL_1_YUVBLK       (1 << 1)
25062306a36Sopenharmony_ci# define HVF_CNTRL_1_VQR(x)       (((x) & 3) << 2)
25162306a36Sopenharmony_ci# define HVF_CNTRL_1_PAD(x)       (((x) & 3) << 4)
25262306a36Sopenharmony_ci# define HVF_CNTRL_1_SEMI_PLANAR  (1 << 6)
25362306a36Sopenharmony_ci#define REG_RPT_CNTRL             REG(0x00, 0xf0)     /* write */
25462306a36Sopenharmony_ci# define RPT_CNTRL_REPEAT(x)      ((x) & 15)
25562306a36Sopenharmony_ci#define REG_I2S_FORMAT            REG(0x00, 0xfc)     /* read/write */
25662306a36Sopenharmony_ci# define I2S_FORMAT_PHILIPS       (0 << 0)
25762306a36Sopenharmony_ci# define I2S_FORMAT_LEFT_J        (2 << 0)
25862306a36Sopenharmony_ci# define I2S_FORMAT_RIGHT_J       (3 << 0)
25962306a36Sopenharmony_ci#define REG_AIP_CLKSEL            REG(0x00, 0xfd)     /* write */
26062306a36Sopenharmony_ci# define AIP_CLKSEL_AIP_SPDIF	  (0 << 3)
26162306a36Sopenharmony_ci# define AIP_CLKSEL_AIP_I2S	  (1 << 3)
26262306a36Sopenharmony_ci# define AIP_CLKSEL_FS_ACLK	  (0 << 0)
26362306a36Sopenharmony_ci# define AIP_CLKSEL_FS_MCLK	  (1 << 0)
26462306a36Sopenharmony_ci# define AIP_CLKSEL_FS_FS64SPDIF  (2 << 0)
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci/* Page 02h: PLL settings */
26762306a36Sopenharmony_ci#define REG_PLL_SERIAL_1          REG(0x02, 0x00)     /* read/write */
26862306a36Sopenharmony_ci# define PLL_SERIAL_1_SRL_FDN     (1 << 0)
26962306a36Sopenharmony_ci# define PLL_SERIAL_1_SRL_IZ(x)   (((x) & 3) << 1)
27062306a36Sopenharmony_ci# define PLL_SERIAL_1_SRL_MAN_IZ  (1 << 6)
27162306a36Sopenharmony_ci#define REG_PLL_SERIAL_2          REG(0x02, 0x01)     /* read/write */
27262306a36Sopenharmony_ci# define PLL_SERIAL_2_SRL_NOSC(x) ((x) << 0)
27362306a36Sopenharmony_ci# define PLL_SERIAL_2_SRL_PR(x)   (((x) & 0xf) << 4)
27462306a36Sopenharmony_ci#define REG_PLL_SERIAL_3          REG(0x02, 0x02)     /* read/write */
27562306a36Sopenharmony_ci# define PLL_SERIAL_3_SRL_CCIR    (1 << 0)
27662306a36Sopenharmony_ci# define PLL_SERIAL_3_SRL_DE      (1 << 2)
27762306a36Sopenharmony_ci# define PLL_SERIAL_3_SRL_PXIN_SEL (1 << 4)
27862306a36Sopenharmony_ci#define REG_SERIALIZER            REG(0x02, 0x03)     /* read/write */
27962306a36Sopenharmony_ci#define REG_BUFFER_OUT            REG(0x02, 0x04)     /* read/write */
28062306a36Sopenharmony_ci#define REG_PLL_SCG1              REG(0x02, 0x05)     /* read/write */
28162306a36Sopenharmony_ci#define REG_PLL_SCG2              REG(0x02, 0x06)     /* read/write */
28262306a36Sopenharmony_ci#define REG_PLL_SCGN1             REG(0x02, 0x07)     /* read/write */
28362306a36Sopenharmony_ci#define REG_PLL_SCGN2             REG(0x02, 0x08)     /* read/write */
28462306a36Sopenharmony_ci#define REG_PLL_SCGR1             REG(0x02, 0x09)     /* read/write */
28562306a36Sopenharmony_ci#define REG_PLL_SCGR2             REG(0x02, 0x0a)     /* read/write */
28662306a36Sopenharmony_ci#define REG_AUDIO_DIV             REG(0x02, 0x0e)     /* read/write */
28762306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_1       0
28862306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_2       1
28962306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_4       2
29062306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_8       3
29162306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_16      4
29262306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_32      5
29362306a36Sopenharmony_ci#define REG_SEL_CLK               REG(0x02, 0x11)     /* read/write */
29462306a36Sopenharmony_ci# define SEL_CLK_SEL_CLK1         (1 << 0)
29562306a36Sopenharmony_ci# define SEL_CLK_SEL_VRF_CLK(x)   (((x) & 3) << 1)
29662306a36Sopenharmony_ci# define SEL_CLK_ENA_SC_CLK       (1 << 3)
29762306a36Sopenharmony_ci#define REG_ANA_GENERAL           REG(0x02, 0x12)     /* read/write */
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/* Page 09h: EDID Control */
30162306a36Sopenharmony_ci#define REG_EDID_DATA_0           REG(0x09, 0x00)     /* read */
30262306a36Sopenharmony_ci/* next 127 successive registers are the EDID block */
30362306a36Sopenharmony_ci#define REG_EDID_CTRL             REG(0x09, 0xfa)     /* read/write */
30462306a36Sopenharmony_ci#define REG_DDC_ADDR              REG(0x09, 0xfb)     /* read/write */
30562306a36Sopenharmony_ci#define REG_DDC_OFFS              REG(0x09, 0xfc)     /* read/write */
30662306a36Sopenharmony_ci#define REG_DDC_SEGM_ADDR         REG(0x09, 0xfd)     /* read/write */
30762306a36Sopenharmony_ci#define REG_DDC_SEGM              REG(0x09, 0xfe)     /* read/write */
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci/* Page 10h: information frames and packets */
31162306a36Sopenharmony_ci#define REG_IF1_HB0               REG(0x10, 0x20)     /* read/write */
31262306a36Sopenharmony_ci#define REG_IF2_HB0               REG(0x10, 0x40)     /* read/write */
31362306a36Sopenharmony_ci#define REG_IF3_HB0               REG(0x10, 0x60)     /* read/write */
31462306a36Sopenharmony_ci#define REG_IF4_HB0               REG(0x10, 0x80)     /* read/write */
31562306a36Sopenharmony_ci#define REG_IF5_HB0               REG(0x10, 0xa0)     /* read/write */
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/* Page 11h: audio settings and content info packets */
31962306a36Sopenharmony_ci#define REG_AIP_CNTRL_0           REG(0x11, 0x00)     /* read/write */
32062306a36Sopenharmony_ci# define AIP_CNTRL_0_RST_FIFO     (1 << 0)
32162306a36Sopenharmony_ci# define AIP_CNTRL_0_SWAP         (1 << 1)
32262306a36Sopenharmony_ci# define AIP_CNTRL_0_LAYOUT       (1 << 2)
32362306a36Sopenharmony_ci# define AIP_CNTRL_0_ACR_MAN      (1 << 5)
32462306a36Sopenharmony_ci# define AIP_CNTRL_0_RST_CTS      (1 << 6)
32562306a36Sopenharmony_ci#define REG_CA_I2S                REG(0x11, 0x01)     /* read/write */
32662306a36Sopenharmony_ci# define CA_I2S_CA_I2S(x)         (((x) & 31) << 0)
32762306a36Sopenharmony_ci# define CA_I2S_HBR_CHSTAT        (1 << 6)
32862306a36Sopenharmony_ci#define REG_LATENCY_RD            REG(0x11, 0x04)     /* read/write */
32962306a36Sopenharmony_ci#define REG_ACR_CTS_0             REG(0x11, 0x05)     /* read/write */
33062306a36Sopenharmony_ci#define REG_ACR_CTS_1             REG(0x11, 0x06)     /* read/write */
33162306a36Sopenharmony_ci#define REG_ACR_CTS_2             REG(0x11, 0x07)     /* read/write */
33262306a36Sopenharmony_ci#define REG_ACR_N_0               REG(0x11, 0x08)     /* read/write */
33362306a36Sopenharmony_ci#define REG_ACR_N_1               REG(0x11, 0x09)     /* read/write */
33462306a36Sopenharmony_ci#define REG_ACR_N_2               REG(0x11, 0x0a)     /* read/write */
33562306a36Sopenharmony_ci#define REG_CTS_N                 REG(0x11, 0x0c)     /* read/write */
33662306a36Sopenharmony_ci# define CTS_N_K(x)               (((x) & 7) << 0)
33762306a36Sopenharmony_ci# define CTS_N_M(x)               (((x) & 3) << 4)
33862306a36Sopenharmony_ci#define REG_ENC_CNTRL             REG(0x11, 0x0d)     /* read/write */
33962306a36Sopenharmony_ci# define ENC_CNTRL_RST_ENC        (1 << 0)
34062306a36Sopenharmony_ci# define ENC_CNTRL_RST_SEL        (1 << 1)
34162306a36Sopenharmony_ci# define ENC_CNTRL_CTL_CODE(x)    (((x) & 3) << 2)
34262306a36Sopenharmony_ci#define REG_DIP_FLAGS             REG(0x11, 0x0e)     /* read/write */
34362306a36Sopenharmony_ci# define DIP_FLAGS_ACR            (1 << 0)
34462306a36Sopenharmony_ci# define DIP_FLAGS_GC             (1 << 1)
34562306a36Sopenharmony_ci#define REG_DIP_IF_FLAGS          REG(0x11, 0x0f)     /* read/write */
34662306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF1         (1 << 1)
34762306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF2         (1 << 2)
34862306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF3         (1 << 3)
34962306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF4         (1 << 4)
35062306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF5         (1 << 5)
35162306a36Sopenharmony_ci#define REG_CH_STAT_B(x)          REG(0x11, 0x14 + (x)) /* read/write */
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/* Page 12h: HDCP and OTP */
35562306a36Sopenharmony_ci#define REG_TX3                   REG(0x12, 0x9a)     /* read/write */
35662306a36Sopenharmony_ci#define REG_TX4                   REG(0x12, 0x9b)     /* read/write */
35762306a36Sopenharmony_ci# define TX4_PD_RAM               (1 << 1)
35862306a36Sopenharmony_ci#define REG_TX33                  REG(0x12, 0xb8)     /* read/write */
35962306a36Sopenharmony_ci# define TX33_HDMI                (1 << 1)
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/* Page 13h: Gamut related metadata packets */
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci/* CEC registers: (not paged)
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_ci#define REG_CEC_INTSTATUS	  0xee		      /* read */
36962306a36Sopenharmony_ci# define CEC_INTSTATUS_CEC	  (1 << 0)
37062306a36Sopenharmony_ci# define CEC_INTSTATUS_HDMI	  (1 << 1)
37162306a36Sopenharmony_ci#define REG_CEC_CAL_XOSC_CTRL1    0xf2
37262306a36Sopenharmony_ci# define CEC_CAL_XOSC_CTRL1_ENA_CAL	BIT(0)
37362306a36Sopenharmony_ci#define REG_CEC_DES_FREQ2         0xf5
37462306a36Sopenharmony_ci# define CEC_DES_FREQ2_DIS_AUTOCAL BIT(7)
37562306a36Sopenharmony_ci#define REG_CEC_CLK               0xf6
37662306a36Sopenharmony_ci# define CEC_CLK_FRO              0x11
37762306a36Sopenharmony_ci#define REG_CEC_FRO_IM_CLK_CTRL   0xfb                /* read/write */
37862306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7)
37962306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_ENA_OTP   (1 << 6)
38062306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1)
38162306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_FRO_DIV   (1 << 0)
38262306a36Sopenharmony_ci#define REG_CEC_RXSHPDINTENA	  0xfc		      /* read/write */
38362306a36Sopenharmony_ci#define REG_CEC_RXSHPDINT	  0xfd		      /* read */
38462306a36Sopenharmony_ci# define CEC_RXSHPDINT_RXSENS     BIT(0)
38562306a36Sopenharmony_ci# define CEC_RXSHPDINT_HPD        BIT(1)
38662306a36Sopenharmony_ci#define REG_CEC_RXSHPDLEV         0xfe                /* read */
38762306a36Sopenharmony_ci# define CEC_RXSHPDLEV_RXSENS     (1 << 0)
38862306a36Sopenharmony_ci# define CEC_RXSHPDLEV_HPD        (1 << 1)
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci#define REG_CEC_ENAMODS           0xff                /* read/write */
39162306a36Sopenharmony_ci# define CEC_ENAMODS_EN_CEC_CLK   (1 << 7)
39262306a36Sopenharmony_ci# define CEC_ENAMODS_DIS_FRO      (1 << 6)
39362306a36Sopenharmony_ci# define CEC_ENAMODS_DIS_CCLK     (1 << 5)
39462306a36Sopenharmony_ci# define CEC_ENAMODS_EN_RXSENS    (1 << 2)
39562306a36Sopenharmony_ci# define CEC_ENAMODS_EN_HDMI      (1 << 1)
39662306a36Sopenharmony_ci# define CEC_ENAMODS_EN_CEC       (1 << 0)
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/* Device versions: */
40062306a36Sopenharmony_ci#define TDA9989N2                 0x0101
40162306a36Sopenharmony_ci#define TDA19989                  0x0201
40262306a36Sopenharmony_ci#define TDA19989N2                0x0202
40362306a36Sopenharmony_ci#define TDA19988                  0x0301
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic void
40662306a36Sopenharmony_cicec_write(struct tda998x_priv *priv, u16 addr, u8 val)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	u8 buf[] = {addr, val};
40962306a36Sopenharmony_ci	struct i2c_msg msg = {
41062306a36Sopenharmony_ci		.addr = priv->cec_addr,
41162306a36Sopenharmony_ci		.len = 2,
41262306a36Sopenharmony_ci		.buf = buf,
41362306a36Sopenharmony_ci	};
41462306a36Sopenharmony_ci	int ret;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	ret = i2c_transfer(priv->hdmi->adapter, &msg, 1);
41762306a36Sopenharmony_ci	if (ret < 0)
41862306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev, "Error %d writing to cec:0x%x\n",
41962306a36Sopenharmony_ci			ret, addr);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic u8
42362306a36Sopenharmony_cicec_read(struct tda998x_priv *priv, u8 addr)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	u8 val;
42662306a36Sopenharmony_ci	struct i2c_msg msg[2] = {
42762306a36Sopenharmony_ci		{
42862306a36Sopenharmony_ci			.addr = priv->cec_addr,
42962306a36Sopenharmony_ci			.len = 1,
43062306a36Sopenharmony_ci			.buf = &addr,
43162306a36Sopenharmony_ci		}, {
43262306a36Sopenharmony_ci			.addr = priv->cec_addr,
43362306a36Sopenharmony_ci			.flags = I2C_M_RD,
43462306a36Sopenharmony_ci			.len = 1,
43562306a36Sopenharmony_ci			.buf = &val,
43662306a36Sopenharmony_ci		},
43762306a36Sopenharmony_ci	};
43862306a36Sopenharmony_ci	int ret;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	ret = i2c_transfer(priv->hdmi->adapter, msg, ARRAY_SIZE(msg));
44162306a36Sopenharmony_ci	if (ret < 0) {
44262306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev, "Error %d reading from cec:0x%x\n",
44362306a36Sopenharmony_ci			ret, addr);
44462306a36Sopenharmony_ci		val = 0;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	return val;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void cec_enamods(struct tda998x_priv *priv, u8 mods, bool enable)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	int val = cec_read(priv, REG_CEC_ENAMODS);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (val < 0)
45562306a36Sopenharmony_ci		return;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (enable)
45862306a36Sopenharmony_ci		val |= mods;
45962306a36Sopenharmony_ci	else
46062306a36Sopenharmony_ci		val &= ~mods;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	cec_write(priv, REG_CEC_ENAMODS, val);
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic void tda998x_cec_set_calibration(struct tda998x_priv *priv, bool enable)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	if (enable) {
46862306a36Sopenharmony_ci		u8 val;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		cec_write(priv, 0xf3, 0xc0);
47162306a36Sopenharmony_ci		cec_write(priv, 0xf4, 0xd4);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		/* Enable automatic calibration mode */
47462306a36Sopenharmony_ci		val = cec_read(priv, REG_CEC_DES_FREQ2);
47562306a36Sopenharmony_ci		val &= ~CEC_DES_FREQ2_DIS_AUTOCAL;
47662306a36Sopenharmony_ci		cec_write(priv, REG_CEC_DES_FREQ2, val);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		/* Enable free running oscillator */
47962306a36Sopenharmony_ci		cec_write(priv, REG_CEC_CLK, CEC_CLK_FRO);
48062306a36Sopenharmony_ci		cec_enamods(priv, CEC_ENAMODS_DIS_FRO, false);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		cec_write(priv, REG_CEC_CAL_XOSC_CTRL1,
48362306a36Sopenharmony_ci			  CEC_CAL_XOSC_CTRL1_ENA_CAL);
48462306a36Sopenharmony_ci	} else {
48562306a36Sopenharmony_ci		cec_write(priv, REG_CEC_CAL_XOSC_CTRL1, 0);
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/*
49062306a36Sopenharmony_ci * Calibration for the internal oscillator: we need to set calibration mode,
49162306a36Sopenharmony_ci * and then pulse the IRQ line low for a 10ms ± 1% period.
49262306a36Sopenharmony_ci */
49362306a36Sopenharmony_cistatic void tda998x_cec_calibration(struct tda998x_priv *priv)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct gpio_desc *calib = priv->calib;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	mutex_lock(&priv->edid_mutex);
49862306a36Sopenharmony_ci	if (priv->hdmi->irq > 0)
49962306a36Sopenharmony_ci		disable_irq(priv->hdmi->irq);
50062306a36Sopenharmony_ci	gpiod_direction_output(calib, 1);
50162306a36Sopenharmony_ci	tda998x_cec_set_calibration(priv, true);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	local_irq_disable();
50462306a36Sopenharmony_ci	gpiod_set_value(calib, 0);
50562306a36Sopenharmony_ci	mdelay(10);
50662306a36Sopenharmony_ci	gpiod_set_value(calib, 1);
50762306a36Sopenharmony_ci	local_irq_enable();
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	tda998x_cec_set_calibration(priv, false);
51062306a36Sopenharmony_ci	gpiod_direction_input(calib);
51162306a36Sopenharmony_ci	if (priv->hdmi->irq > 0)
51262306a36Sopenharmony_ci		enable_irq(priv->hdmi->irq);
51362306a36Sopenharmony_ci	mutex_unlock(&priv->edid_mutex);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic int tda998x_cec_hook_init(void *data)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct tda998x_priv *priv = data;
51962306a36Sopenharmony_ci	struct gpio_desc *calib;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	calib = gpiod_get(&priv->hdmi->dev, "nxp,calib", GPIOD_ASIS);
52262306a36Sopenharmony_ci	if (IS_ERR(calib)) {
52362306a36Sopenharmony_ci		dev_warn(&priv->hdmi->dev, "failed to get calibration gpio: %ld\n",
52462306a36Sopenharmony_ci			 PTR_ERR(calib));
52562306a36Sopenharmony_ci		return PTR_ERR(calib);
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	priv->calib = calib;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return 0;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic void tda998x_cec_hook_exit(void *data)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct tda998x_priv *priv = data;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	gpiod_put(priv->calib);
53862306a36Sopenharmony_ci	priv->calib = NULL;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic int tda998x_cec_hook_open(void *data)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct tda998x_priv *priv = data;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	cec_enamods(priv, CEC_ENAMODS_EN_CEC_CLK | CEC_ENAMODS_EN_CEC, true);
54662306a36Sopenharmony_ci	tda998x_cec_calibration(priv);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic void tda998x_cec_hook_release(void *data)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	struct tda998x_priv *priv = data;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	cec_enamods(priv, CEC_ENAMODS_EN_CEC_CLK | CEC_ENAMODS_EN_CEC, false);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic int
55962306a36Sopenharmony_ciset_page(struct tda998x_priv *priv, u16 reg)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	if (REG2PAGE(reg) != priv->current_page) {
56262306a36Sopenharmony_ci		struct i2c_client *client = priv->hdmi;
56362306a36Sopenharmony_ci		u8 buf[] = {
56462306a36Sopenharmony_ci				REG_CURPAGE, REG2PAGE(reg)
56562306a36Sopenharmony_ci		};
56662306a36Sopenharmony_ci		int ret = i2c_master_send(client, buf, sizeof(buf));
56762306a36Sopenharmony_ci		if (ret < 0) {
56862306a36Sopenharmony_ci			dev_err(&client->dev, "%s %04x err %d\n", __func__,
56962306a36Sopenharmony_ci					reg, ret);
57062306a36Sopenharmony_ci			return ret;
57162306a36Sopenharmony_ci		}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		priv->current_page = REG2PAGE(reg);
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci	return 0;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic int
57962306a36Sopenharmony_cireg_read_range(struct tda998x_priv *priv, u16 reg, char *buf, int cnt)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct i2c_client *client = priv->hdmi;
58262306a36Sopenharmony_ci	u8 addr = REG2ADDR(reg);
58362306a36Sopenharmony_ci	int ret;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
58662306a36Sopenharmony_ci	ret = set_page(priv, reg);
58762306a36Sopenharmony_ci	if (ret < 0)
58862306a36Sopenharmony_ci		goto out;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	ret = i2c_master_send(client, &addr, sizeof(addr));
59162306a36Sopenharmony_ci	if (ret < 0)
59262306a36Sopenharmony_ci		goto fail;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	ret = i2c_master_recv(client, buf, cnt);
59562306a36Sopenharmony_ci	if (ret < 0)
59662306a36Sopenharmony_ci		goto fail;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	goto out;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cifail:
60162306a36Sopenharmony_ci	dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg);
60262306a36Sopenharmony_ciout:
60362306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
60462306a36Sopenharmony_ci	return ret;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci#define MAX_WRITE_RANGE_BUF 32
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic void
61062306a36Sopenharmony_cireg_write_range(struct tda998x_priv *priv, u16 reg, u8 *p, int cnt)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct i2c_client *client = priv->hdmi;
61362306a36Sopenharmony_ci	/* This is the maximum size of the buffer passed in */
61462306a36Sopenharmony_ci	u8 buf[MAX_WRITE_RANGE_BUF + 1];
61562306a36Sopenharmony_ci	int ret;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (cnt > MAX_WRITE_RANGE_BUF) {
61862306a36Sopenharmony_ci		dev_err(&client->dev, "Fixed write buffer too small (%d)\n",
61962306a36Sopenharmony_ci				MAX_WRITE_RANGE_BUF);
62062306a36Sopenharmony_ci		return;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	buf[0] = REG2ADDR(reg);
62462306a36Sopenharmony_ci	memcpy(&buf[1], p, cnt);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
62762306a36Sopenharmony_ci	ret = set_page(priv, reg);
62862306a36Sopenharmony_ci	if (ret < 0)
62962306a36Sopenharmony_ci		goto out;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	ret = i2c_master_send(client, buf, cnt + 1);
63262306a36Sopenharmony_ci	if (ret < 0)
63362306a36Sopenharmony_ci		dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
63462306a36Sopenharmony_ciout:
63562306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic int
63962306a36Sopenharmony_cireg_read(struct tda998x_priv *priv, u16 reg)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	u8 val = 0;
64262306a36Sopenharmony_ci	int ret;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	ret = reg_read_range(priv, reg, &val, sizeof(val));
64562306a36Sopenharmony_ci	if (ret < 0)
64662306a36Sopenharmony_ci		return ret;
64762306a36Sopenharmony_ci	return val;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic void
65162306a36Sopenharmony_cireg_write(struct tda998x_priv *priv, u16 reg, u8 val)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct i2c_client *client = priv->hdmi;
65462306a36Sopenharmony_ci	u8 buf[] = {REG2ADDR(reg), val};
65562306a36Sopenharmony_ci	int ret;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
65862306a36Sopenharmony_ci	ret = set_page(priv, reg);
65962306a36Sopenharmony_ci	if (ret < 0)
66062306a36Sopenharmony_ci		goto out;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	ret = i2c_master_send(client, buf, sizeof(buf));
66362306a36Sopenharmony_ci	if (ret < 0)
66462306a36Sopenharmony_ci		dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
66562306a36Sopenharmony_ciout:
66662306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
66762306a36Sopenharmony_ci}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic void
67062306a36Sopenharmony_cireg_write16(struct tda998x_priv *priv, u16 reg, u16 val)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	struct i2c_client *client = priv->hdmi;
67362306a36Sopenharmony_ci	u8 buf[] = {REG2ADDR(reg), val >> 8, val};
67462306a36Sopenharmony_ci	int ret;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
67762306a36Sopenharmony_ci	ret = set_page(priv, reg);
67862306a36Sopenharmony_ci	if (ret < 0)
67962306a36Sopenharmony_ci		goto out;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	ret = i2c_master_send(client, buf, sizeof(buf));
68262306a36Sopenharmony_ci	if (ret < 0)
68362306a36Sopenharmony_ci		dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
68462306a36Sopenharmony_ciout:
68562306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic void
68962306a36Sopenharmony_cireg_set(struct tda998x_priv *priv, u16 reg, u8 val)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	int old_val;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	old_val = reg_read(priv, reg);
69462306a36Sopenharmony_ci	if (old_val >= 0)
69562306a36Sopenharmony_ci		reg_write(priv, reg, old_val | val);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic void
69962306a36Sopenharmony_cireg_clear(struct tda998x_priv *priv, u16 reg, u8 val)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	int old_val;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	old_val = reg_read(priv, reg);
70462306a36Sopenharmony_ci	if (old_val >= 0)
70562306a36Sopenharmony_ci		reg_write(priv, reg, old_val & ~val);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic void
70962306a36Sopenharmony_citda998x_reset(struct tda998x_priv *priv)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	/* reset audio and i2c master: */
71262306a36Sopenharmony_ci	reg_write(priv, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER);
71362306a36Sopenharmony_ci	msleep(50);
71462306a36Sopenharmony_ci	reg_write(priv, REG_SOFTRESET, 0);
71562306a36Sopenharmony_ci	msleep(50);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* reset transmitter: */
71862306a36Sopenharmony_ci	reg_set(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
71962306a36Sopenharmony_ci	reg_clear(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/* PLL registers common configuration */
72262306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SERIAL_1, 0x00);
72362306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
72462306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SERIAL_3, 0x00);
72562306a36Sopenharmony_ci	reg_write(priv, REG_SERIALIZER,   0x00);
72662306a36Sopenharmony_ci	reg_write(priv, REG_BUFFER_OUT,   0x00);
72762306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SCG1,     0x00);
72862306a36Sopenharmony_ci	reg_write(priv, REG_AUDIO_DIV,    AUDIO_DIV_SERCLK_8);
72962306a36Sopenharmony_ci	reg_write(priv, REG_SEL_CLK,      SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
73062306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SCGN1,    0xfa);
73162306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SCGN2,    0x00);
73262306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SCGR1,    0x5b);
73362306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SCGR2,    0x00);
73462306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SCG2,     0x10);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/* Write the default value MUX register */
73762306a36Sopenharmony_ci	reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci/*
74162306a36Sopenharmony_ci * The TDA998x has a problem when trying to read the EDID close to a
74262306a36Sopenharmony_ci * HPD assertion: it needs a delay of 100ms to avoid timing out while
74362306a36Sopenharmony_ci * trying to read EDID data.
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * However, tda998x_connector_get_modes() may be called at any moment
74662306a36Sopenharmony_ci * after tda998x_connector_detect() indicates that we are connected, so
74762306a36Sopenharmony_ci * we need to delay probing modes in tda998x_connector_get_modes() after
74862306a36Sopenharmony_ci * we have seen a HPD inactive->active transition.  This code implements
74962306a36Sopenharmony_ci * that delay.
75062306a36Sopenharmony_ci */
75162306a36Sopenharmony_cistatic void tda998x_edid_delay_done(struct timer_list *t)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct tda998x_priv *priv = from_timer(priv, t, edid_delay_timer);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	priv->edid_delay_active = false;
75662306a36Sopenharmony_ci	wake_up(&priv->edid_delay_waitq);
75762306a36Sopenharmony_ci	schedule_work(&priv->detect_work);
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic void tda998x_edid_delay_start(struct tda998x_priv *priv)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	priv->edid_delay_active = true;
76362306a36Sopenharmony_ci	mod_timer(&priv->edid_delay_timer, jiffies + HZ/10);
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_cistatic int tda998x_edid_delay_wait(struct tda998x_priv *priv)
76762306a36Sopenharmony_ci{
76862306a36Sopenharmony_ci	return wait_event_killable(priv->edid_delay_waitq, !priv->edid_delay_active);
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci/*
77262306a36Sopenharmony_ci * We need to run the KMS hotplug event helper outside of our threaded
77362306a36Sopenharmony_ci * interrupt routine as this can call back into our get_modes method,
77462306a36Sopenharmony_ci * which will want to make use of interrupts.
77562306a36Sopenharmony_ci */
77662306a36Sopenharmony_cistatic void tda998x_detect_work(struct work_struct *work)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	struct tda998x_priv *priv =
77962306a36Sopenharmony_ci		container_of(work, struct tda998x_priv, detect_work);
78062306a36Sopenharmony_ci	struct drm_device *dev = priv->connector.dev;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (dev)
78362306a36Sopenharmony_ci		drm_kms_helper_hotplug_event(dev);
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci/*
78762306a36Sopenharmony_ci * only 2 interrupts may occur: screen plug/unplug and EDID read
78862306a36Sopenharmony_ci */
78962306a36Sopenharmony_cistatic irqreturn_t tda998x_irq_thread(int irq, void *data)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	struct tda998x_priv *priv = data;
79262306a36Sopenharmony_ci	u8 sta, cec, lvl, flag0, flag1, flag2;
79362306a36Sopenharmony_ci	bool handled = false;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	sta = cec_read(priv, REG_CEC_INTSTATUS);
79662306a36Sopenharmony_ci	if (sta & CEC_INTSTATUS_HDMI) {
79762306a36Sopenharmony_ci		cec = cec_read(priv, REG_CEC_RXSHPDINT);
79862306a36Sopenharmony_ci		lvl = cec_read(priv, REG_CEC_RXSHPDLEV);
79962306a36Sopenharmony_ci		flag0 = reg_read(priv, REG_INT_FLAGS_0);
80062306a36Sopenharmony_ci		flag1 = reg_read(priv, REG_INT_FLAGS_1);
80162306a36Sopenharmony_ci		flag2 = reg_read(priv, REG_INT_FLAGS_2);
80262306a36Sopenharmony_ci		DRM_DEBUG_DRIVER(
80362306a36Sopenharmony_ci			"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n",
80462306a36Sopenharmony_ci			sta, cec, lvl, flag0, flag1, flag2);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci		if (cec & CEC_RXSHPDINT_HPD) {
80762306a36Sopenharmony_ci			if (lvl & CEC_RXSHPDLEV_HPD) {
80862306a36Sopenharmony_ci				tda998x_edid_delay_start(priv);
80962306a36Sopenharmony_ci			} else {
81062306a36Sopenharmony_ci				schedule_work(&priv->detect_work);
81162306a36Sopenharmony_ci				cec_notifier_phys_addr_invalidate(
81262306a36Sopenharmony_ci						priv->cec_notify);
81362306a36Sopenharmony_ci			}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci			handled = true;
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) {
81962306a36Sopenharmony_ci			priv->wq_edid_wait = 0;
82062306a36Sopenharmony_ci			wake_up(&priv->wq_edid);
82162306a36Sopenharmony_ci			handled = true;
82262306a36Sopenharmony_ci		}
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	return IRQ_RETVAL(handled);
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic void
82962306a36Sopenharmony_citda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr,
83062306a36Sopenharmony_ci		 union hdmi_infoframe *frame)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	u8 buf[MAX_WRITE_RANGE_BUF];
83362306a36Sopenharmony_ci	ssize_t len;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	len = hdmi_infoframe_pack(frame, buf, sizeof(buf));
83662306a36Sopenharmony_ci	if (len < 0) {
83762306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev,
83862306a36Sopenharmony_ci			"hdmi_infoframe_pack() type=0x%02x failed: %zd\n",
83962306a36Sopenharmony_ci			frame->any.type, len);
84062306a36Sopenharmony_ci		return;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	reg_clear(priv, REG_DIP_IF_FLAGS, bit);
84462306a36Sopenharmony_ci	reg_write_range(priv, addr, buf, len);
84562306a36Sopenharmony_ci	reg_set(priv, REG_DIP_IF_FLAGS, bit);
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic void tda998x_write_aif(struct tda998x_priv *priv,
84962306a36Sopenharmony_ci			      const struct hdmi_audio_infoframe *cea)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	union hdmi_infoframe frame;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	frame.audio = *cea;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame);
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic void
85962306a36Sopenharmony_citda998x_write_avi(struct tda998x_priv *priv, const struct drm_display_mode *mode)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	union hdmi_infoframe frame;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
86462306a36Sopenharmony_ci						 &priv->connector, mode);
86562306a36Sopenharmony_ci	frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
86662306a36Sopenharmony_ci	drm_hdmi_avi_infoframe_quant_range(&frame.avi, &priv->connector, mode,
86762306a36Sopenharmony_ci					   priv->rgb_quant_range);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame);
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic void tda998x_write_vsi(struct tda998x_priv *priv,
87362306a36Sopenharmony_ci			      const struct drm_display_mode *mode)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	union hdmi_infoframe frame;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	if (drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
87862306a36Sopenharmony_ci							&priv->connector,
87962306a36Sopenharmony_ci							mode))
88062306a36Sopenharmony_ci		reg_clear(priv, REG_DIP_IF_FLAGS, DIP_IF_FLAGS_IF1);
88162306a36Sopenharmony_ci	else
88262306a36Sopenharmony_ci		tda998x_write_if(priv, DIP_IF_FLAGS_IF1, REG_IF1_HB0, &frame);
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/* Audio support */
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_cistatic const struct tda998x_audio_route tda998x_audio_route[AUDIO_ROUTE_NUM] = {
88862306a36Sopenharmony_ci	[AUDIO_ROUTE_I2S] = {
88962306a36Sopenharmony_ci		.ena_aclk = 1,
89062306a36Sopenharmony_ci		.mux_ap = MUX_AP_SELECT_I2S,
89162306a36Sopenharmony_ci		.aip_clksel = AIP_CLKSEL_AIP_I2S | AIP_CLKSEL_FS_ACLK,
89262306a36Sopenharmony_ci	},
89362306a36Sopenharmony_ci	[AUDIO_ROUTE_SPDIF] = {
89462306a36Sopenharmony_ci		.ena_aclk = 0,
89562306a36Sopenharmony_ci		.mux_ap = MUX_AP_SELECT_SPDIF,
89662306a36Sopenharmony_ci		.aip_clksel = AIP_CLKSEL_AIP_SPDIF | AIP_CLKSEL_FS_FS64SPDIF,
89762306a36Sopenharmony_ci	},
89862306a36Sopenharmony_ci};
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci/* Configure the TDA998x audio data and clock routing. */
90162306a36Sopenharmony_cistatic int tda998x_derive_routing(struct tda998x_priv *priv,
90262306a36Sopenharmony_ci				  struct tda998x_audio_settings *s,
90362306a36Sopenharmony_ci				  unsigned int route)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	s->route = &tda998x_audio_route[route];
90662306a36Sopenharmony_ci	s->ena_ap = priv->audio_port_enable[route];
90762306a36Sopenharmony_ci	if (s->ena_ap == 0) {
90862306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev, "no audio configuration found\n");
90962306a36Sopenharmony_ci		return -EINVAL;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	return 0;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci/*
91662306a36Sopenharmony_ci * The audio clock divisor register controls a divider producing Audio_Clk_Out
91762306a36Sopenharmony_ci * from SERclk by dividing it by 2^n where 0 <= n <= 5.  We don't know what
91862306a36Sopenharmony_ci * Audio_Clk_Out or SERclk are. We guess SERclk is the same as TMDS clock.
91962306a36Sopenharmony_ci *
92062306a36Sopenharmony_ci * It seems that Audio_Clk_Out must be the smallest value that is greater
92162306a36Sopenharmony_ci * than 128*fs, otherwise audio does not function. There is some suggestion
92262306a36Sopenharmony_ci * that 126*fs is a better value.
92362306a36Sopenharmony_ci */
92462306a36Sopenharmony_cistatic u8 tda998x_get_adiv(struct tda998x_priv *priv, unsigned int fs)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	unsigned long min_audio_clk = fs * 128;
92762306a36Sopenharmony_ci	unsigned long ser_clk = priv->tmds_clock * 1000;
92862306a36Sopenharmony_ci	u8 adiv;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	for (adiv = AUDIO_DIV_SERCLK_32; adiv != AUDIO_DIV_SERCLK_1; adiv--)
93162306a36Sopenharmony_ci		if (ser_clk > min_audio_clk << adiv)
93262306a36Sopenharmony_ci			break;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	dev_dbg(&priv->hdmi->dev,
93562306a36Sopenharmony_ci		"ser_clk=%luHz fs=%uHz min_aclk=%luHz adiv=%d\n",
93662306a36Sopenharmony_ci		ser_clk, fs, min_audio_clk, adiv);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	return adiv;
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci/*
94262306a36Sopenharmony_ci * In auto-CTS mode, the TDA998x uses a "measured time stamp" counter to
94362306a36Sopenharmony_ci * generate the CTS value.  It appears that the "measured time stamp" is
94462306a36Sopenharmony_ci * the number of TDMS clock cycles within a number of audio input clock
94562306a36Sopenharmony_ci * cycles defined by the k and N parameters defined below, in a similar
94662306a36Sopenharmony_ci * way to that which is set out in the CTS generation in the HDMI spec.
94762306a36Sopenharmony_ci *
94862306a36Sopenharmony_ci *  tmdsclk ----> mts -> /m ---> CTS
94962306a36Sopenharmony_ci *                 ^
95062306a36Sopenharmony_ci *  sclk -> /k -> /N
95162306a36Sopenharmony_ci *
95262306a36Sopenharmony_ci * CTS = mts / m, where m is 2^M.
95362306a36Sopenharmony_ci * /k is a divider based on the K value below, K+1 for K < 4, or 8 for K >= 4
95462306a36Sopenharmony_ci * /N is a divider based on the HDMI specified N value.
95562306a36Sopenharmony_ci *
95662306a36Sopenharmony_ci * This produces the following equation:
95762306a36Sopenharmony_ci *  CTS = tmds_clock * k * N / (sclk * m)
95862306a36Sopenharmony_ci *
95962306a36Sopenharmony_ci * When combined with the sink-side equation, and realising that sclk is
96062306a36Sopenharmony_ci * bclk_ratio * fs, we end up with:
96162306a36Sopenharmony_ci *  k = m * bclk_ratio / 128.
96262306a36Sopenharmony_ci *
96362306a36Sopenharmony_ci * Note: S/PDIF always uses a bclk_ratio of 64.
96462306a36Sopenharmony_ci */
96562306a36Sopenharmony_cistatic int tda998x_derive_cts_n(struct tda998x_priv *priv,
96662306a36Sopenharmony_ci				struct tda998x_audio_settings *settings,
96762306a36Sopenharmony_ci				unsigned int ratio)
96862306a36Sopenharmony_ci{
96962306a36Sopenharmony_ci	switch (ratio) {
97062306a36Sopenharmony_ci	case 16:
97162306a36Sopenharmony_ci		settings->cts_n = CTS_N_M(3) | CTS_N_K(0);
97262306a36Sopenharmony_ci		break;
97362306a36Sopenharmony_ci	case 32:
97462306a36Sopenharmony_ci		settings->cts_n = CTS_N_M(3) | CTS_N_K(1);
97562306a36Sopenharmony_ci		break;
97662306a36Sopenharmony_ci	case 48:
97762306a36Sopenharmony_ci		settings->cts_n = CTS_N_M(3) | CTS_N_K(2);
97862306a36Sopenharmony_ci		break;
97962306a36Sopenharmony_ci	case 64:
98062306a36Sopenharmony_ci		settings->cts_n = CTS_N_M(3) | CTS_N_K(3);
98162306a36Sopenharmony_ci		break;
98262306a36Sopenharmony_ci	case 128:
98362306a36Sopenharmony_ci		settings->cts_n = CTS_N_M(0) | CTS_N_K(0);
98462306a36Sopenharmony_ci		break;
98562306a36Sopenharmony_ci	default:
98662306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev, "unsupported bclk ratio %ufs\n",
98762306a36Sopenharmony_ci			ratio);
98862306a36Sopenharmony_ci		return -EINVAL;
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci	return 0;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cistatic void tda998x_audio_mute(struct tda998x_priv *priv, bool on)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	if (on) {
99662306a36Sopenharmony_ci		reg_set(priv, REG_SOFTRESET, SOFTRESET_AUDIO);
99762306a36Sopenharmony_ci		reg_clear(priv, REG_SOFTRESET, SOFTRESET_AUDIO);
99862306a36Sopenharmony_ci		reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
99962306a36Sopenharmony_ci	} else {
100062306a36Sopenharmony_ci		reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic void tda998x_configure_audio(struct tda998x_priv *priv)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	const struct tda998x_audio_settings *settings = &priv->audio;
100762306a36Sopenharmony_ci	u8 buf[6], adiv;
100862306a36Sopenharmony_ci	u32 n;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/* If audio is not configured, there is nothing to do. */
101162306a36Sopenharmony_ci	if (settings->ena_ap == 0)
101262306a36Sopenharmony_ci		return;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	adiv = tda998x_get_adiv(priv, settings->sample_rate);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	/* Enable audio ports */
101762306a36Sopenharmony_ci	reg_write(priv, REG_ENA_AP, settings->ena_ap);
101862306a36Sopenharmony_ci	reg_write(priv, REG_ENA_ACLK, settings->route->ena_aclk);
101962306a36Sopenharmony_ci	reg_write(priv, REG_MUX_AP, settings->route->mux_ap);
102062306a36Sopenharmony_ci	reg_write(priv, REG_I2S_FORMAT, settings->i2s_format);
102162306a36Sopenharmony_ci	reg_write(priv, REG_AIP_CLKSEL, settings->route->aip_clksel);
102262306a36Sopenharmony_ci	reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT |
102362306a36Sopenharmony_ci					AIP_CNTRL_0_ACR_MAN);	/* auto CTS */
102462306a36Sopenharmony_ci	reg_write(priv, REG_CTS_N, settings->cts_n);
102562306a36Sopenharmony_ci	reg_write(priv, REG_AUDIO_DIV, adiv);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	/*
102862306a36Sopenharmony_ci	 * This is the approximate value of N, which happens to be
102962306a36Sopenharmony_ci	 * the recommended values for non-coherent clocks.
103062306a36Sopenharmony_ci	 */
103162306a36Sopenharmony_ci	n = 128 * settings->sample_rate / 1000;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	/* Write the CTS and N values */
103462306a36Sopenharmony_ci	buf[0] = 0x44;
103562306a36Sopenharmony_ci	buf[1] = 0x42;
103662306a36Sopenharmony_ci	buf[2] = 0x01;
103762306a36Sopenharmony_ci	buf[3] = n;
103862306a36Sopenharmony_ci	buf[4] = n >> 8;
103962306a36Sopenharmony_ci	buf[5] = n >> 16;
104062306a36Sopenharmony_ci	reg_write_range(priv, REG_ACR_CTS_0, buf, 6);
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	/* Reset CTS generator */
104362306a36Sopenharmony_ci	reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
104462306a36Sopenharmony_ci	reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	/* Write the channel status
104762306a36Sopenharmony_ci	 * The REG_CH_STAT_B-registers skip IEC958 AES2 byte, because
104862306a36Sopenharmony_ci	 * there is a separate register for each I2S wire.
104962306a36Sopenharmony_ci	 */
105062306a36Sopenharmony_ci	buf[0] = settings->status[0];
105162306a36Sopenharmony_ci	buf[1] = settings->status[1];
105262306a36Sopenharmony_ci	buf[2] = settings->status[3];
105362306a36Sopenharmony_ci	buf[3] = settings->status[4];
105462306a36Sopenharmony_ci	reg_write_range(priv, REG_CH_STAT_B(0), buf, 4);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	tda998x_audio_mute(priv, true);
105762306a36Sopenharmony_ci	msleep(20);
105862306a36Sopenharmony_ci	tda998x_audio_mute(priv, false);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	tda998x_write_aif(priv, &settings->cea);
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_cistatic int tda998x_audio_hw_params(struct device *dev, void *data,
106462306a36Sopenharmony_ci				   struct hdmi_codec_daifmt *daifmt,
106562306a36Sopenharmony_ci				   struct hdmi_codec_params *params)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct tda998x_priv *priv = dev_get_drvdata(dev);
106862306a36Sopenharmony_ci	unsigned int bclk_ratio;
106962306a36Sopenharmony_ci	bool spdif = daifmt->fmt == HDMI_SPDIF;
107062306a36Sopenharmony_ci	int ret;
107162306a36Sopenharmony_ci	struct tda998x_audio_settings audio = {
107262306a36Sopenharmony_ci		.sample_rate = params->sample_rate,
107362306a36Sopenharmony_ci		.cea = params->cea,
107462306a36Sopenharmony_ci	};
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	memcpy(audio.status, params->iec.status,
107762306a36Sopenharmony_ci	       min(sizeof(audio.status), sizeof(params->iec.status)));
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	switch (daifmt->fmt) {
108062306a36Sopenharmony_ci	case HDMI_I2S:
108162306a36Sopenharmony_ci		audio.i2s_format = I2S_FORMAT_PHILIPS;
108262306a36Sopenharmony_ci		break;
108362306a36Sopenharmony_ci	case HDMI_LEFT_J:
108462306a36Sopenharmony_ci		audio.i2s_format = I2S_FORMAT_LEFT_J;
108562306a36Sopenharmony_ci		break;
108662306a36Sopenharmony_ci	case HDMI_RIGHT_J:
108762306a36Sopenharmony_ci		audio.i2s_format = I2S_FORMAT_RIGHT_J;
108862306a36Sopenharmony_ci		break;
108962306a36Sopenharmony_ci	case HDMI_SPDIF:
109062306a36Sopenharmony_ci		audio.i2s_format = 0;
109162306a36Sopenharmony_ci		break;
109262306a36Sopenharmony_ci	default:
109362306a36Sopenharmony_ci		dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt);
109462306a36Sopenharmony_ci		return -EINVAL;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (!spdif &&
109862306a36Sopenharmony_ci	    (daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
109962306a36Sopenharmony_ci	     daifmt->bit_clk_provider || daifmt->frame_clk_provider)) {
110062306a36Sopenharmony_ci		dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
110162306a36Sopenharmony_ci			daifmt->bit_clk_inv, daifmt->frame_clk_inv,
110262306a36Sopenharmony_ci			daifmt->bit_clk_provider,
110362306a36Sopenharmony_ci			daifmt->frame_clk_provider);
110462306a36Sopenharmony_ci		return -EINVAL;
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	ret = tda998x_derive_routing(priv, &audio, AUDIO_ROUTE_I2S + spdif);
110862306a36Sopenharmony_ci	if (ret < 0)
110962306a36Sopenharmony_ci		return ret;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	bclk_ratio = spdif ? 64 : params->sample_width * 2;
111262306a36Sopenharmony_ci	ret = tda998x_derive_cts_n(priv, &audio, bclk_ratio);
111362306a36Sopenharmony_ci	if (ret < 0)
111462306a36Sopenharmony_ci		return ret;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	mutex_lock(&priv->audio_mutex);
111762306a36Sopenharmony_ci	priv->audio = audio;
111862306a36Sopenharmony_ci	if (priv->supports_infoframes && priv->sink_has_audio)
111962306a36Sopenharmony_ci		tda998x_configure_audio(priv);
112062306a36Sopenharmony_ci	mutex_unlock(&priv->audio_mutex);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	return 0;
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_cistatic void tda998x_audio_shutdown(struct device *dev, void *data)
112662306a36Sopenharmony_ci{
112762306a36Sopenharmony_ci	struct tda998x_priv *priv = dev_get_drvdata(dev);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	mutex_lock(&priv->audio_mutex);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	reg_write(priv, REG_ENA_AP, 0);
113262306a36Sopenharmony_ci	priv->audio.ena_ap = 0;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	mutex_unlock(&priv->audio_mutex);
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic int tda998x_audio_mute_stream(struct device *dev, void *data,
113862306a36Sopenharmony_ci				     bool enable, int direction)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	struct tda998x_priv *priv = dev_get_drvdata(dev);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	mutex_lock(&priv->audio_mutex);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	tda998x_audio_mute(priv, enable);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	mutex_unlock(&priv->audio_mutex);
114762306a36Sopenharmony_ci	return 0;
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic int tda998x_audio_get_eld(struct device *dev, void *data,
115162306a36Sopenharmony_ci				 uint8_t *buf, size_t len)
115262306a36Sopenharmony_ci{
115362306a36Sopenharmony_ci	struct tda998x_priv *priv = dev_get_drvdata(dev);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	mutex_lock(&priv->audio_mutex);
115662306a36Sopenharmony_ci	memcpy(buf, priv->connector.eld,
115762306a36Sopenharmony_ci	       min(sizeof(priv->connector.eld), len));
115862306a36Sopenharmony_ci	mutex_unlock(&priv->audio_mutex);
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	return 0;
116162306a36Sopenharmony_ci}
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_cistatic const struct hdmi_codec_ops audio_codec_ops = {
116462306a36Sopenharmony_ci	.hw_params = tda998x_audio_hw_params,
116562306a36Sopenharmony_ci	.audio_shutdown = tda998x_audio_shutdown,
116662306a36Sopenharmony_ci	.mute_stream = tda998x_audio_mute_stream,
116762306a36Sopenharmony_ci	.get_eld = tda998x_audio_get_eld,
116862306a36Sopenharmony_ci	.no_capture_mute = 1,
116962306a36Sopenharmony_ci};
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_cistatic int tda998x_audio_codec_init(struct tda998x_priv *priv,
117262306a36Sopenharmony_ci				    struct device *dev)
117362306a36Sopenharmony_ci{
117462306a36Sopenharmony_ci	struct hdmi_codec_pdata codec_data = {
117562306a36Sopenharmony_ci		.ops = &audio_codec_ops,
117662306a36Sopenharmony_ci		.max_i2s_channels = 2,
117762306a36Sopenharmony_ci		.no_i2s_capture = 1,
117862306a36Sopenharmony_ci		.no_spdif_capture = 1,
117962306a36Sopenharmony_ci	};
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	if (priv->audio_port_enable[AUDIO_ROUTE_I2S])
118262306a36Sopenharmony_ci		codec_data.i2s = 1;
118362306a36Sopenharmony_ci	if (priv->audio_port_enable[AUDIO_ROUTE_SPDIF])
118462306a36Sopenharmony_ci		codec_data.spdif = 1;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	priv->audio_pdev = platform_device_register_data(
118762306a36Sopenharmony_ci		dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
118862306a36Sopenharmony_ci		&codec_data, sizeof(codec_data));
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(priv->audio_pdev);
119162306a36Sopenharmony_ci}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci/* DRM connector functions */
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic enum drm_connector_status
119662306a36Sopenharmony_citda998x_connector_detect(struct drm_connector *connector, bool force)
119762306a36Sopenharmony_ci{
119862306a36Sopenharmony_ci	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
119962306a36Sopenharmony_ci	u8 val = cec_read(priv, REG_CEC_RXSHPDLEV);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
120262306a36Sopenharmony_ci			connector_status_disconnected;
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic void tda998x_connector_destroy(struct drm_connector *connector)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	drm_connector_cleanup(connector);
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_cistatic const struct drm_connector_funcs tda998x_connector_funcs = {
121162306a36Sopenharmony_ci	.reset = drm_atomic_helper_connector_reset,
121262306a36Sopenharmony_ci	.fill_modes = drm_helper_probe_single_connector_modes,
121362306a36Sopenharmony_ci	.detect = tda998x_connector_detect,
121462306a36Sopenharmony_ci	.destroy = tda998x_connector_destroy,
121562306a36Sopenharmony_ci	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
121662306a36Sopenharmony_ci	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
121762306a36Sopenharmony_ci};
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	struct tda998x_priv *priv = data;
122262306a36Sopenharmony_ci	u8 offset, segptr;
122362306a36Sopenharmony_ci	int ret, i;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	offset = (blk & 1) ? 128 : 0;
122662306a36Sopenharmony_ci	segptr = blk / 2;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	mutex_lock(&priv->edid_mutex);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	reg_write(priv, REG_DDC_ADDR, 0xa0);
123162306a36Sopenharmony_ci	reg_write(priv, REG_DDC_OFFS, offset);
123262306a36Sopenharmony_ci	reg_write(priv, REG_DDC_SEGM_ADDR, 0x60);
123362306a36Sopenharmony_ci	reg_write(priv, REG_DDC_SEGM, segptr);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	/* enable reading EDID: */
123662306a36Sopenharmony_ci	priv->wq_edid_wait = 1;
123762306a36Sopenharmony_ci	reg_write(priv, REG_EDID_CTRL, 0x1);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	/* flag must be cleared by sw: */
124062306a36Sopenharmony_ci	reg_write(priv, REG_EDID_CTRL, 0x0);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	/* wait for block read to complete: */
124362306a36Sopenharmony_ci	if (priv->hdmi->irq) {
124462306a36Sopenharmony_ci		i = wait_event_timeout(priv->wq_edid,
124562306a36Sopenharmony_ci					!priv->wq_edid_wait,
124662306a36Sopenharmony_ci					msecs_to_jiffies(100));
124762306a36Sopenharmony_ci		if (i < 0) {
124862306a36Sopenharmony_ci			dev_err(&priv->hdmi->dev, "read edid wait err %d\n", i);
124962306a36Sopenharmony_ci			ret = i;
125062306a36Sopenharmony_ci			goto failed;
125162306a36Sopenharmony_ci		}
125262306a36Sopenharmony_ci	} else {
125362306a36Sopenharmony_ci		for (i = 100; i > 0; i--) {
125462306a36Sopenharmony_ci			msleep(1);
125562306a36Sopenharmony_ci			ret = reg_read(priv, REG_INT_FLAGS_2);
125662306a36Sopenharmony_ci			if (ret < 0)
125762306a36Sopenharmony_ci				goto failed;
125862306a36Sopenharmony_ci			if (ret & INT_FLAGS_2_EDID_BLK_RD)
125962306a36Sopenharmony_ci				break;
126062306a36Sopenharmony_ci		}
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	if (i == 0) {
126462306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev, "read edid timeout\n");
126562306a36Sopenharmony_ci		ret = -ETIMEDOUT;
126662306a36Sopenharmony_ci		goto failed;
126762306a36Sopenharmony_ci	}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	ret = reg_read_range(priv, REG_EDID_DATA_0, buf, length);
127062306a36Sopenharmony_ci	if (ret != length) {
127162306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev, "failed to read edid block %d: %d\n",
127262306a36Sopenharmony_ci			blk, ret);
127362306a36Sopenharmony_ci		goto failed;
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	ret = 0;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci failed:
127962306a36Sopenharmony_ci	mutex_unlock(&priv->edid_mutex);
128062306a36Sopenharmony_ci	return ret;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int tda998x_connector_get_modes(struct drm_connector *connector)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
128662306a36Sopenharmony_ci	struct edid *edid;
128762306a36Sopenharmony_ci	int n;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	/*
129062306a36Sopenharmony_ci	 * If we get killed while waiting for the HPD timeout, return
129162306a36Sopenharmony_ci	 * no modes found: we are not in a restartable path, so we
129262306a36Sopenharmony_ci	 * can't handle signals gracefully.
129362306a36Sopenharmony_ci	 */
129462306a36Sopenharmony_ci	if (tda998x_edid_delay_wait(priv))
129562306a36Sopenharmony_ci		return 0;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	if (priv->rev == TDA19988)
129862306a36Sopenharmony_ci		reg_clear(priv, REG_TX4, TX4_PD_RAM);
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	edid = drm_do_get_edid(connector, read_edid_block, priv);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	if (priv->rev == TDA19988)
130362306a36Sopenharmony_ci		reg_set(priv, REG_TX4, TX4_PD_RAM);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	if (!edid) {
130662306a36Sopenharmony_ci		dev_warn(&priv->hdmi->dev, "failed to read EDID\n");
130762306a36Sopenharmony_ci		return 0;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	drm_connector_update_edid_property(connector, edid);
131162306a36Sopenharmony_ci	cec_notifier_set_phys_addr_from_edid(priv->cec_notify, edid);
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	mutex_lock(&priv->audio_mutex);
131462306a36Sopenharmony_ci	n = drm_add_edid_modes(connector, edid);
131562306a36Sopenharmony_ci	priv->sink_has_audio = drm_detect_monitor_audio(edid);
131662306a36Sopenharmony_ci	mutex_unlock(&priv->audio_mutex);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	kfree(edid);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	return n;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cistatic struct drm_encoder *
132462306a36Sopenharmony_citda998x_connector_best_encoder(struct drm_connector *connector)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	return priv->bridge.encoder;
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cistatic
133262306a36Sopenharmony_ciconst struct drm_connector_helper_funcs tda998x_connector_helper_funcs = {
133362306a36Sopenharmony_ci	.get_modes = tda998x_connector_get_modes,
133462306a36Sopenharmony_ci	.best_encoder = tda998x_connector_best_encoder,
133562306a36Sopenharmony_ci};
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic int tda998x_connector_init(struct tda998x_priv *priv,
133862306a36Sopenharmony_ci				  struct drm_device *drm)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	struct drm_connector *connector = &priv->connector;
134162306a36Sopenharmony_ci	int ret;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	connector->interlace_allowed = 1;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (priv->hdmi->irq)
134662306a36Sopenharmony_ci		connector->polled = DRM_CONNECTOR_POLL_HPD;
134762306a36Sopenharmony_ci	else
134862306a36Sopenharmony_ci		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
134962306a36Sopenharmony_ci			DRM_CONNECTOR_POLL_DISCONNECT;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	drm_connector_helper_add(connector, &tda998x_connector_helper_funcs);
135262306a36Sopenharmony_ci	ret = drm_connector_init(drm, connector, &tda998x_connector_funcs,
135362306a36Sopenharmony_ci				 DRM_MODE_CONNECTOR_HDMIA);
135462306a36Sopenharmony_ci	if (ret)
135562306a36Sopenharmony_ci		return ret;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	drm_connector_attach_encoder(&priv->connector,
135862306a36Sopenharmony_ci				     priv->bridge.encoder);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	return 0;
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci/* DRM bridge functions */
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic int tda998x_bridge_attach(struct drm_bridge *bridge,
136662306a36Sopenharmony_ci				 enum drm_bridge_attach_flags flags)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
137162306a36Sopenharmony_ci		DRM_ERROR("Fix bridge driver to make connector optional!");
137262306a36Sopenharmony_ci		return -EINVAL;
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	return tda998x_connector_init(priv, bridge->dev);
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_cistatic void tda998x_bridge_detach(struct drm_bridge *bridge)
137962306a36Sopenharmony_ci{
138062306a36Sopenharmony_ci	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	drm_connector_cleanup(&priv->connector);
138362306a36Sopenharmony_ci}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_cistatic enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge,
138662306a36Sopenharmony_ci				     const struct drm_display_info *info,
138762306a36Sopenharmony_ci				     const struct drm_display_mode *mode)
138862306a36Sopenharmony_ci{
138962306a36Sopenharmony_ci	/* TDA19988 dotclock can go up to 165MHz */
139062306a36Sopenharmony_ci	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	if (mode->clock > ((priv->rev == TDA19988) ? 165000 : 150000))
139362306a36Sopenharmony_ci		return MODE_CLOCK_HIGH;
139462306a36Sopenharmony_ci	if (mode->htotal >= BIT(13))
139562306a36Sopenharmony_ci		return MODE_BAD_HVALUE;
139662306a36Sopenharmony_ci	if (mode->vtotal >= BIT(11))
139762306a36Sopenharmony_ci		return MODE_BAD_VVALUE;
139862306a36Sopenharmony_ci	return MODE_OK;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic void tda998x_bridge_enable(struct drm_bridge *bridge)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (!priv->is_on) {
140662306a36Sopenharmony_ci		/* enable video ports, audio will be enabled later */
140762306a36Sopenharmony_ci		reg_write(priv, REG_ENA_VP_0, 0xff);
140862306a36Sopenharmony_ci		reg_write(priv, REG_ENA_VP_1, 0xff);
140962306a36Sopenharmony_ci		reg_write(priv, REG_ENA_VP_2, 0xff);
141062306a36Sopenharmony_ci		/* set muxing after enabling ports: */
141162306a36Sopenharmony_ci		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
141262306a36Sopenharmony_ci		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
141362306a36Sopenharmony_ci		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		priv->is_on = true;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic void tda998x_bridge_disable(struct drm_bridge *bridge)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	if (priv->is_on) {
142462306a36Sopenharmony_ci		/* disable video ports */
142562306a36Sopenharmony_ci		reg_write(priv, REG_ENA_VP_0, 0x00);
142662306a36Sopenharmony_ci		reg_write(priv, REG_ENA_VP_1, 0x00);
142762306a36Sopenharmony_ci		reg_write(priv, REG_ENA_VP_2, 0x00);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci		priv->is_on = false;
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic void tda998x_bridge_mode_set(struct drm_bridge *bridge,
143462306a36Sopenharmony_ci				    const struct drm_display_mode *mode,
143562306a36Sopenharmony_ci				    const struct drm_display_mode *adjusted_mode)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
143862306a36Sopenharmony_ci	unsigned long tmds_clock;
143962306a36Sopenharmony_ci	u16 ref_pix, ref_line, n_pix, n_line;
144062306a36Sopenharmony_ci	u16 hs_pix_s, hs_pix_e;
144162306a36Sopenharmony_ci	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
144262306a36Sopenharmony_ci	u16 vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e;
144362306a36Sopenharmony_ci	u16 vwin1_line_s, vwin1_line_e;
144462306a36Sopenharmony_ci	u16 vwin2_line_s, vwin2_line_e;
144562306a36Sopenharmony_ci	u16 de_pix_s, de_pix_e;
144662306a36Sopenharmony_ci	u8 reg, div, rep, sel_clk;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	/*
144962306a36Sopenharmony_ci	 * Since we are "computer" like, our source invariably produces
145062306a36Sopenharmony_ci	 * full-range RGB.  If the monitor supports full-range, then use
145162306a36Sopenharmony_ci	 * it, otherwise reduce to limited-range.
145262306a36Sopenharmony_ci	 */
145362306a36Sopenharmony_ci	priv->rgb_quant_range =
145462306a36Sopenharmony_ci		priv->connector.display_info.rgb_quant_range_selectable ?
145562306a36Sopenharmony_ci		HDMI_QUANTIZATION_RANGE_FULL :
145662306a36Sopenharmony_ci		drm_default_rgb_quant_range(adjusted_mode);
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	/*
145962306a36Sopenharmony_ci	 * Internally TDA998x is using ITU-R BT.656 style sync but
146062306a36Sopenharmony_ci	 * we get VESA style sync. TDA998x is using a reference pixel
146162306a36Sopenharmony_ci	 * relative to ITU to sync to the input frame and for output
146262306a36Sopenharmony_ci	 * sync generation. Currently, we are using reference detection
146362306a36Sopenharmony_ci	 * from HS/VS, i.e. REFPIX/REFLINE denote frame start sync point
146462306a36Sopenharmony_ci	 * which is position of rising VS with coincident rising HS.
146562306a36Sopenharmony_ci	 *
146662306a36Sopenharmony_ci	 * Now there is some issues to take care of:
146762306a36Sopenharmony_ci	 * - HDMI data islands require sync-before-active
146862306a36Sopenharmony_ci	 * - TDA998x register values must be > 0 to be enabled
146962306a36Sopenharmony_ci	 * - REFLINE needs an additional offset of +1
147062306a36Sopenharmony_ci	 * - REFPIX needs an addtional offset of +1 for UYUV and +3 for RGB
147162306a36Sopenharmony_ci	 *
147262306a36Sopenharmony_ci	 * So we add +1 to all horizontal and vertical register values,
147362306a36Sopenharmony_ci	 * plus an additional +3 for REFPIX as we are using RGB input only.
147462306a36Sopenharmony_ci	 */
147562306a36Sopenharmony_ci	n_pix        = mode->htotal;
147662306a36Sopenharmony_ci	n_line       = mode->vtotal;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	hs_pix_e     = mode->hsync_end - mode->hdisplay;
147962306a36Sopenharmony_ci	hs_pix_s     = mode->hsync_start - mode->hdisplay;
148062306a36Sopenharmony_ci	de_pix_e     = mode->htotal;
148162306a36Sopenharmony_ci	de_pix_s     = mode->htotal - mode->hdisplay;
148262306a36Sopenharmony_ci	ref_pix      = 3 + hs_pix_s;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	/*
148562306a36Sopenharmony_ci	 * Attached LCD controllers may generate broken sync. Allow
148662306a36Sopenharmony_ci	 * those to adjust the position of the rising VS edge by adding
148762306a36Sopenharmony_ci	 * HSKEW to ref_pix.
148862306a36Sopenharmony_ci	 */
148962306a36Sopenharmony_ci	if (adjusted_mode->flags & DRM_MODE_FLAG_HSKEW)
149062306a36Sopenharmony_ci		ref_pix += adjusted_mode->hskew;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0) {
149362306a36Sopenharmony_ci		ref_line     = 1 + mode->vsync_start - mode->vdisplay;
149462306a36Sopenharmony_ci		vwin1_line_s = mode->vtotal - mode->vdisplay - 1;
149562306a36Sopenharmony_ci		vwin1_line_e = vwin1_line_s + mode->vdisplay;
149662306a36Sopenharmony_ci		vs1_pix_s    = vs1_pix_e = hs_pix_s;
149762306a36Sopenharmony_ci		vs1_line_s   = mode->vsync_start - mode->vdisplay;
149862306a36Sopenharmony_ci		vs1_line_e   = vs1_line_s +
149962306a36Sopenharmony_ci			       mode->vsync_end - mode->vsync_start;
150062306a36Sopenharmony_ci		vwin2_line_s = vwin2_line_e = 0;
150162306a36Sopenharmony_ci		vs2_pix_s    = vs2_pix_e  = 0;
150262306a36Sopenharmony_ci		vs2_line_s   = vs2_line_e = 0;
150362306a36Sopenharmony_ci	} else {
150462306a36Sopenharmony_ci		ref_line     = 1 + (mode->vsync_start - mode->vdisplay)/2;
150562306a36Sopenharmony_ci		vwin1_line_s = (mode->vtotal - mode->vdisplay)/2;
150662306a36Sopenharmony_ci		vwin1_line_e = vwin1_line_s + mode->vdisplay/2;
150762306a36Sopenharmony_ci		vs1_pix_s    = vs1_pix_e = hs_pix_s;
150862306a36Sopenharmony_ci		vs1_line_s   = (mode->vsync_start - mode->vdisplay)/2;
150962306a36Sopenharmony_ci		vs1_line_e   = vs1_line_s +
151062306a36Sopenharmony_ci			       (mode->vsync_end - mode->vsync_start)/2;
151162306a36Sopenharmony_ci		vwin2_line_s = vwin1_line_s + mode->vtotal/2;
151262306a36Sopenharmony_ci		vwin2_line_e = vwin2_line_s + mode->vdisplay/2;
151362306a36Sopenharmony_ci		vs2_pix_s    = vs2_pix_e = hs_pix_s + mode->htotal/2;
151462306a36Sopenharmony_ci		vs2_line_s   = vs1_line_s + mode->vtotal/2 ;
151562306a36Sopenharmony_ci		vs2_line_e   = vs2_line_s +
151662306a36Sopenharmony_ci			       (mode->vsync_end - mode->vsync_start)/2;
151762306a36Sopenharmony_ci	}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	/*
152062306a36Sopenharmony_ci	 * Select pixel repeat depending on the double-clock flag
152162306a36Sopenharmony_ci	 * (which means we have to repeat each pixel once.)
152262306a36Sopenharmony_ci	 */
152362306a36Sopenharmony_ci	rep = mode->flags & DRM_MODE_FLAG_DBLCLK ? 1 : 0;
152462306a36Sopenharmony_ci	sel_clk = SEL_CLK_ENA_SC_CLK | SEL_CLK_SEL_CLK1 |
152562306a36Sopenharmony_ci		  SEL_CLK_SEL_VRF_CLK(rep ? 2 : 0);
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	/* the TMDS clock is scaled up by the pixel repeat */
152862306a36Sopenharmony_ci	tmds_clock = mode->clock * (1 + rep);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/*
153162306a36Sopenharmony_ci	 * The divisor is power-of-2. The TDA9983B datasheet gives
153262306a36Sopenharmony_ci	 * this as ranges of Msample/s, which is 10x the TMDS clock:
153362306a36Sopenharmony_ci	 *   0 - 800 to 1500 Msample/s
153462306a36Sopenharmony_ci	 *   1 - 400 to 800 Msample/s
153562306a36Sopenharmony_ci	 *   2 - 200 to 400 Msample/s
153662306a36Sopenharmony_ci	 *   3 - as 2 above
153762306a36Sopenharmony_ci	 */
153862306a36Sopenharmony_ci	for (div = 0; div < 3; div++)
153962306a36Sopenharmony_ci		if (80000 >> div <= tmds_clock)
154062306a36Sopenharmony_ci			break;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	mutex_lock(&priv->audio_mutex);
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	priv->tmds_clock = tmds_clock;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	/* mute the audio FIFO: */
154762306a36Sopenharmony_ci	reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	/* set HDMI HDCP mode off: */
155062306a36Sopenharmony_ci	reg_write(priv, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
155162306a36Sopenharmony_ci	reg_clear(priv, REG_TX33, TX33_HDMI);
155262306a36Sopenharmony_ci	reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(0));
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	/* no pre-filter or interpolator: */
155562306a36Sopenharmony_ci	reg_write(priv, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) |
155662306a36Sopenharmony_ci			HVF_CNTRL_0_INTPOL(0));
155762306a36Sopenharmony_ci	reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_PREFILT);
155862306a36Sopenharmony_ci	reg_write(priv, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
155962306a36Sopenharmony_ci	reg_write(priv, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) |
156062306a36Sopenharmony_ci			VIP_CNTRL_4_BLC(0));
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	reg_clear(priv, REG_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IZ);
156362306a36Sopenharmony_ci	reg_clear(priv, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR |
156462306a36Sopenharmony_ci					  PLL_SERIAL_3_SRL_DE);
156562306a36Sopenharmony_ci	reg_write(priv, REG_SERIALIZER, 0);
156662306a36Sopenharmony_ci	reg_write(priv, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR(0));
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	reg_write(priv, REG_RPT_CNTRL, RPT_CNTRL_REPEAT(rep));
156962306a36Sopenharmony_ci	reg_write(priv, REG_SEL_CLK, sel_clk);
157062306a36Sopenharmony_ci	reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
157162306a36Sopenharmony_ci			PLL_SERIAL_2_SRL_PR(rep));
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	/* set color matrix according to output rgb quant range */
157462306a36Sopenharmony_ci	if (priv->rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) {
157562306a36Sopenharmony_ci		static u8 tda998x_full_to_limited_range[] = {
157662306a36Sopenharmony_ci			MAT_CONTRL_MAT_SC(2),
157762306a36Sopenharmony_ci			0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157862306a36Sopenharmony_ci			0x03, 0x6f, 0x00, 0x00, 0x00, 0x00,
157962306a36Sopenharmony_ci			0x00, 0x00, 0x03, 0x6f, 0x00, 0x00,
158062306a36Sopenharmony_ci			0x00, 0x00, 0x00, 0x00, 0x03, 0x6f,
158162306a36Sopenharmony_ci			0x00, 0x40, 0x00, 0x40, 0x00, 0x40
158262306a36Sopenharmony_ci		};
158362306a36Sopenharmony_ci		reg_clear(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);
158462306a36Sopenharmony_ci		reg_write_range(priv, REG_MAT_CONTRL,
158562306a36Sopenharmony_ci				tda998x_full_to_limited_range,
158662306a36Sopenharmony_ci				sizeof(tda998x_full_to_limited_range));
158762306a36Sopenharmony_ci	} else {
158862306a36Sopenharmony_ci		reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP |
158962306a36Sopenharmony_ci					MAT_CONTRL_MAT_SC(1));
159062306a36Sopenharmony_ci		reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	/* set BIAS tmds value: */
159462306a36Sopenharmony_ci	reg_write(priv, REG_ANA_GENERAL, 0x09);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	/*
159762306a36Sopenharmony_ci	 * Sync on rising HSYNC/VSYNC
159862306a36Sopenharmony_ci	 */
159962306a36Sopenharmony_ci	reg = VIP_CNTRL_3_SYNC_HS;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	/*
160262306a36Sopenharmony_ci	 * TDA19988 requires high-active sync at input stage,
160362306a36Sopenharmony_ci	 * so invert low-active sync provided by master encoder here
160462306a36Sopenharmony_ci	 */
160562306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
160662306a36Sopenharmony_ci		reg |= VIP_CNTRL_3_H_TGL;
160762306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
160862306a36Sopenharmony_ci		reg |= VIP_CNTRL_3_V_TGL;
160962306a36Sopenharmony_ci	reg_write(priv, REG_VIP_CNTRL_3, reg);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	reg_write(priv, REG_VIDFORMAT, 0x00);
161262306a36Sopenharmony_ci	reg_write16(priv, REG_REFPIX_MSB, ref_pix);
161362306a36Sopenharmony_ci	reg_write16(priv, REG_REFLINE_MSB, ref_line);
161462306a36Sopenharmony_ci	reg_write16(priv, REG_NPIX_MSB, n_pix);
161562306a36Sopenharmony_ci	reg_write16(priv, REG_NLINE_MSB, n_line);
161662306a36Sopenharmony_ci	reg_write16(priv, REG_VS_LINE_STRT_1_MSB, vs1_line_s);
161762306a36Sopenharmony_ci	reg_write16(priv, REG_VS_PIX_STRT_1_MSB, vs1_pix_s);
161862306a36Sopenharmony_ci	reg_write16(priv, REG_VS_LINE_END_1_MSB, vs1_line_e);
161962306a36Sopenharmony_ci	reg_write16(priv, REG_VS_PIX_END_1_MSB, vs1_pix_e);
162062306a36Sopenharmony_ci	reg_write16(priv, REG_VS_LINE_STRT_2_MSB, vs2_line_s);
162162306a36Sopenharmony_ci	reg_write16(priv, REG_VS_PIX_STRT_2_MSB, vs2_pix_s);
162262306a36Sopenharmony_ci	reg_write16(priv, REG_VS_LINE_END_2_MSB, vs2_line_e);
162362306a36Sopenharmony_ci	reg_write16(priv, REG_VS_PIX_END_2_MSB, vs2_pix_e);
162462306a36Sopenharmony_ci	reg_write16(priv, REG_HS_PIX_START_MSB, hs_pix_s);
162562306a36Sopenharmony_ci	reg_write16(priv, REG_HS_PIX_STOP_MSB, hs_pix_e);
162662306a36Sopenharmony_ci	reg_write16(priv, REG_VWIN_START_1_MSB, vwin1_line_s);
162762306a36Sopenharmony_ci	reg_write16(priv, REG_VWIN_END_1_MSB, vwin1_line_e);
162862306a36Sopenharmony_ci	reg_write16(priv, REG_VWIN_START_2_MSB, vwin2_line_s);
162962306a36Sopenharmony_ci	reg_write16(priv, REG_VWIN_END_2_MSB, vwin2_line_e);
163062306a36Sopenharmony_ci	reg_write16(priv, REG_DE_START_MSB, de_pix_s);
163162306a36Sopenharmony_ci	reg_write16(priv, REG_DE_STOP_MSB, de_pix_e);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	if (priv->rev == TDA19988) {
163462306a36Sopenharmony_ci		/* let incoming pixels fill the active space (if any) */
163562306a36Sopenharmony_ci		reg_write(priv, REG_ENABLE_SPACE, 0x00);
163662306a36Sopenharmony_ci	}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	/*
163962306a36Sopenharmony_ci	 * Always generate sync polarity relative to input sync and
164062306a36Sopenharmony_ci	 * revert input stage toggled sync at output stage
164162306a36Sopenharmony_ci	 */
164262306a36Sopenharmony_ci	reg = TBG_CNTRL_1_DWIN_DIS | TBG_CNTRL_1_TGL_EN;
164362306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
164462306a36Sopenharmony_ci		reg |= TBG_CNTRL_1_H_TGL;
164562306a36Sopenharmony_ci	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
164662306a36Sopenharmony_ci		reg |= TBG_CNTRL_1_V_TGL;
164762306a36Sopenharmony_ci	reg_write(priv, REG_TBG_CNTRL_1, reg);
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	/* must be last register set: */
165062306a36Sopenharmony_ci	reg_write(priv, REG_TBG_CNTRL_0, 0);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	/* CEA-861B section 6 says that:
165362306a36Sopenharmony_ci	 * CEA version 1 (CEA-861) has no support for infoframes.
165462306a36Sopenharmony_ci	 * CEA version 2 (CEA-861A) supports version 1 AVI infoframes,
165562306a36Sopenharmony_ci	 * and optional basic audio.
165662306a36Sopenharmony_ci	 * CEA version 3 (CEA-861B) supports version 1 and 2 AVI infoframes,
165762306a36Sopenharmony_ci	 * and optional digital audio, with audio infoframes.
165862306a36Sopenharmony_ci	 *
165962306a36Sopenharmony_ci	 * Since we only support generation of version 2 AVI infoframes,
166062306a36Sopenharmony_ci	 * ignore CEA version 2 and below (iow, behave as if we're a
166162306a36Sopenharmony_ci	 * CEA-861 source.)
166262306a36Sopenharmony_ci	 */
166362306a36Sopenharmony_ci	priv->supports_infoframes = priv->connector.display_info.cea_rev >= 3;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (priv->supports_infoframes) {
166662306a36Sopenharmony_ci		/* We need to turn HDMI HDCP stuff on to get audio through */
166762306a36Sopenharmony_ci		reg &= ~TBG_CNTRL_1_DWIN_DIS;
166862306a36Sopenharmony_ci		reg_write(priv, REG_TBG_CNTRL_1, reg);
166962306a36Sopenharmony_ci		reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(1));
167062306a36Sopenharmony_ci		reg_set(priv, REG_TX33, TX33_HDMI);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		tda998x_write_avi(priv, adjusted_mode);
167362306a36Sopenharmony_ci		tda998x_write_vsi(priv, adjusted_mode);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci		if (priv->sink_has_audio)
167662306a36Sopenharmony_ci			tda998x_configure_audio(priv);
167762306a36Sopenharmony_ci	}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	mutex_unlock(&priv->audio_mutex);
168062306a36Sopenharmony_ci}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_cistatic const struct drm_bridge_funcs tda998x_bridge_funcs = {
168362306a36Sopenharmony_ci	.attach = tda998x_bridge_attach,
168462306a36Sopenharmony_ci	.detach = tda998x_bridge_detach,
168562306a36Sopenharmony_ci	.mode_valid = tda998x_bridge_mode_valid,
168662306a36Sopenharmony_ci	.disable = tda998x_bridge_disable,
168762306a36Sopenharmony_ci	.mode_set = tda998x_bridge_mode_set,
168862306a36Sopenharmony_ci	.enable = tda998x_bridge_enable,
168962306a36Sopenharmony_ci};
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci/* I2C driver functions */
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_cistatic int tda998x_get_audio_ports(struct tda998x_priv *priv,
169462306a36Sopenharmony_ci				   struct device_node *np)
169562306a36Sopenharmony_ci{
169662306a36Sopenharmony_ci	const u32 *port_data;
169762306a36Sopenharmony_ci	u32 size;
169862306a36Sopenharmony_ci	int i;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	port_data = of_get_property(np, "audio-ports", &size);
170162306a36Sopenharmony_ci	if (!port_data)
170262306a36Sopenharmony_ci		return 0;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	size /= sizeof(u32);
170562306a36Sopenharmony_ci	if (size > 2 * ARRAY_SIZE(priv->audio_port_enable) || size % 2 != 0) {
170662306a36Sopenharmony_ci		dev_err(&priv->hdmi->dev,
170762306a36Sopenharmony_ci			"Bad number of elements in audio-ports dt-property\n");
170862306a36Sopenharmony_ci		return -EINVAL;
170962306a36Sopenharmony_ci	}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	size /= 2;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
171462306a36Sopenharmony_ci		unsigned int route;
171562306a36Sopenharmony_ci		u8 afmt = be32_to_cpup(&port_data[2*i]);
171662306a36Sopenharmony_ci		u8 ena_ap = be32_to_cpup(&port_data[2*i+1]);
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci		switch (afmt) {
171962306a36Sopenharmony_ci		case AFMT_I2S:
172062306a36Sopenharmony_ci			route = AUDIO_ROUTE_I2S;
172162306a36Sopenharmony_ci			break;
172262306a36Sopenharmony_ci		case AFMT_SPDIF:
172362306a36Sopenharmony_ci			route = AUDIO_ROUTE_SPDIF;
172462306a36Sopenharmony_ci			break;
172562306a36Sopenharmony_ci		default:
172662306a36Sopenharmony_ci			dev_err(&priv->hdmi->dev,
172762306a36Sopenharmony_ci				"Bad audio format %u\n", afmt);
172862306a36Sopenharmony_ci			return -EINVAL;
172962306a36Sopenharmony_ci		}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci		if (!ena_ap) {
173262306a36Sopenharmony_ci			dev_err(&priv->hdmi->dev, "invalid zero port config\n");
173362306a36Sopenharmony_ci			continue;
173462306a36Sopenharmony_ci		}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci		if (priv->audio_port_enable[route]) {
173762306a36Sopenharmony_ci			dev_err(&priv->hdmi->dev,
173862306a36Sopenharmony_ci				"%s format already configured\n",
173962306a36Sopenharmony_ci				route == AUDIO_ROUTE_SPDIF ? "SPDIF" : "I2S");
174062306a36Sopenharmony_ci			return -EINVAL;
174162306a36Sopenharmony_ci		}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci		priv->audio_port_enable[route] = ena_ap;
174462306a36Sopenharmony_ci	}
174562306a36Sopenharmony_ci	return 0;
174662306a36Sopenharmony_ci}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_cistatic int tda998x_set_config(struct tda998x_priv *priv,
174962306a36Sopenharmony_ci			      const struct tda998x_encoder_params *p)
175062306a36Sopenharmony_ci{
175162306a36Sopenharmony_ci	priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p->swap_a) |
175262306a36Sopenharmony_ci			    (p->mirr_a ? VIP_CNTRL_0_MIRR_A : 0) |
175362306a36Sopenharmony_ci			    VIP_CNTRL_0_SWAP_B(p->swap_b) |
175462306a36Sopenharmony_ci			    (p->mirr_b ? VIP_CNTRL_0_MIRR_B : 0);
175562306a36Sopenharmony_ci	priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(p->swap_c) |
175662306a36Sopenharmony_ci			    (p->mirr_c ? VIP_CNTRL_1_MIRR_C : 0) |
175762306a36Sopenharmony_ci			    VIP_CNTRL_1_SWAP_D(p->swap_d) |
175862306a36Sopenharmony_ci			    (p->mirr_d ? VIP_CNTRL_1_MIRR_D : 0);
175962306a36Sopenharmony_ci	priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(p->swap_e) |
176062306a36Sopenharmony_ci			    (p->mirr_e ? VIP_CNTRL_2_MIRR_E : 0) |
176162306a36Sopenharmony_ci			    VIP_CNTRL_2_SWAP_F(p->swap_f) |
176262306a36Sopenharmony_ci			    (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (p->audio_params.format != AFMT_UNUSED) {
176562306a36Sopenharmony_ci		unsigned int ratio, route;
176662306a36Sopenharmony_ci		bool spdif = p->audio_params.format == AFMT_SPDIF;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci		route = AUDIO_ROUTE_I2S + spdif;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci		priv->audio.route = &tda998x_audio_route[route];
177162306a36Sopenharmony_ci		priv->audio.cea = p->audio_params.cea;
177262306a36Sopenharmony_ci		priv->audio.sample_rate = p->audio_params.sample_rate;
177362306a36Sopenharmony_ci		memcpy(priv->audio.status, p->audio_params.status,
177462306a36Sopenharmony_ci		       min(sizeof(priv->audio.status),
177562306a36Sopenharmony_ci			   sizeof(p->audio_params.status)));
177662306a36Sopenharmony_ci		priv->audio.ena_ap = p->audio_params.config;
177762306a36Sopenharmony_ci		priv->audio.i2s_format = I2S_FORMAT_PHILIPS;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci		ratio = spdif ? 64 : p->audio_params.sample_width * 2;
178062306a36Sopenharmony_ci		return tda998x_derive_cts_n(priv, &priv->audio, ratio);
178162306a36Sopenharmony_ci	}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	return 0;
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic void tda998x_destroy(struct device *dev)
178762306a36Sopenharmony_ci{
178862306a36Sopenharmony_ci	struct tda998x_priv *priv = dev_get_drvdata(dev);
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	drm_bridge_remove(&priv->bridge);
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	/* disable all IRQs and free the IRQ handler */
179362306a36Sopenharmony_ci	cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
179462306a36Sopenharmony_ci	reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	if (priv->audio_pdev)
179762306a36Sopenharmony_ci		platform_device_unregister(priv->audio_pdev);
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	if (priv->hdmi->irq)
180062306a36Sopenharmony_ci		free_irq(priv->hdmi->irq, priv);
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	del_timer_sync(&priv->edid_delay_timer);
180362306a36Sopenharmony_ci	cancel_work_sync(&priv->detect_work);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	i2c_unregister_device(priv->cec);
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	cec_notifier_conn_unregister(priv->cec_notify);
180862306a36Sopenharmony_ci}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_cistatic int tda998x_create(struct device *dev)
181162306a36Sopenharmony_ci{
181262306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
181362306a36Sopenharmony_ci	struct device_node *np = client->dev.of_node;
181462306a36Sopenharmony_ci	struct i2c_board_info cec_info;
181562306a36Sopenharmony_ci	struct tda998x_priv *priv;
181662306a36Sopenharmony_ci	u32 video;
181762306a36Sopenharmony_ci	int rev_lo, rev_hi, ret;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
182062306a36Sopenharmony_ci	if (!priv)
182162306a36Sopenharmony_ci		return -ENOMEM;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	dev_set_drvdata(dev, priv);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	mutex_init(&priv->mutex);	/* protect the page access */
182662306a36Sopenharmony_ci	mutex_init(&priv->audio_mutex); /* protect access from audio thread */
182762306a36Sopenharmony_ci	mutex_init(&priv->edid_mutex);
182862306a36Sopenharmony_ci	INIT_LIST_HEAD(&priv->bridge.list);
182962306a36Sopenharmony_ci	init_waitqueue_head(&priv->edid_delay_waitq);
183062306a36Sopenharmony_ci	timer_setup(&priv->edid_delay_timer, tda998x_edid_delay_done, 0);
183162306a36Sopenharmony_ci	INIT_WORK(&priv->detect_work, tda998x_detect_work);
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3);
183462306a36Sopenharmony_ci	priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1);
183562306a36Sopenharmony_ci	priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5);
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	/* CEC I2C address bound to TDA998x I2C addr by configuration pins */
183862306a36Sopenharmony_ci	priv->cec_addr = 0x34 + (client->addr & 0x03);
183962306a36Sopenharmony_ci	priv->current_page = 0xff;
184062306a36Sopenharmony_ci	priv->hdmi = client;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	/* wake up the device: */
184362306a36Sopenharmony_ci	cec_write(priv, REG_CEC_ENAMODS,
184462306a36Sopenharmony_ci			CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	tda998x_reset(priv);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	/* read version: */
184962306a36Sopenharmony_ci	rev_lo = reg_read(priv, REG_VERSION_LSB);
185062306a36Sopenharmony_ci	if (rev_lo < 0) {
185162306a36Sopenharmony_ci		dev_err(dev, "failed to read version: %d\n", rev_lo);
185262306a36Sopenharmony_ci		return rev_lo;
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	rev_hi = reg_read(priv, REG_VERSION_MSB);
185662306a36Sopenharmony_ci	if (rev_hi < 0) {
185762306a36Sopenharmony_ci		dev_err(dev, "failed to read version: %d\n", rev_hi);
185862306a36Sopenharmony_ci		return rev_hi;
185962306a36Sopenharmony_ci	}
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	priv->rev = rev_lo | rev_hi << 8;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	/* mask off feature bits: */
186462306a36Sopenharmony_ci	priv->rev &= ~0x30; /* not-hdcp and not-scalar bit */
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	switch (priv->rev) {
186762306a36Sopenharmony_ci	case TDA9989N2:
186862306a36Sopenharmony_ci		dev_info(dev, "found TDA9989 n2");
186962306a36Sopenharmony_ci		break;
187062306a36Sopenharmony_ci	case TDA19989:
187162306a36Sopenharmony_ci		dev_info(dev, "found TDA19989");
187262306a36Sopenharmony_ci		break;
187362306a36Sopenharmony_ci	case TDA19989N2:
187462306a36Sopenharmony_ci		dev_info(dev, "found TDA19989 n2");
187562306a36Sopenharmony_ci		break;
187662306a36Sopenharmony_ci	case TDA19988:
187762306a36Sopenharmony_ci		dev_info(dev, "found TDA19988");
187862306a36Sopenharmony_ci		break;
187962306a36Sopenharmony_ci	default:
188062306a36Sopenharmony_ci		dev_err(dev, "found unsupported device: %04x\n", priv->rev);
188162306a36Sopenharmony_ci		return -ENXIO;
188262306a36Sopenharmony_ci	}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	/* after reset, enable DDC: */
188562306a36Sopenharmony_ci	reg_write(priv, REG_DDC_DISABLE, 0x00);
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	/* set clock on DDC channel: */
188862306a36Sopenharmony_ci	reg_write(priv, REG_TX3, 39);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	/* if necessary, disable multi-master: */
189162306a36Sopenharmony_ci	if (priv->rev == TDA19989)
189262306a36Sopenharmony_ci		reg_set(priv, REG_I2C_MASTER, I2C_MASTER_DIS_MM);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	cec_write(priv, REG_CEC_FRO_IM_CLK_CTRL,
189562306a36Sopenharmony_ci			CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL);
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	/* ensure interrupts are disabled */
189862306a36Sopenharmony_ci	cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	/* clear pending interrupts */
190162306a36Sopenharmony_ci	cec_read(priv, REG_CEC_RXSHPDINT);
190262306a36Sopenharmony_ci	reg_read(priv, REG_INT_FLAGS_0);
190362306a36Sopenharmony_ci	reg_read(priv, REG_INT_FLAGS_1);
190462306a36Sopenharmony_ci	reg_read(priv, REG_INT_FLAGS_2);
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	/* initialize the optional IRQ */
190762306a36Sopenharmony_ci	if (client->irq) {
190862306a36Sopenharmony_ci		unsigned long irq_flags;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci		/* init read EDID waitqueue and HDP work */
191162306a36Sopenharmony_ci		init_waitqueue_head(&priv->wq_edid);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci		irq_flags =
191462306a36Sopenharmony_ci			irqd_get_trigger_type(irq_get_irq_data(client->irq));
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci		priv->cec_glue.irq_flags = irq_flags;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci		irq_flags |= IRQF_SHARED | IRQF_ONESHOT;
191962306a36Sopenharmony_ci		ret = request_threaded_irq(client->irq, NULL,
192062306a36Sopenharmony_ci					   tda998x_irq_thread, irq_flags,
192162306a36Sopenharmony_ci					   "tda998x", priv);
192262306a36Sopenharmony_ci		if (ret) {
192362306a36Sopenharmony_ci			dev_err(dev, "failed to request IRQ#%u: %d\n",
192462306a36Sopenharmony_ci				client->irq, ret);
192562306a36Sopenharmony_ci			goto err_irq;
192662306a36Sopenharmony_ci		}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci		/* enable HPD irq */
192962306a36Sopenharmony_ci		cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD);
193062306a36Sopenharmony_ci	}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	priv->cec_notify = cec_notifier_conn_register(dev, NULL, NULL);
193362306a36Sopenharmony_ci	if (!priv->cec_notify) {
193462306a36Sopenharmony_ci		ret = -ENOMEM;
193562306a36Sopenharmony_ci		goto fail;
193662306a36Sopenharmony_ci	}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	priv->cec_glue.parent = dev;
193962306a36Sopenharmony_ci	priv->cec_glue.data = priv;
194062306a36Sopenharmony_ci	priv->cec_glue.init = tda998x_cec_hook_init;
194162306a36Sopenharmony_ci	priv->cec_glue.exit = tda998x_cec_hook_exit;
194262306a36Sopenharmony_ci	priv->cec_glue.open = tda998x_cec_hook_open;
194362306a36Sopenharmony_ci	priv->cec_glue.release = tda998x_cec_hook_release;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	/*
194662306a36Sopenharmony_ci	 * Some TDA998x are actually two I2C devices merged onto one piece
194762306a36Sopenharmony_ci	 * of silicon: TDA9989 and TDA19989 combine the HDMI transmitter
194862306a36Sopenharmony_ci	 * with a slightly modified TDA9950 CEC device.  The CEC device
194962306a36Sopenharmony_ci	 * is at the TDA9950 address, with the address pins strapped across
195062306a36Sopenharmony_ci	 * to the TDA998x address pins.  Hence, it always has the same
195162306a36Sopenharmony_ci	 * offset.
195262306a36Sopenharmony_ci	 */
195362306a36Sopenharmony_ci	memset(&cec_info, 0, sizeof(cec_info));
195462306a36Sopenharmony_ci	strscpy(cec_info.type, "tda9950", sizeof(cec_info.type));
195562306a36Sopenharmony_ci	cec_info.addr = priv->cec_addr;
195662306a36Sopenharmony_ci	cec_info.platform_data = &priv->cec_glue;
195762306a36Sopenharmony_ci	cec_info.irq = client->irq;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	priv->cec = i2c_new_client_device(client->adapter, &cec_info);
196062306a36Sopenharmony_ci	if (IS_ERR(priv->cec)) {
196162306a36Sopenharmony_ci		ret = PTR_ERR(priv->cec);
196262306a36Sopenharmony_ci		goto fail;
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	/* enable EDID read irq: */
196662306a36Sopenharmony_ci	reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	if (np) {
196962306a36Sopenharmony_ci		/* get the device tree parameters */
197062306a36Sopenharmony_ci		ret = of_property_read_u32(np, "video-ports", &video);
197162306a36Sopenharmony_ci		if (ret == 0) {
197262306a36Sopenharmony_ci			priv->vip_cntrl_0 = video >> 16;
197362306a36Sopenharmony_ci			priv->vip_cntrl_1 = video >> 8;
197462306a36Sopenharmony_ci			priv->vip_cntrl_2 = video;
197562306a36Sopenharmony_ci		}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci		ret = tda998x_get_audio_ports(priv, np);
197862306a36Sopenharmony_ci		if (ret)
197962306a36Sopenharmony_ci			goto fail;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci		if (priv->audio_port_enable[AUDIO_ROUTE_I2S] ||
198262306a36Sopenharmony_ci		    priv->audio_port_enable[AUDIO_ROUTE_SPDIF])
198362306a36Sopenharmony_ci			tda998x_audio_codec_init(priv, &client->dev);
198462306a36Sopenharmony_ci	} else if (dev->platform_data) {
198562306a36Sopenharmony_ci		ret = tda998x_set_config(priv, dev->platform_data);
198662306a36Sopenharmony_ci		if (ret)
198762306a36Sopenharmony_ci			goto fail;
198862306a36Sopenharmony_ci	}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	priv->bridge.funcs = &tda998x_bridge_funcs;
199162306a36Sopenharmony_ci#ifdef CONFIG_OF
199262306a36Sopenharmony_ci	priv->bridge.of_node = dev->of_node;
199362306a36Sopenharmony_ci#endif
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	drm_bridge_add(&priv->bridge);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	return 0;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_cifail:
200062306a36Sopenharmony_ci	tda998x_destroy(dev);
200162306a36Sopenharmony_cierr_irq:
200262306a36Sopenharmony_ci	return ret;
200362306a36Sopenharmony_ci}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci/* DRM encoder functions */
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_cistatic int tda998x_encoder_init(struct device *dev, struct drm_device *drm)
200862306a36Sopenharmony_ci{
200962306a36Sopenharmony_ci	struct tda998x_priv *priv = dev_get_drvdata(dev);
201062306a36Sopenharmony_ci	u32 crtcs = 0;
201162306a36Sopenharmony_ci	int ret;
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	if (dev->of_node)
201462306a36Sopenharmony_ci		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	/* If no CRTCs were found, fall back to our old behaviour */
201762306a36Sopenharmony_ci	if (crtcs == 0) {
201862306a36Sopenharmony_ci		dev_warn(dev, "Falling back to first CRTC\n");
201962306a36Sopenharmony_ci		crtcs = 1 << 0;
202062306a36Sopenharmony_ci	}
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	priv->encoder.possible_crtcs = crtcs;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	ret = drm_simple_encoder_init(drm, &priv->encoder,
202562306a36Sopenharmony_ci				      DRM_MODE_ENCODER_TMDS);
202662306a36Sopenharmony_ci	if (ret)
202762306a36Sopenharmony_ci		goto err_encoder;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	ret = drm_bridge_attach(&priv->encoder, &priv->bridge, NULL, 0);
203062306a36Sopenharmony_ci	if (ret)
203162306a36Sopenharmony_ci		goto err_bridge;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	return 0;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_cierr_bridge:
203662306a36Sopenharmony_ci	drm_encoder_cleanup(&priv->encoder);
203762306a36Sopenharmony_cierr_encoder:
203862306a36Sopenharmony_ci	return ret;
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_cistatic int tda998x_bind(struct device *dev, struct device *master, void *data)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	struct drm_device *drm = data;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	return tda998x_encoder_init(dev, drm);
204662306a36Sopenharmony_ci}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_cistatic void tda998x_unbind(struct device *dev, struct device *master,
204962306a36Sopenharmony_ci			   void *data)
205062306a36Sopenharmony_ci{
205162306a36Sopenharmony_ci	struct tda998x_priv *priv = dev_get_drvdata(dev);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	drm_encoder_cleanup(&priv->encoder);
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic const struct component_ops tda998x_ops = {
205762306a36Sopenharmony_ci	.bind = tda998x_bind,
205862306a36Sopenharmony_ci	.unbind = tda998x_unbind,
205962306a36Sopenharmony_ci};
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cistatic int
206262306a36Sopenharmony_citda998x_probe(struct i2c_client *client)
206362306a36Sopenharmony_ci{
206462306a36Sopenharmony_ci	int ret;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
206762306a36Sopenharmony_ci		dev_warn(&client->dev, "adapter does not support I2C\n");
206862306a36Sopenharmony_ci		return -EIO;
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	ret = tda998x_create(&client->dev);
207262306a36Sopenharmony_ci	if (ret)
207362306a36Sopenharmony_ci		return ret;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	ret = component_add(&client->dev, &tda998x_ops);
207662306a36Sopenharmony_ci	if (ret)
207762306a36Sopenharmony_ci		tda998x_destroy(&client->dev);
207862306a36Sopenharmony_ci	return ret;
207962306a36Sopenharmony_ci}
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_cistatic void tda998x_remove(struct i2c_client *client)
208262306a36Sopenharmony_ci{
208362306a36Sopenharmony_ci	component_del(&client->dev, &tda998x_ops);
208462306a36Sopenharmony_ci	tda998x_destroy(&client->dev);
208562306a36Sopenharmony_ci}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci#ifdef CONFIG_OF
208862306a36Sopenharmony_cistatic const struct of_device_id tda998x_dt_ids[] = {
208962306a36Sopenharmony_ci	{ .compatible = "nxp,tda998x", },
209062306a36Sopenharmony_ci	{ }
209162306a36Sopenharmony_ci};
209262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tda998x_dt_ids);
209362306a36Sopenharmony_ci#endif
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_cistatic const struct i2c_device_id tda998x_ids[] = {
209662306a36Sopenharmony_ci	{ "tda998x", 0 },
209762306a36Sopenharmony_ci	{ }
209862306a36Sopenharmony_ci};
209962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tda998x_ids);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_cistatic struct i2c_driver tda998x_driver = {
210262306a36Sopenharmony_ci	.probe = tda998x_probe,
210362306a36Sopenharmony_ci	.remove = tda998x_remove,
210462306a36Sopenharmony_ci	.driver = {
210562306a36Sopenharmony_ci		.name = "tda998x",
210662306a36Sopenharmony_ci		.of_match_table = of_match_ptr(tda998x_dt_ids),
210762306a36Sopenharmony_ci	},
210862306a36Sopenharmony_ci	.id_table = tda998x_ids,
210962306a36Sopenharmony_ci};
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_cimodule_i2c_driver(tda998x_driver);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ciMODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
211462306a36Sopenharmony_ciMODULE_DESCRIPTION("NXP Semiconductors TDA998X HDMI Encoder");
211562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2116