xref: /linux/drivers/gpu/drm/bridge/tda998x_drv.c (revision be54f8c558027a218423134dd9b8c7c46d92204a)
1325ba852SDmitry Baryshkov // SPDX-License-Identifier: GPL-2.0-only
2325ba852SDmitry Baryshkov /*
3325ba852SDmitry Baryshkov  * Copyright (C) 2012 Texas Instruments
4325ba852SDmitry Baryshkov  * Author: Rob Clark <robdclark@gmail.com>
5325ba852SDmitry Baryshkov  */
6325ba852SDmitry Baryshkov 
7325ba852SDmitry Baryshkov #include <linux/component.h>
8325ba852SDmitry Baryshkov #include <linux/gpio/consumer.h>
9325ba852SDmitry Baryshkov #include <linux/hdmi.h>
10325ba852SDmitry Baryshkov #include <linux/i2c.h>
11325ba852SDmitry Baryshkov #include <linux/module.h>
12325ba852SDmitry Baryshkov #include <linux/platform_data/tda9950.h>
13325ba852SDmitry Baryshkov #include <linux/irq.h>
14325ba852SDmitry Baryshkov #include <sound/asoundef.h>
15325ba852SDmitry Baryshkov #include <sound/hdmi-codec.h>
16325ba852SDmitry Baryshkov 
17325ba852SDmitry Baryshkov #include <drm/drm_atomic_helper.h>
18325ba852SDmitry Baryshkov #include <drm/drm_bridge.h>
19325ba852SDmitry Baryshkov #include <drm/drm_edid.h>
20325ba852SDmitry Baryshkov #include <drm/drm_of.h>
21325ba852SDmitry Baryshkov #include <drm/drm_print.h>
22325ba852SDmitry Baryshkov #include <drm/drm_probe_helper.h>
23325ba852SDmitry Baryshkov #include <drm/drm_simple_kms_helper.h>
24325ba852SDmitry Baryshkov 
25325ba852SDmitry Baryshkov #include <media/cec-notifier.h>
26325ba852SDmitry Baryshkov 
27325ba852SDmitry Baryshkov #include <dt-bindings/display/tda998x.h>
28325ba852SDmitry Baryshkov 
29325ba852SDmitry Baryshkov #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
30325ba852SDmitry Baryshkov 
31325ba852SDmitry Baryshkov enum {
32325ba852SDmitry Baryshkov 	AUDIO_ROUTE_I2S,
33325ba852SDmitry Baryshkov 	AUDIO_ROUTE_SPDIF,
34325ba852SDmitry Baryshkov 	AUDIO_ROUTE_NUM
35325ba852SDmitry Baryshkov };
36325ba852SDmitry Baryshkov 
37325ba852SDmitry Baryshkov struct tda998x_audio_route {
38325ba852SDmitry Baryshkov 	u8 ena_aclk;
39325ba852SDmitry Baryshkov 	u8 mux_ap;
40325ba852SDmitry Baryshkov 	u8 aip_clksel;
41325ba852SDmitry Baryshkov };
42325ba852SDmitry Baryshkov 
43325ba852SDmitry Baryshkov struct tda998x_audio_settings {
44325ba852SDmitry Baryshkov 	const struct tda998x_audio_route *route;
45325ba852SDmitry Baryshkov 	struct hdmi_audio_infoframe cea;
46325ba852SDmitry Baryshkov 	unsigned int sample_rate;
47325ba852SDmitry Baryshkov 	u8 status[5];
48325ba852SDmitry Baryshkov 	u8 ena_ap;
49325ba852SDmitry Baryshkov 	u8 i2s_format;
50325ba852SDmitry Baryshkov 	u8 cts_n;
51325ba852SDmitry Baryshkov };
52325ba852SDmitry Baryshkov 
53325ba852SDmitry Baryshkov struct tda998x_priv {
54325ba852SDmitry Baryshkov 	struct i2c_client *cec;
55325ba852SDmitry Baryshkov 	struct i2c_client *hdmi;
56325ba852SDmitry Baryshkov 	struct mutex mutex;
57325ba852SDmitry Baryshkov 	u16 rev;
58325ba852SDmitry Baryshkov 	u8 cec_addr;
59325ba852SDmitry Baryshkov 	u8 current_page;
60325ba852SDmitry Baryshkov 	bool is_on;
61325ba852SDmitry Baryshkov 	bool supports_infoframes;
62325ba852SDmitry Baryshkov 	bool sink_has_audio;
63325ba852SDmitry Baryshkov 	enum hdmi_quantization_range rgb_quant_range;
64325ba852SDmitry Baryshkov 	u8 vip_cntrl_0;
65325ba852SDmitry Baryshkov 	u8 vip_cntrl_1;
66325ba852SDmitry Baryshkov 	u8 vip_cntrl_2;
67325ba852SDmitry Baryshkov 	unsigned long tmds_clock;
68325ba852SDmitry Baryshkov 	struct tda998x_audio_settings audio;
69325ba852SDmitry Baryshkov 
70325ba852SDmitry Baryshkov 	struct platform_device *audio_pdev;
71325ba852SDmitry Baryshkov 	struct mutex audio_mutex;
72325ba852SDmitry Baryshkov 
73325ba852SDmitry Baryshkov 	struct mutex edid_mutex;
74325ba852SDmitry Baryshkov 	wait_queue_head_t wq_edid;
75325ba852SDmitry Baryshkov 	volatile int wq_edid_wait;
76325ba852SDmitry Baryshkov 
77325ba852SDmitry Baryshkov 	struct work_struct detect_work;
78325ba852SDmitry Baryshkov 	struct timer_list edid_delay_timer;
79325ba852SDmitry Baryshkov 	wait_queue_head_t edid_delay_waitq;
80325ba852SDmitry Baryshkov 	bool edid_delay_active;
81325ba852SDmitry Baryshkov 
82325ba852SDmitry Baryshkov 	struct drm_encoder encoder;
83325ba852SDmitry Baryshkov 	struct drm_bridge bridge;
84325ba852SDmitry Baryshkov 	struct drm_connector connector;
85325ba852SDmitry Baryshkov 
86325ba852SDmitry Baryshkov 	u8 audio_port_enable[AUDIO_ROUTE_NUM];
87325ba852SDmitry Baryshkov 	struct tda9950_glue cec_glue;
88325ba852SDmitry Baryshkov 	struct gpio_desc *calib;
89325ba852SDmitry Baryshkov 	struct cec_notifier *cec_notify;
90325ba852SDmitry Baryshkov };
91325ba852SDmitry Baryshkov 
92325ba852SDmitry Baryshkov #define conn_to_tda998x_priv(x) \
93325ba852SDmitry Baryshkov 	container_of(x, struct tda998x_priv, connector)
94325ba852SDmitry Baryshkov #define enc_to_tda998x_priv(x) \
95325ba852SDmitry Baryshkov 	container_of(x, struct tda998x_priv, encoder)
96325ba852SDmitry Baryshkov #define bridge_to_tda998x_priv(x) \
97325ba852SDmitry Baryshkov 	container_of(x, struct tda998x_priv, bridge)
98325ba852SDmitry Baryshkov 
99325ba852SDmitry Baryshkov /* The TDA9988 series of devices use a paged register scheme.. to simplify
100325ba852SDmitry Baryshkov  * things we encode the page # in upper bits of the register #.  To read/
101325ba852SDmitry Baryshkov  * write a given register, we need to make sure CURPAGE register is set
102325ba852SDmitry Baryshkov  * appropriately.  Which implies reads/writes are not atomic.  Fun!
103325ba852SDmitry Baryshkov  */
104325ba852SDmitry Baryshkov 
105325ba852SDmitry Baryshkov #define REG(page, addr) (((page) << 8) | (addr))
106325ba852SDmitry Baryshkov #define REG2ADDR(reg)   ((reg) & 0xff)
107325ba852SDmitry Baryshkov #define REG2PAGE(reg)   (((reg) >> 8) & 0xff)
108325ba852SDmitry Baryshkov 
109325ba852SDmitry Baryshkov #define REG_CURPAGE               0xff                /* write */
110325ba852SDmitry Baryshkov 
111325ba852SDmitry Baryshkov 
112325ba852SDmitry Baryshkov /* Page 00h: General Control */
113325ba852SDmitry Baryshkov #define REG_VERSION_LSB           REG(0x00, 0x00)     /* read */
114325ba852SDmitry Baryshkov #define REG_MAIN_CNTRL0           REG(0x00, 0x01)     /* read/write */
115325ba852SDmitry Baryshkov # define MAIN_CNTRL0_SR           (1 << 0)
116325ba852SDmitry Baryshkov # define MAIN_CNTRL0_DECS         (1 << 1)
117325ba852SDmitry Baryshkov # define MAIN_CNTRL0_DEHS         (1 << 2)
118325ba852SDmitry Baryshkov # define MAIN_CNTRL0_CECS         (1 << 3)
119325ba852SDmitry Baryshkov # define MAIN_CNTRL0_CEHS         (1 << 4)
120325ba852SDmitry Baryshkov # define MAIN_CNTRL0_SCALER       (1 << 7)
121325ba852SDmitry Baryshkov #define REG_VERSION_MSB           REG(0x00, 0x02)     /* read */
122325ba852SDmitry Baryshkov #define REG_SOFTRESET             REG(0x00, 0x0a)     /* write */
123325ba852SDmitry Baryshkov # define SOFTRESET_AUDIO          (1 << 0)
124325ba852SDmitry Baryshkov # define SOFTRESET_I2C_MASTER     (1 << 1)
125325ba852SDmitry Baryshkov #define REG_DDC_DISABLE           REG(0x00, 0x0b)     /* read/write */
126325ba852SDmitry Baryshkov #define REG_CCLK_ON               REG(0x00, 0x0c)     /* read/write */
127325ba852SDmitry Baryshkov #define REG_I2C_MASTER            REG(0x00, 0x0d)     /* read/write */
128325ba852SDmitry Baryshkov # define I2C_MASTER_DIS_MM        (1 << 0)
129325ba852SDmitry Baryshkov # define I2C_MASTER_DIS_FILT      (1 << 1)
130325ba852SDmitry Baryshkov # define I2C_MASTER_APP_STRT_LAT  (1 << 2)
131325ba852SDmitry Baryshkov #define REG_FEAT_POWERDOWN        REG(0x00, 0x0e)     /* read/write */
132325ba852SDmitry Baryshkov # define FEAT_POWERDOWN_PREFILT   BIT(0)
133325ba852SDmitry Baryshkov # define FEAT_POWERDOWN_CSC       BIT(1)
134325ba852SDmitry Baryshkov # define FEAT_POWERDOWN_SPDIF     (1 << 3)
135325ba852SDmitry Baryshkov #define REG_INT_FLAGS_0           REG(0x00, 0x0f)     /* read/write */
136325ba852SDmitry Baryshkov #define REG_INT_FLAGS_1           REG(0x00, 0x10)     /* read/write */
137325ba852SDmitry Baryshkov #define REG_INT_FLAGS_2           REG(0x00, 0x11)     /* read/write */
138325ba852SDmitry Baryshkov # define INT_FLAGS_2_EDID_BLK_RD  (1 << 1)
139325ba852SDmitry Baryshkov #define REG_ENA_ACLK              REG(0x00, 0x16)     /* read/write */
140325ba852SDmitry Baryshkov #define REG_ENA_VP_0              REG(0x00, 0x18)     /* read/write */
141325ba852SDmitry Baryshkov #define REG_ENA_VP_1              REG(0x00, 0x19)     /* read/write */
142325ba852SDmitry Baryshkov #define REG_ENA_VP_2              REG(0x00, 0x1a)     /* read/write */
143325ba852SDmitry Baryshkov #define REG_ENA_AP                REG(0x00, 0x1e)     /* read/write */
144325ba852SDmitry Baryshkov #define REG_VIP_CNTRL_0           REG(0x00, 0x20)     /* write */
145325ba852SDmitry Baryshkov # define VIP_CNTRL_0_MIRR_A       (1 << 7)
146325ba852SDmitry Baryshkov # define VIP_CNTRL_0_SWAP_A(x)    (((x) & 7) << 4)
147325ba852SDmitry Baryshkov # define VIP_CNTRL_0_MIRR_B       (1 << 3)
148325ba852SDmitry Baryshkov # define VIP_CNTRL_0_SWAP_B(x)    (((x) & 7) << 0)
149325ba852SDmitry Baryshkov #define REG_VIP_CNTRL_1           REG(0x00, 0x21)     /* write */
150325ba852SDmitry Baryshkov # define VIP_CNTRL_1_MIRR_C       (1 << 7)
151325ba852SDmitry Baryshkov # define VIP_CNTRL_1_SWAP_C(x)    (((x) & 7) << 4)
152325ba852SDmitry Baryshkov # define VIP_CNTRL_1_MIRR_D       (1 << 3)
153325ba852SDmitry Baryshkov # define VIP_CNTRL_1_SWAP_D(x)    (((x) & 7) << 0)
154325ba852SDmitry Baryshkov #define REG_VIP_CNTRL_2           REG(0x00, 0x22)     /* write */
155325ba852SDmitry Baryshkov # define VIP_CNTRL_2_MIRR_E       (1 << 7)
156325ba852SDmitry Baryshkov # define VIP_CNTRL_2_SWAP_E(x)    (((x) & 7) << 4)
157325ba852SDmitry Baryshkov # define VIP_CNTRL_2_MIRR_F       (1 << 3)
158325ba852SDmitry Baryshkov # define VIP_CNTRL_2_SWAP_F(x)    (((x) & 7) << 0)
159325ba852SDmitry Baryshkov #define REG_VIP_CNTRL_3           REG(0x00, 0x23)     /* write */
160325ba852SDmitry Baryshkov # define VIP_CNTRL_3_X_TGL        (1 << 0)
161325ba852SDmitry Baryshkov # define VIP_CNTRL_3_H_TGL        (1 << 1)
162325ba852SDmitry Baryshkov # define VIP_CNTRL_3_V_TGL        (1 << 2)
163325ba852SDmitry Baryshkov # define VIP_CNTRL_3_EMB          (1 << 3)
164325ba852SDmitry Baryshkov # define VIP_CNTRL_3_SYNC_DE      (1 << 4)
165325ba852SDmitry Baryshkov # define VIP_CNTRL_3_SYNC_HS      (1 << 5)
166325ba852SDmitry Baryshkov # define VIP_CNTRL_3_DE_INT       (1 << 6)
167325ba852SDmitry Baryshkov # define VIP_CNTRL_3_EDGE         (1 << 7)
168325ba852SDmitry Baryshkov #define REG_VIP_CNTRL_4           REG(0x00, 0x24)     /* write */
169325ba852SDmitry Baryshkov # define VIP_CNTRL_4_BLC(x)       (((x) & 3) << 0)
170325ba852SDmitry Baryshkov # define VIP_CNTRL_4_BLANKIT(x)   (((x) & 3) << 2)
171325ba852SDmitry Baryshkov # define VIP_CNTRL_4_CCIR656      (1 << 4)
172325ba852SDmitry Baryshkov # define VIP_CNTRL_4_656_ALT      (1 << 5)
173325ba852SDmitry Baryshkov # define VIP_CNTRL_4_TST_656      (1 << 6)
174325ba852SDmitry Baryshkov # define VIP_CNTRL_4_TST_PAT      (1 << 7)
175325ba852SDmitry Baryshkov #define REG_VIP_CNTRL_5           REG(0x00, 0x25)     /* write */
176325ba852SDmitry Baryshkov # define VIP_CNTRL_5_CKCASE       (1 << 0)
177325ba852SDmitry Baryshkov # define VIP_CNTRL_5_SP_CNT(x)    (((x) & 3) << 1)
178325ba852SDmitry Baryshkov #define REG_MUX_AP                REG(0x00, 0x26)     /* read/write */
179325ba852SDmitry Baryshkov # define MUX_AP_SELECT_I2S	  0x64
180325ba852SDmitry Baryshkov # define MUX_AP_SELECT_SPDIF	  0x40
181325ba852SDmitry Baryshkov #define REG_MUX_VP_VIP_OUT        REG(0x00, 0x27)     /* read/write */
182325ba852SDmitry Baryshkov #define REG_MAT_CONTRL            REG(0x00, 0x80)     /* write */
183325ba852SDmitry Baryshkov # define MAT_CONTRL_MAT_SC(x)     (((x) & 3) << 0)
184325ba852SDmitry Baryshkov # define MAT_CONTRL_MAT_BP        (1 << 2)
185325ba852SDmitry Baryshkov #define REG_VIDFORMAT             REG(0x00, 0xa0)     /* write */
186325ba852SDmitry Baryshkov #define REG_REFPIX_MSB            REG(0x00, 0xa1)     /* write */
187325ba852SDmitry Baryshkov #define REG_REFPIX_LSB            REG(0x00, 0xa2)     /* write */
188325ba852SDmitry Baryshkov #define REG_REFLINE_MSB           REG(0x00, 0xa3)     /* write */
189325ba852SDmitry Baryshkov #define REG_REFLINE_LSB           REG(0x00, 0xa4)     /* write */
190325ba852SDmitry Baryshkov #define REG_NPIX_MSB              REG(0x00, 0xa5)     /* write */
191325ba852SDmitry Baryshkov #define REG_NPIX_LSB              REG(0x00, 0xa6)     /* write */
192325ba852SDmitry Baryshkov #define REG_NLINE_MSB             REG(0x00, 0xa7)     /* write */
193325ba852SDmitry Baryshkov #define REG_NLINE_LSB             REG(0x00, 0xa8)     /* write */
194325ba852SDmitry Baryshkov #define REG_VS_LINE_STRT_1_MSB    REG(0x00, 0xa9)     /* write */
195325ba852SDmitry Baryshkov #define REG_VS_LINE_STRT_1_LSB    REG(0x00, 0xaa)     /* write */
196325ba852SDmitry Baryshkov #define REG_VS_PIX_STRT_1_MSB     REG(0x00, 0xab)     /* write */
197325ba852SDmitry Baryshkov #define REG_VS_PIX_STRT_1_LSB     REG(0x00, 0xac)     /* write */
198325ba852SDmitry Baryshkov #define REG_VS_LINE_END_1_MSB     REG(0x00, 0xad)     /* write */
199325ba852SDmitry Baryshkov #define REG_VS_LINE_END_1_LSB     REG(0x00, 0xae)     /* write */
200325ba852SDmitry Baryshkov #define REG_VS_PIX_END_1_MSB      REG(0x00, 0xaf)     /* write */
201325ba852SDmitry Baryshkov #define REG_VS_PIX_END_1_LSB      REG(0x00, 0xb0)     /* write */
202325ba852SDmitry Baryshkov #define REG_VS_LINE_STRT_2_MSB    REG(0x00, 0xb1)     /* write */
203325ba852SDmitry Baryshkov #define REG_VS_LINE_STRT_2_LSB    REG(0x00, 0xb2)     /* write */
204325ba852SDmitry Baryshkov #define REG_VS_PIX_STRT_2_MSB     REG(0x00, 0xb3)     /* write */
205325ba852SDmitry Baryshkov #define REG_VS_PIX_STRT_2_LSB     REG(0x00, 0xb4)     /* write */
206325ba852SDmitry Baryshkov #define REG_VS_LINE_END_2_MSB     REG(0x00, 0xb5)     /* write */
207325ba852SDmitry Baryshkov #define REG_VS_LINE_END_2_LSB     REG(0x00, 0xb6)     /* write */
208325ba852SDmitry Baryshkov #define REG_VS_PIX_END_2_MSB      REG(0x00, 0xb7)     /* write */
209325ba852SDmitry Baryshkov #define REG_VS_PIX_END_2_LSB      REG(0x00, 0xb8)     /* write */
210325ba852SDmitry Baryshkov #define REG_HS_PIX_START_MSB      REG(0x00, 0xb9)     /* write */
211325ba852SDmitry Baryshkov #define REG_HS_PIX_START_LSB      REG(0x00, 0xba)     /* write */
212325ba852SDmitry Baryshkov #define REG_HS_PIX_STOP_MSB       REG(0x00, 0xbb)     /* write */
213325ba852SDmitry Baryshkov #define REG_HS_PIX_STOP_LSB       REG(0x00, 0xbc)     /* write */
214325ba852SDmitry Baryshkov #define REG_VWIN_START_1_MSB      REG(0x00, 0xbd)     /* write */
215325ba852SDmitry Baryshkov #define REG_VWIN_START_1_LSB      REG(0x00, 0xbe)     /* write */
216325ba852SDmitry Baryshkov #define REG_VWIN_END_1_MSB        REG(0x00, 0xbf)     /* write */
217325ba852SDmitry Baryshkov #define REG_VWIN_END_1_LSB        REG(0x00, 0xc0)     /* write */
218325ba852SDmitry Baryshkov #define REG_VWIN_START_2_MSB      REG(0x00, 0xc1)     /* write */
219325ba852SDmitry Baryshkov #define REG_VWIN_START_2_LSB      REG(0x00, 0xc2)     /* write */
220325ba852SDmitry Baryshkov #define REG_VWIN_END_2_MSB        REG(0x00, 0xc3)     /* write */
221325ba852SDmitry Baryshkov #define REG_VWIN_END_2_LSB        REG(0x00, 0xc4)     /* write */
222325ba852SDmitry Baryshkov #define REG_DE_START_MSB          REG(0x00, 0xc5)     /* write */
223325ba852SDmitry Baryshkov #define REG_DE_START_LSB          REG(0x00, 0xc6)     /* write */
224325ba852SDmitry Baryshkov #define REG_DE_STOP_MSB           REG(0x00, 0xc7)     /* write */
225325ba852SDmitry Baryshkov #define REG_DE_STOP_LSB           REG(0x00, 0xc8)     /* write */
226325ba852SDmitry Baryshkov #define REG_TBG_CNTRL_0           REG(0x00, 0xca)     /* write */
227325ba852SDmitry Baryshkov # define TBG_CNTRL_0_TOP_TGL      (1 << 0)
228325ba852SDmitry Baryshkov # define TBG_CNTRL_0_TOP_SEL      (1 << 1)
229325ba852SDmitry Baryshkov # define TBG_CNTRL_0_DE_EXT       (1 << 2)
230325ba852SDmitry Baryshkov # define TBG_CNTRL_0_TOP_EXT      (1 << 3)
231325ba852SDmitry Baryshkov # define TBG_CNTRL_0_FRAME_DIS    (1 << 5)
232325ba852SDmitry Baryshkov # define TBG_CNTRL_0_SYNC_MTHD    (1 << 6)
233325ba852SDmitry Baryshkov # define TBG_CNTRL_0_SYNC_ONCE    (1 << 7)
234325ba852SDmitry Baryshkov #define REG_TBG_CNTRL_1           REG(0x00, 0xcb)     /* write */
235325ba852SDmitry Baryshkov # define TBG_CNTRL_1_H_TGL        (1 << 0)
236325ba852SDmitry Baryshkov # define TBG_CNTRL_1_V_TGL        (1 << 1)
237325ba852SDmitry Baryshkov # define TBG_CNTRL_1_TGL_EN       (1 << 2)
238325ba852SDmitry Baryshkov # define TBG_CNTRL_1_X_EXT        (1 << 3)
239325ba852SDmitry Baryshkov # define TBG_CNTRL_1_H_EXT        (1 << 4)
240325ba852SDmitry Baryshkov # define TBG_CNTRL_1_V_EXT        (1 << 5)
241325ba852SDmitry Baryshkov # define TBG_CNTRL_1_DWIN_DIS     (1 << 6)
242325ba852SDmitry Baryshkov #define REG_ENABLE_SPACE          REG(0x00, 0xd6)     /* write */
243325ba852SDmitry Baryshkov #define REG_HVF_CNTRL_0           REG(0x00, 0xe4)     /* write */
244325ba852SDmitry Baryshkov # define HVF_CNTRL_0_SM           (1 << 7)
245325ba852SDmitry Baryshkov # define HVF_CNTRL_0_RWB          (1 << 6)
246325ba852SDmitry Baryshkov # define HVF_CNTRL_0_PREFIL(x)    (((x) & 3) << 2)
247325ba852SDmitry Baryshkov # define HVF_CNTRL_0_INTPOL(x)    (((x) & 3) << 0)
248325ba852SDmitry Baryshkov #define REG_HVF_CNTRL_1           REG(0x00, 0xe5)     /* write */
249325ba852SDmitry Baryshkov # define HVF_CNTRL_1_FOR          (1 << 0)
250325ba852SDmitry Baryshkov # define HVF_CNTRL_1_YUVBLK       (1 << 1)
251325ba852SDmitry Baryshkov # define HVF_CNTRL_1_VQR(x)       (((x) & 3) << 2)
252325ba852SDmitry Baryshkov # define HVF_CNTRL_1_PAD(x)       (((x) & 3) << 4)
253325ba852SDmitry Baryshkov # define HVF_CNTRL_1_SEMI_PLANAR  (1 << 6)
254325ba852SDmitry Baryshkov #define REG_RPT_CNTRL             REG(0x00, 0xf0)     /* write */
255325ba852SDmitry Baryshkov # define RPT_CNTRL_REPEAT(x)      ((x) & 15)
256325ba852SDmitry Baryshkov #define REG_I2S_FORMAT            REG(0x00, 0xfc)     /* read/write */
257325ba852SDmitry Baryshkov # define I2S_FORMAT_PHILIPS       (0 << 0)
258325ba852SDmitry Baryshkov # define I2S_FORMAT_LEFT_J        (2 << 0)
259325ba852SDmitry Baryshkov # define I2S_FORMAT_RIGHT_J       (3 << 0)
260325ba852SDmitry Baryshkov #define REG_AIP_CLKSEL            REG(0x00, 0xfd)     /* write */
261325ba852SDmitry Baryshkov # define AIP_CLKSEL_AIP_SPDIF	  (0 << 3)
262325ba852SDmitry Baryshkov # define AIP_CLKSEL_AIP_I2S	  (1 << 3)
263325ba852SDmitry Baryshkov # define AIP_CLKSEL_FS_ACLK	  (0 << 0)
264325ba852SDmitry Baryshkov # define AIP_CLKSEL_FS_MCLK	  (1 << 0)
265325ba852SDmitry Baryshkov # define AIP_CLKSEL_FS_FS64SPDIF  (2 << 0)
266325ba852SDmitry Baryshkov 
267325ba852SDmitry Baryshkov /* Page 02h: PLL settings */
268325ba852SDmitry Baryshkov #define REG_PLL_SERIAL_1          REG(0x02, 0x00)     /* read/write */
269325ba852SDmitry Baryshkov # define PLL_SERIAL_1_SRL_FDN     (1 << 0)
270325ba852SDmitry Baryshkov # define PLL_SERIAL_1_SRL_IZ(x)   (((x) & 3) << 1)
271325ba852SDmitry Baryshkov # define PLL_SERIAL_1_SRL_MAN_IZ  (1 << 6)
272325ba852SDmitry Baryshkov #define REG_PLL_SERIAL_2          REG(0x02, 0x01)     /* read/write */
273325ba852SDmitry Baryshkov # define PLL_SERIAL_2_SRL_NOSC(x) ((x) << 0)
274325ba852SDmitry Baryshkov # define PLL_SERIAL_2_SRL_PR(x)   (((x) & 0xf) << 4)
275325ba852SDmitry Baryshkov #define REG_PLL_SERIAL_3          REG(0x02, 0x02)     /* read/write */
276325ba852SDmitry Baryshkov # define PLL_SERIAL_3_SRL_CCIR    (1 << 0)
277325ba852SDmitry Baryshkov # define PLL_SERIAL_3_SRL_DE      (1 << 2)
278325ba852SDmitry Baryshkov # define PLL_SERIAL_3_SRL_PXIN_SEL (1 << 4)
279325ba852SDmitry Baryshkov #define REG_SERIALIZER            REG(0x02, 0x03)     /* read/write */
280325ba852SDmitry Baryshkov #define REG_BUFFER_OUT            REG(0x02, 0x04)     /* read/write */
281325ba852SDmitry Baryshkov #define REG_PLL_SCG1              REG(0x02, 0x05)     /* read/write */
282325ba852SDmitry Baryshkov #define REG_PLL_SCG2              REG(0x02, 0x06)     /* read/write */
283325ba852SDmitry Baryshkov #define REG_PLL_SCGN1             REG(0x02, 0x07)     /* read/write */
284325ba852SDmitry Baryshkov #define REG_PLL_SCGN2             REG(0x02, 0x08)     /* read/write */
285325ba852SDmitry Baryshkov #define REG_PLL_SCGR1             REG(0x02, 0x09)     /* read/write */
286325ba852SDmitry Baryshkov #define REG_PLL_SCGR2             REG(0x02, 0x0a)     /* read/write */
287325ba852SDmitry Baryshkov #define REG_AUDIO_DIV             REG(0x02, 0x0e)     /* read/write */
288325ba852SDmitry Baryshkov # define AUDIO_DIV_SERCLK_1       0
289325ba852SDmitry Baryshkov # define AUDIO_DIV_SERCLK_2       1
290325ba852SDmitry Baryshkov # define AUDIO_DIV_SERCLK_4       2
291325ba852SDmitry Baryshkov # define AUDIO_DIV_SERCLK_8       3
292325ba852SDmitry Baryshkov # define AUDIO_DIV_SERCLK_16      4
293325ba852SDmitry Baryshkov # define AUDIO_DIV_SERCLK_32      5
294325ba852SDmitry Baryshkov #define REG_SEL_CLK               REG(0x02, 0x11)     /* read/write */
295325ba852SDmitry Baryshkov # define SEL_CLK_SEL_CLK1         (1 << 0)
296325ba852SDmitry Baryshkov # define SEL_CLK_SEL_VRF_CLK(x)   (((x) & 3) << 1)
297325ba852SDmitry Baryshkov # define SEL_CLK_ENA_SC_CLK       (1 << 3)
298325ba852SDmitry Baryshkov #define REG_ANA_GENERAL           REG(0x02, 0x12)     /* read/write */
299325ba852SDmitry Baryshkov 
300325ba852SDmitry Baryshkov 
301325ba852SDmitry Baryshkov /* Page 09h: EDID Control */
302325ba852SDmitry Baryshkov #define REG_EDID_DATA_0           REG(0x09, 0x00)     /* read */
303325ba852SDmitry Baryshkov /* next 127 successive registers are the EDID block */
304325ba852SDmitry Baryshkov #define REG_EDID_CTRL             REG(0x09, 0xfa)     /* read/write */
305325ba852SDmitry Baryshkov #define REG_DDC_ADDR              REG(0x09, 0xfb)     /* read/write */
306325ba852SDmitry Baryshkov #define REG_DDC_OFFS              REG(0x09, 0xfc)     /* read/write */
307325ba852SDmitry Baryshkov #define REG_DDC_SEGM_ADDR         REG(0x09, 0xfd)     /* read/write */
308325ba852SDmitry Baryshkov #define REG_DDC_SEGM              REG(0x09, 0xfe)     /* read/write */
309325ba852SDmitry Baryshkov 
310325ba852SDmitry Baryshkov 
311325ba852SDmitry Baryshkov /* Page 10h: information frames and packets */
312325ba852SDmitry Baryshkov #define REG_IF1_HB0               REG(0x10, 0x20)     /* read/write */
313325ba852SDmitry Baryshkov #define REG_IF2_HB0               REG(0x10, 0x40)     /* read/write */
314325ba852SDmitry Baryshkov #define REG_IF3_HB0               REG(0x10, 0x60)     /* read/write */
315325ba852SDmitry Baryshkov #define REG_IF4_HB0               REG(0x10, 0x80)     /* read/write */
316325ba852SDmitry Baryshkov #define REG_IF5_HB0               REG(0x10, 0xa0)     /* read/write */
317325ba852SDmitry Baryshkov 
318325ba852SDmitry Baryshkov 
319325ba852SDmitry Baryshkov /* Page 11h: audio settings and content info packets */
320325ba852SDmitry Baryshkov #define REG_AIP_CNTRL_0           REG(0x11, 0x00)     /* read/write */
321325ba852SDmitry Baryshkov # define AIP_CNTRL_0_RST_FIFO     (1 << 0)
322325ba852SDmitry Baryshkov # define AIP_CNTRL_0_SWAP         (1 << 1)
323325ba852SDmitry Baryshkov # define AIP_CNTRL_0_LAYOUT       (1 << 2)
324325ba852SDmitry Baryshkov # define AIP_CNTRL_0_ACR_MAN      (1 << 5)
325325ba852SDmitry Baryshkov # define AIP_CNTRL_0_RST_CTS      (1 << 6)
326325ba852SDmitry Baryshkov #define REG_CA_I2S                REG(0x11, 0x01)     /* read/write */
327325ba852SDmitry Baryshkov # define CA_I2S_CA_I2S(x)         (((x) & 31) << 0)
328325ba852SDmitry Baryshkov # define CA_I2S_HBR_CHSTAT        (1 << 6)
329325ba852SDmitry Baryshkov #define REG_LATENCY_RD            REG(0x11, 0x04)     /* read/write */
330325ba852SDmitry Baryshkov #define REG_ACR_CTS_0             REG(0x11, 0x05)     /* read/write */
331325ba852SDmitry Baryshkov #define REG_ACR_CTS_1             REG(0x11, 0x06)     /* read/write */
332325ba852SDmitry Baryshkov #define REG_ACR_CTS_2             REG(0x11, 0x07)     /* read/write */
333325ba852SDmitry Baryshkov #define REG_ACR_N_0               REG(0x11, 0x08)     /* read/write */
334325ba852SDmitry Baryshkov #define REG_ACR_N_1               REG(0x11, 0x09)     /* read/write */
335325ba852SDmitry Baryshkov #define REG_ACR_N_2               REG(0x11, 0x0a)     /* read/write */
336325ba852SDmitry Baryshkov #define REG_CTS_N                 REG(0x11, 0x0c)     /* read/write */
337325ba852SDmitry Baryshkov # define CTS_N_K(x)               (((x) & 7) << 0)
338325ba852SDmitry Baryshkov # define CTS_N_M(x)               (((x) & 3) << 4)
339325ba852SDmitry Baryshkov #define REG_ENC_CNTRL             REG(0x11, 0x0d)     /* read/write */
340325ba852SDmitry Baryshkov # define ENC_CNTRL_RST_ENC        (1 << 0)
341325ba852SDmitry Baryshkov # define ENC_CNTRL_RST_SEL        (1 << 1)
342325ba852SDmitry Baryshkov # define ENC_CNTRL_CTL_CODE(x)    (((x) & 3) << 2)
343325ba852SDmitry Baryshkov #define REG_DIP_FLAGS             REG(0x11, 0x0e)     /* read/write */
344325ba852SDmitry Baryshkov # define DIP_FLAGS_ACR            (1 << 0)
345325ba852SDmitry Baryshkov # define DIP_FLAGS_GC             (1 << 1)
346325ba852SDmitry Baryshkov #define REG_DIP_IF_FLAGS          REG(0x11, 0x0f)     /* read/write */
347325ba852SDmitry Baryshkov # define DIP_IF_FLAGS_IF1         (1 << 1)
348325ba852SDmitry Baryshkov # define DIP_IF_FLAGS_IF2         (1 << 2)
349325ba852SDmitry Baryshkov # define DIP_IF_FLAGS_IF3         (1 << 3)
350325ba852SDmitry Baryshkov # define DIP_IF_FLAGS_IF4         (1 << 4)
351325ba852SDmitry Baryshkov # define DIP_IF_FLAGS_IF5         (1 << 5)
352325ba852SDmitry Baryshkov #define REG_CH_STAT_B(x)          REG(0x11, 0x14 + (x)) /* read/write */
353325ba852SDmitry Baryshkov 
354325ba852SDmitry Baryshkov 
355325ba852SDmitry Baryshkov /* Page 12h: HDCP and OTP */
356325ba852SDmitry Baryshkov #define REG_TX3                   REG(0x12, 0x9a)     /* read/write */
357325ba852SDmitry Baryshkov #define REG_TX4                   REG(0x12, 0x9b)     /* read/write */
358325ba852SDmitry Baryshkov # define TX4_PD_RAM               (1 << 1)
359325ba852SDmitry Baryshkov #define REG_TX33                  REG(0x12, 0xb8)     /* read/write */
360325ba852SDmitry Baryshkov # define TX33_HDMI                (1 << 1)
361325ba852SDmitry Baryshkov 
362325ba852SDmitry Baryshkov 
363325ba852SDmitry Baryshkov /* Page 13h: Gamut related metadata packets */
364325ba852SDmitry Baryshkov 
365325ba852SDmitry Baryshkov 
366325ba852SDmitry Baryshkov 
367325ba852SDmitry Baryshkov /* CEC registers: (not paged)
368325ba852SDmitry Baryshkov  */
369325ba852SDmitry Baryshkov #define REG_CEC_INTSTATUS	  0xee		      /* read */
370325ba852SDmitry Baryshkov # define CEC_INTSTATUS_CEC	  (1 << 0)
371325ba852SDmitry Baryshkov # define CEC_INTSTATUS_HDMI	  (1 << 1)
372325ba852SDmitry Baryshkov #define REG_CEC_CAL_XOSC_CTRL1    0xf2
373325ba852SDmitry Baryshkov # define CEC_CAL_XOSC_CTRL1_ENA_CAL	BIT(0)
374325ba852SDmitry Baryshkov #define REG_CEC_DES_FREQ2         0xf5
375325ba852SDmitry Baryshkov # define CEC_DES_FREQ2_DIS_AUTOCAL BIT(7)
376325ba852SDmitry Baryshkov #define REG_CEC_CLK               0xf6
377325ba852SDmitry Baryshkov # define CEC_CLK_FRO              0x11
378325ba852SDmitry Baryshkov #define REG_CEC_FRO_IM_CLK_CTRL   0xfb                /* read/write */
379325ba852SDmitry Baryshkov # define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7)
380325ba852SDmitry Baryshkov # define CEC_FRO_IM_CLK_CTRL_ENA_OTP   (1 << 6)
381325ba852SDmitry Baryshkov # define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1)
382325ba852SDmitry Baryshkov # define CEC_FRO_IM_CLK_CTRL_FRO_DIV   (1 << 0)
383325ba852SDmitry Baryshkov #define REG_CEC_RXSHPDINTENA	  0xfc		      /* read/write */
384325ba852SDmitry Baryshkov #define REG_CEC_RXSHPDINT	  0xfd		      /* read */
385325ba852SDmitry Baryshkov # define CEC_RXSHPDINT_RXSENS     BIT(0)
386325ba852SDmitry Baryshkov # define CEC_RXSHPDINT_HPD        BIT(1)
387325ba852SDmitry Baryshkov #define REG_CEC_RXSHPDLEV         0xfe                /* read */
388325ba852SDmitry Baryshkov # define CEC_RXSHPDLEV_RXSENS     (1 << 0)
389325ba852SDmitry Baryshkov # define CEC_RXSHPDLEV_HPD        (1 << 1)
390325ba852SDmitry Baryshkov 
391325ba852SDmitry Baryshkov #define REG_CEC_ENAMODS           0xff                /* read/write */
392325ba852SDmitry Baryshkov # define CEC_ENAMODS_EN_CEC_CLK   (1 << 7)
393325ba852SDmitry Baryshkov # define CEC_ENAMODS_DIS_FRO      (1 << 6)
394325ba852SDmitry Baryshkov # define CEC_ENAMODS_DIS_CCLK     (1 << 5)
395325ba852SDmitry Baryshkov # define CEC_ENAMODS_EN_RXSENS    (1 << 2)
396325ba852SDmitry Baryshkov # define CEC_ENAMODS_EN_HDMI      (1 << 1)
397325ba852SDmitry Baryshkov # define CEC_ENAMODS_EN_CEC       (1 << 0)
398325ba852SDmitry Baryshkov 
399325ba852SDmitry Baryshkov 
400325ba852SDmitry Baryshkov /* Device versions: */
401325ba852SDmitry Baryshkov #define TDA9989N2                 0x0101
402325ba852SDmitry Baryshkov #define TDA19989                  0x0201
403325ba852SDmitry Baryshkov #define TDA19989N2                0x0202
404325ba852SDmitry Baryshkov #define TDA19988                  0x0301
405325ba852SDmitry Baryshkov 
406325ba852SDmitry Baryshkov static void
cec_write(struct tda998x_priv * priv,u16 addr,u8 val)407325ba852SDmitry Baryshkov cec_write(struct tda998x_priv *priv, u16 addr, u8 val)
408325ba852SDmitry Baryshkov {
409325ba852SDmitry Baryshkov 	u8 buf[] = {addr, val};
410325ba852SDmitry Baryshkov 	struct i2c_msg msg = {
411325ba852SDmitry Baryshkov 		.addr = priv->cec_addr,
412325ba852SDmitry Baryshkov 		.len = 2,
413325ba852SDmitry Baryshkov 		.buf = buf,
414325ba852SDmitry Baryshkov 	};
415325ba852SDmitry Baryshkov 	int ret;
416325ba852SDmitry Baryshkov 
417325ba852SDmitry Baryshkov 	ret = i2c_transfer(priv->hdmi->adapter, &msg, 1);
418325ba852SDmitry Baryshkov 	if (ret < 0)
419325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev, "Error %d writing to cec:0x%x\n",
420325ba852SDmitry Baryshkov 			ret, addr);
421325ba852SDmitry Baryshkov }
422325ba852SDmitry Baryshkov 
423325ba852SDmitry Baryshkov static u8
cec_read(struct tda998x_priv * priv,u8 addr)424325ba852SDmitry Baryshkov cec_read(struct tda998x_priv *priv, u8 addr)
425325ba852SDmitry Baryshkov {
426325ba852SDmitry Baryshkov 	u8 val;
427325ba852SDmitry Baryshkov 	struct i2c_msg msg[2] = {
428325ba852SDmitry Baryshkov 		{
429325ba852SDmitry Baryshkov 			.addr = priv->cec_addr,
430325ba852SDmitry Baryshkov 			.len = 1,
431325ba852SDmitry Baryshkov 			.buf = &addr,
432325ba852SDmitry Baryshkov 		}, {
433325ba852SDmitry Baryshkov 			.addr = priv->cec_addr,
434325ba852SDmitry Baryshkov 			.flags = I2C_M_RD,
435325ba852SDmitry Baryshkov 			.len = 1,
436325ba852SDmitry Baryshkov 			.buf = &val,
437325ba852SDmitry Baryshkov 		},
438325ba852SDmitry Baryshkov 	};
439325ba852SDmitry Baryshkov 	int ret;
440325ba852SDmitry Baryshkov 
441325ba852SDmitry Baryshkov 	ret = i2c_transfer(priv->hdmi->adapter, msg, ARRAY_SIZE(msg));
442325ba852SDmitry Baryshkov 	if (ret < 0) {
443325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev, "Error %d reading from cec:0x%x\n",
444325ba852SDmitry Baryshkov 			ret, addr);
445325ba852SDmitry Baryshkov 		val = 0;
446325ba852SDmitry Baryshkov 	}
447325ba852SDmitry Baryshkov 
448325ba852SDmitry Baryshkov 	return val;
449325ba852SDmitry Baryshkov }
450325ba852SDmitry Baryshkov 
cec_enamods(struct tda998x_priv * priv,u8 mods,bool enable)451325ba852SDmitry Baryshkov static void cec_enamods(struct tda998x_priv *priv, u8 mods, bool enable)
452325ba852SDmitry Baryshkov {
453325ba852SDmitry Baryshkov 	int val = cec_read(priv, REG_CEC_ENAMODS);
454325ba852SDmitry Baryshkov 
455325ba852SDmitry Baryshkov 	if (val < 0)
456325ba852SDmitry Baryshkov 		return;
457325ba852SDmitry Baryshkov 
458325ba852SDmitry Baryshkov 	if (enable)
459325ba852SDmitry Baryshkov 		val |= mods;
460325ba852SDmitry Baryshkov 	else
461325ba852SDmitry Baryshkov 		val &= ~mods;
462325ba852SDmitry Baryshkov 
463325ba852SDmitry Baryshkov 	cec_write(priv, REG_CEC_ENAMODS, val);
464325ba852SDmitry Baryshkov }
465325ba852SDmitry Baryshkov 
tda998x_cec_set_calibration(struct tda998x_priv * priv,bool enable)466325ba852SDmitry Baryshkov static void tda998x_cec_set_calibration(struct tda998x_priv *priv, bool enable)
467325ba852SDmitry Baryshkov {
468325ba852SDmitry Baryshkov 	if (enable) {
469325ba852SDmitry Baryshkov 		u8 val;
470325ba852SDmitry Baryshkov 
471325ba852SDmitry Baryshkov 		cec_write(priv, 0xf3, 0xc0);
472325ba852SDmitry Baryshkov 		cec_write(priv, 0xf4, 0xd4);
473325ba852SDmitry Baryshkov 
474325ba852SDmitry Baryshkov 		/* Enable automatic calibration mode */
475325ba852SDmitry Baryshkov 		val = cec_read(priv, REG_CEC_DES_FREQ2);
476325ba852SDmitry Baryshkov 		val &= ~CEC_DES_FREQ2_DIS_AUTOCAL;
477325ba852SDmitry Baryshkov 		cec_write(priv, REG_CEC_DES_FREQ2, val);
478325ba852SDmitry Baryshkov 
479325ba852SDmitry Baryshkov 		/* Enable free running oscillator */
480325ba852SDmitry Baryshkov 		cec_write(priv, REG_CEC_CLK, CEC_CLK_FRO);
481325ba852SDmitry Baryshkov 		cec_enamods(priv, CEC_ENAMODS_DIS_FRO, false);
482325ba852SDmitry Baryshkov 
483325ba852SDmitry Baryshkov 		cec_write(priv, REG_CEC_CAL_XOSC_CTRL1,
484325ba852SDmitry Baryshkov 			  CEC_CAL_XOSC_CTRL1_ENA_CAL);
485325ba852SDmitry Baryshkov 	} else {
486325ba852SDmitry Baryshkov 		cec_write(priv, REG_CEC_CAL_XOSC_CTRL1, 0);
487325ba852SDmitry Baryshkov 	}
488325ba852SDmitry Baryshkov }
489325ba852SDmitry Baryshkov 
490325ba852SDmitry Baryshkov /*
491325ba852SDmitry Baryshkov  * Calibration for the internal oscillator: we need to set calibration mode,
492325ba852SDmitry Baryshkov  * and then pulse the IRQ line low for a 10ms ± 1% period.
493325ba852SDmitry Baryshkov  */
tda998x_cec_calibration(struct tda998x_priv * priv)494325ba852SDmitry Baryshkov static void tda998x_cec_calibration(struct tda998x_priv *priv)
495325ba852SDmitry Baryshkov {
496325ba852SDmitry Baryshkov 	struct gpio_desc *calib = priv->calib;
497325ba852SDmitry Baryshkov 
498325ba852SDmitry Baryshkov 	mutex_lock(&priv->edid_mutex);
499325ba852SDmitry Baryshkov 	if (priv->hdmi->irq > 0)
500325ba852SDmitry Baryshkov 		disable_irq(priv->hdmi->irq);
501325ba852SDmitry Baryshkov 	gpiod_direction_output(calib, 1);
502325ba852SDmitry Baryshkov 	tda998x_cec_set_calibration(priv, true);
503325ba852SDmitry Baryshkov 
504325ba852SDmitry Baryshkov 	local_irq_disable();
505325ba852SDmitry Baryshkov 	gpiod_set_value(calib, 0);
506325ba852SDmitry Baryshkov 	mdelay(10);
507325ba852SDmitry Baryshkov 	gpiod_set_value(calib, 1);
508325ba852SDmitry Baryshkov 	local_irq_enable();
509325ba852SDmitry Baryshkov 
510325ba852SDmitry Baryshkov 	tda998x_cec_set_calibration(priv, false);
511325ba852SDmitry Baryshkov 	gpiod_direction_input(calib);
512325ba852SDmitry Baryshkov 	if (priv->hdmi->irq > 0)
513325ba852SDmitry Baryshkov 		enable_irq(priv->hdmi->irq);
514325ba852SDmitry Baryshkov 	mutex_unlock(&priv->edid_mutex);
515325ba852SDmitry Baryshkov }
516325ba852SDmitry Baryshkov 
tda998x_cec_hook_init(void * data)517325ba852SDmitry Baryshkov static int tda998x_cec_hook_init(void *data)
518325ba852SDmitry Baryshkov {
519325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = data;
520325ba852SDmitry Baryshkov 	struct gpio_desc *calib;
521325ba852SDmitry Baryshkov 
522325ba852SDmitry Baryshkov 	calib = gpiod_get(&priv->hdmi->dev, "nxp,calib", GPIOD_ASIS);
523325ba852SDmitry Baryshkov 	if (IS_ERR(calib)) {
524325ba852SDmitry Baryshkov 		dev_warn(&priv->hdmi->dev, "failed to get calibration gpio: %ld\n",
525325ba852SDmitry Baryshkov 			 PTR_ERR(calib));
526325ba852SDmitry Baryshkov 		return PTR_ERR(calib);
527325ba852SDmitry Baryshkov 	}
528325ba852SDmitry Baryshkov 
529325ba852SDmitry Baryshkov 	priv->calib = calib;
530325ba852SDmitry Baryshkov 
531325ba852SDmitry Baryshkov 	return 0;
532325ba852SDmitry Baryshkov }
533325ba852SDmitry Baryshkov 
tda998x_cec_hook_exit(void * data)534325ba852SDmitry Baryshkov static void tda998x_cec_hook_exit(void *data)
535325ba852SDmitry Baryshkov {
536325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = data;
537325ba852SDmitry Baryshkov 
538325ba852SDmitry Baryshkov 	gpiod_put(priv->calib);
539325ba852SDmitry Baryshkov 	priv->calib = NULL;
540325ba852SDmitry Baryshkov }
541325ba852SDmitry Baryshkov 
tda998x_cec_hook_open(void * data)542325ba852SDmitry Baryshkov static int tda998x_cec_hook_open(void *data)
543325ba852SDmitry Baryshkov {
544325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = data;
545325ba852SDmitry Baryshkov 
546325ba852SDmitry Baryshkov 	cec_enamods(priv, CEC_ENAMODS_EN_CEC_CLK | CEC_ENAMODS_EN_CEC, true);
547325ba852SDmitry Baryshkov 	tda998x_cec_calibration(priv);
548325ba852SDmitry Baryshkov 
549325ba852SDmitry Baryshkov 	return 0;
550325ba852SDmitry Baryshkov }
551325ba852SDmitry Baryshkov 
tda998x_cec_hook_release(void * data)552325ba852SDmitry Baryshkov static void tda998x_cec_hook_release(void *data)
553325ba852SDmitry Baryshkov {
554325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = data;
555325ba852SDmitry Baryshkov 
556325ba852SDmitry Baryshkov 	cec_enamods(priv, CEC_ENAMODS_EN_CEC_CLK | CEC_ENAMODS_EN_CEC, false);
557325ba852SDmitry Baryshkov }
558325ba852SDmitry Baryshkov 
559325ba852SDmitry Baryshkov static int
set_page(struct tda998x_priv * priv,u16 reg)560325ba852SDmitry Baryshkov set_page(struct tda998x_priv *priv, u16 reg)
561325ba852SDmitry Baryshkov {
562325ba852SDmitry Baryshkov 	if (REG2PAGE(reg) != priv->current_page) {
563325ba852SDmitry Baryshkov 		struct i2c_client *client = priv->hdmi;
564325ba852SDmitry Baryshkov 		u8 buf[] = {
565325ba852SDmitry Baryshkov 				REG_CURPAGE, REG2PAGE(reg)
566325ba852SDmitry Baryshkov 		};
567325ba852SDmitry Baryshkov 		int ret = i2c_master_send(client, buf, sizeof(buf));
568325ba852SDmitry Baryshkov 		if (ret < 0) {
569325ba852SDmitry Baryshkov 			dev_err(&client->dev, "%s %04x err %d\n", __func__,
570325ba852SDmitry Baryshkov 					reg, ret);
571325ba852SDmitry Baryshkov 			return ret;
572325ba852SDmitry Baryshkov 		}
573325ba852SDmitry Baryshkov 
574325ba852SDmitry Baryshkov 		priv->current_page = REG2PAGE(reg);
575325ba852SDmitry Baryshkov 	}
576325ba852SDmitry Baryshkov 	return 0;
577325ba852SDmitry Baryshkov }
578325ba852SDmitry Baryshkov 
579325ba852SDmitry Baryshkov static int
reg_read_range(struct tda998x_priv * priv,u16 reg,char * buf,int cnt)580325ba852SDmitry Baryshkov reg_read_range(struct tda998x_priv *priv, u16 reg, char *buf, int cnt)
581325ba852SDmitry Baryshkov {
582325ba852SDmitry Baryshkov 	struct i2c_client *client = priv->hdmi;
583325ba852SDmitry Baryshkov 	u8 addr = REG2ADDR(reg);
584325ba852SDmitry Baryshkov 	int ret;
585325ba852SDmitry Baryshkov 
586325ba852SDmitry Baryshkov 	mutex_lock(&priv->mutex);
587325ba852SDmitry Baryshkov 	ret = set_page(priv, reg);
588325ba852SDmitry Baryshkov 	if (ret < 0)
589325ba852SDmitry Baryshkov 		goto out;
590325ba852SDmitry Baryshkov 
591325ba852SDmitry Baryshkov 	ret = i2c_master_send(client, &addr, sizeof(addr));
592325ba852SDmitry Baryshkov 	if (ret < 0)
593325ba852SDmitry Baryshkov 		goto fail;
594325ba852SDmitry Baryshkov 
595325ba852SDmitry Baryshkov 	ret = i2c_master_recv(client, buf, cnt);
596325ba852SDmitry Baryshkov 	if (ret < 0)
597325ba852SDmitry Baryshkov 		goto fail;
598325ba852SDmitry Baryshkov 
599325ba852SDmitry Baryshkov 	goto out;
600325ba852SDmitry Baryshkov 
601325ba852SDmitry Baryshkov fail:
602325ba852SDmitry Baryshkov 	dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg);
603325ba852SDmitry Baryshkov out:
604325ba852SDmitry Baryshkov 	mutex_unlock(&priv->mutex);
605325ba852SDmitry Baryshkov 	return ret;
606325ba852SDmitry Baryshkov }
607325ba852SDmitry Baryshkov 
608325ba852SDmitry Baryshkov #define MAX_WRITE_RANGE_BUF 32
609325ba852SDmitry Baryshkov 
610325ba852SDmitry Baryshkov static void
reg_write_range(struct tda998x_priv * priv,u16 reg,u8 * p,int cnt)611325ba852SDmitry Baryshkov reg_write_range(struct tda998x_priv *priv, u16 reg, u8 *p, int cnt)
612325ba852SDmitry Baryshkov {
613325ba852SDmitry Baryshkov 	struct i2c_client *client = priv->hdmi;
614325ba852SDmitry Baryshkov 	/* This is the maximum size of the buffer passed in */
615325ba852SDmitry Baryshkov 	u8 buf[MAX_WRITE_RANGE_BUF + 1];
616325ba852SDmitry Baryshkov 	int ret;
617325ba852SDmitry Baryshkov 
618325ba852SDmitry Baryshkov 	if (cnt > MAX_WRITE_RANGE_BUF) {
619325ba852SDmitry Baryshkov 		dev_err(&client->dev, "Fixed write buffer too small (%d)\n",
620325ba852SDmitry Baryshkov 				MAX_WRITE_RANGE_BUF);
621325ba852SDmitry Baryshkov 		return;
622325ba852SDmitry Baryshkov 	}
623325ba852SDmitry Baryshkov 
624325ba852SDmitry Baryshkov 	buf[0] = REG2ADDR(reg);
625325ba852SDmitry Baryshkov 	memcpy(&buf[1], p, cnt);
626325ba852SDmitry Baryshkov 
627325ba852SDmitry Baryshkov 	mutex_lock(&priv->mutex);
628325ba852SDmitry Baryshkov 	ret = set_page(priv, reg);
629325ba852SDmitry Baryshkov 	if (ret < 0)
630325ba852SDmitry Baryshkov 		goto out;
631325ba852SDmitry Baryshkov 
632325ba852SDmitry Baryshkov 	ret = i2c_master_send(client, buf, cnt + 1);
633325ba852SDmitry Baryshkov 	if (ret < 0)
634325ba852SDmitry Baryshkov 		dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
635325ba852SDmitry Baryshkov out:
636325ba852SDmitry Baryshkov 	mutex_unlock(&priv->mutex);
637325ba852SDmitry Baryshkov }
638325ba852SDmitry Baryshkov 
639325ba852SDmitry Baryshkov static int
reg_read(struct tda998x_priv * priv,u16 reg)640325ba852SDmitry Baryshkov reg_read(struct tda998x_priv *priv, u16 reg)
641325ba852SDmitry Baryshkov {
642325ba852SDmitry Baryshkov 	u8 val = 0;
643325ba852SDmitry Baryshkov 	int ret;
644325ba852SDmitry Baryshkov 
645325ba852SDmitry Baryshkov 	ret = reg_read_range(priv, reg, &val, sizeof(val));
646325ba852SDmitry Baryshkov 	if (ret < 0)
647325ba852SDmitry Baryshkov 		return ret;
648325ba852SDmitry Baryshkov 	return val;
649325ba852SDmitry Baryshkov }
650325ba852SDmitry Baryshkov 
651325ba852SDmitry Baryshkov static void
reg_write(struct tda998x_priv * priv,u16 reg,u8 val)652325ba852SDmitry Baryshkov reg_write(struct tda998x_priv *priv, u16 reg, u8 val)
653325ba852SDmitry Baryshkov {
654325ba852SDmitry Baryshkov 	struct i2c_client *client = priv->hdmi;
655325ba852SDmitry Baryshkov 	u8 buf[] = {REG2ADDR(reg), val};
656325ba852SDmitry Baryshkov 	int ret;
657325ba852SDmitry Baryshkov 
658325ba852SDmitry Baryshkov 	mutex_lock(&priv->mutex);
659325ba852SDmitry Baryshkov 	ret = set_page(priv, reg);
660325ba852SDmitry Baryshkov 	if (ret < 0)
661325ba852SDmitry Baryshkov 		goto out;
662325ba852SDmitry Baryshkov 
663325ba852SDmitry Baryshkov 	ret = i2c_master_send(client, buf, sizeof(buf));
664325ba852SDmitry Baryshkov 	if (ret < 0)
665325ba852SDmitry Baryshkov 		dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
666325ba852SDmitry Baryshkov out:
667325ba852SDmitry Baryshkov 	mutex_unlock(&priv->mutex);
668325ba852SDmitry Baryshkov }
669325ba852SDmitry Baryshkov 
670325ba852SDmitry Baryshkov static void
reg_write16(struct tda998x_priv * priv,u16 reg,u16 val)671325ba852SDmitry Baryshkov reg_write16(struct tda998x_priv *priv, u16 reg, u16 val)
672325ba852SDmitry Baryshkov {
673325ba852SDmitry Baryshkov 	struct i2c_client *client = priv->hdmi;
674325ba852SDmitry Baryshkov 	u8 buf[] = {REG2ADDR(reg), val >> 8, val};
675325ba852SDmitry Baryshkov 	int ret;
676325ba852SDmitry Baryshkov 
677325ba852SDmitry Baryshkov 	mutex_lock(&priv->mutex);
678325ba852SDmitry Baryshkov 	ret = set_page(priv, reg);
679325ba852SDmitry Baryshkov 	if (ret < 0)
680325ba852SDmitry Baryshkov 		goto out;
681325ba852SDmitry Baryshkov 
682325ba852SDmitry Baryshkov 	ret = i2c_master_send(client, buf, sizeof(buf));
683325ba852SDmitry Baryshkov 	if (ret < 0)
684325ba852SDmitry Baryshkov 		dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
685325ba852SDmitry Baryshkov out:
686325ba852SDmitry Baryshkov 	mutex_unlock(&priv->mutex);
687325ba852SDmitry Baryshkov }
688325ba852SDmitry Baryshkov 
689325ba852SDmitry Baryshkov static void
reg_set(struct tda998x_priv * priv,u16 reg,u8 val)690325ba852SDmitry Baryshkov reg_set(struct tda998x_priv *priv, u16 reg, u8 val)
691325ba852SDmitry Baryshkov {
692325ba852SDmitry Baryshkov 	int old_val;
693325ba852SDmitry Baryshkov 
694325ba852SDmitry Baryshkov 	old_val = reg_read(priv, reg);
695325ba852SDmitry Baryshkov 	if (old_val >= 0)
696325ba852SDmitry Baryshkov 		reg_write(priv, reg, old_val | val);
697325ba852SDmitry Baryshkov }
698325ba852SDmitry Baryshkov 
699325ba852SDmitry Baryshkov static void
reg_clear(struct tda998x_priv * priv,u16 reg,u8 val)700325ba852SDmitry Baryshkov reg_clear(struct tda998x_priv *priv, u16 reg, u8 val)
701325ba852SDmitry Baryshkov {
702325ba852SDmitry Baryshkov 	int old_val;
703325ba852SDmitry Baryshkov 
704325ba852SDmitry Baryshkov 	old_val = reg_read(priv, reg);
705325ba852SDmitry Baryshkov 	if (old_val >= 0)
706325ba852SDmitry Baryshkov 		reg_write(priv, reg, old_val & ~val);
707325ba852SDmitry Baryshkov }
708325ba852SDmitry Baryshkov 
709325ba852SDmitry Baryshkov static void
tda998x_reset(struct tda998x_priv * priv)710325ba852SDmitry Baryshkov tda998x_reset(struct tda998x_priv *priv)
711325ba852SDmitry Baryshkov {
712325ba852SDmitry Baryshkov 	/* reset audio and i2c master: */
713325ba852SDmitry Baryshkov 	reg_write(priv, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER);
714325ba852SDmitry Baryshkov 	msleep(50);
715325ba852SDmitry Baryshkov 	reg_write(priv, REG_SOFTRESET, 0);
716325ba852SDmitry Baryshkov 	msleep(50);
717325ba852SDmitry Baryshkov 
718325ba852SDmitry Baryshkov 	/* reset transmitter: */
719325ba852SDmitry Baryshkov 	reg_set(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
720325ba852SDmitry Baryshkov 	reg_clear(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
721325ba852SDmitry Baryshkov 
722325ba852SDmitry Baryshkov 	/* PLL registers common configuration */
723325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SERIAL_1, 0x00);
724325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
725325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SERIAL_3, 0x00);
726325ba852SDmitry Baryshkov 	reg_write(priv, REG_SERIALIZER,   0x00);
727325ba852SDmitry Baryshkov 	reg_write(priv, REG_BUFFER_OUT,   0x00);
728325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SCG1,     0x00);
729325ba852SDmitry Baryshkov 	reg_write(priv, REG_AUDIO_DIV,    AUDIO_DIV_SERCLK_8);
730325ba852SDmitry Baryshkov 	reg_write(priv, REG_SEL_CLK,      SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
731325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SCGN1,    0xfa);
732325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SCGN2,    0x00);
733325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SCGR1,    0x5b);
734325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SCGR2,    0x00);
735325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SCG2,     0x10);
736325ba852SDmitry Baryshkov 
737325ba852SDmitry Baryshkov 	/* Write the default value MUX register */
738325ba852SDmitry Baryshkov 	reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
739325ba852SDmitry Baryshkov }
740325ba852SDmitry Baryshkov 
741325ba852SDmitry Baryshkov /*
742325ba852SDmitry Baryshkov  * The TDA998x has a problem when trying to read the EDID close to a
743325ba852SDmitry Baryshkov  * HPD assertion: it needs a delay of 100ms to avoid timing out while
744325ba852SDmitry Baryshkov  * trying to read EDID data.
745325ba852SDmitry Baryshkov  *
746325ba852SDmitry Baryshkov  * However, tda998x_connector_get_modes() may be called at any moment
747325ba852SDmitry Baryshkov  * after tda998x_connector_detect() indicates that we are connected, so
748325ba852SDmitry Baryshkov  * we need to delay probing modes in tda998x_connector_get_modes() after
749325ba852SDmitry Baryshkov  * we have seen a HPD inactive->active transition.  This code implements
750325ba852SDmitry Baryshkov  * that delay.
751325ba852SDmitry Baryshkov  */
tda998x_edid_delay_done(struct timer_list * t)752325ba852SDmitry Baryshkov static void tda998x_edid_delay_done(struct timer_list *t)
753325ba852SDmitry Baryshkov {
754*41cb0855SIngo Molnar 	struct tda998x_priv *priv = timer_container_of(priv, t,
755*41cb0855SIngo Molnar 						       edid_delay_timer);
756325ba852SDmitry Baryshkov 
757325ba852SDmitry Baryshkov 	priv->edid_delay_active = false;
758325ba852SDmitry Baryshkov 	wake_up(&priv->edid_delay_waitq);
759325ba852SDmitry Baryshkov 	schedule_work(&priv->detect_work);
760325ba852SDmitry Baryshkov }
761325ba852SDmitry Baryshkov 
tda998x_edid_delay_start(struct tda998x_priv * priv)762325ba852SDmitry Baryshkov static void tda998x_edid_delay_start(struct tda998x_priv *priv)
763325ba852SDmitry Baryshkov {
764325ba852SDmitry Baryshkov 	priv->edid_delay_active = true;
765325ba852SDmitry Baryshkov 	mod_timer(&priv->edid_delay_timer, jiffies + HZ/10);
766325ba852SDmitry Baryshkov }
767325ba852SDmitry Baryshkov 
tda998x_edid_delay_wait(struct tda998x_priv * priv)768325ba852SDmitry Baryshkov static int tda998x_edid_delay_wait(struct tda998x_priv *priv)
769325ba852SDmitry Baryshkov {
770325ba852SDmitry Baryshkov 	return wait_event_killable(priv->edid_delay_waitq, !priv->edid_delay_active);
771325ba852SDmitry Baryshkov }
772325ba852SDmitry Baryshkov 
773325ba852SDmitry Baryshkov /*
774325ba852SDmitry Baryshkov  * We need to run the KMS hotplug event helper outside of our threaded
775325ba852SDmitry Baryshkov  * interrupt routine as this can call back into our get_modes method,
776325ba852SDmitry Baryshkov  * which will want to make use of interrupts.
777325ba852SDmitry Baryshkov  */
tda998x_detect_work(struct work_struct * work)778325ba852SDmitry Baryshkov static void tda998x_detect_work(struct work_struct *work)
779325ba852SDmitry Baryshkov {
780325ba852SDmitry Baryshkov 	struct tda998x_priv *priv =
781325ba852SDmitry Baryshkov 		container_of(work, struct tda998x_priv, detect_work);
782325ba852SDmitry Baryshkov 	struct drm_device *dev = priv->connector.dev;
783325ba852SDmitry Baryshkov 
784325ba852SDmitry Baryshkov 	if (dev)
785325ba852SDmitry Baryshkov 		drm_kms_helper_hotplug_event(dev);
786325ba852SDmitry Baryshkov }
787325ba852SDmitry Baryshkov 
788325ba852SDmitry Baryshkov /*
789325ba852SDmitry Baryshkov  * only 2 interrupts may occur: screen plug/unplug and EDID read
790325ba852SDmitry Baryshkov  */
tda998x_irq_thread(int irq,void * data)791325ba852SDmitry Baryshkov static irqreturn_t tda998x_irq_thread(int irq, void *data)
792325ba852SDmitry Baryshkov {
793325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = data;
794325ba852SDmitry Baryshkov 	u8 sta, cec, lvl, flag0, flag1, flag2;
795325ba852SDmitry Baryshkov 	bool handled = false;
796325ba852SDmitry Baryshkov 
797325ba852SDmitry Baryshkov 	sta = cec_read(priv, REG_CEC_INTSTATUS);
798325ba852SDmitry Baryshkov 	if (sta & CEC_INTSTATUS_HDMI) {
799325ba852SDmitry Baryshkov 		cec = cec_read(priv, REG_CEC_RXSHPDINT);
800325ba852SDmitry Baryshkov 		lvl = cec_read(priv, REG_CEC_RXSHPDLEV);
801325ba852SDmitry Baryshkov 		flag0 = reg_read(priv, REG_INT_FLAGS_0);
802325ba852SDmitry Baryshkov 		flag1 = reg_read(priv, REG_INT_FLAGS_1);
803325ba852SDmitry Baryshkov 		flag2 = reg_read(priv, REG_INT_FLAGS_2);
804325ba852SDmitry Baryshkov 		DRM_DEBUG_DRIVER(
805325ba852SDmitry Baryshkov 			"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n",
806325ba852SDmitry Baryshkov 			sta, cec, lvl, flag0, flag1, flag2);
807325ba852SDmitry Baryshkov 
808325ba852SDmitry Baryshkov 		if (cec & CEC_RXSHPDINT_HPD) {
809325ba852SDmitry Baryshkov 			if (lvl & CEC_RXSHPDLEV_HPD) {
810325ba852SDmitry Baryshkov 				tda998x_edid_delay_start(priv);
811325ba852SDmitry Baryshkov 			} else {
812325ba852SDmitry Baryshkov 				schedule_work(&priv->detect_work);
813325ba852SDmitry Baryshkov 				cec_notifier_phys_addr_invalidate(
814325ba852SDmitry Baryshkov 						priv->cec_notify);
815325ba852SDmitry Baryshkov 			}
816325ba852SDmitry Baryshkov 
817325ba852SDmitry Baryshkov 			handled = true;
818325ba852SDmitry Baryshkov 		}
819325ba852SDmitry Baryshkov 
820325ba852SDmitry Baryshkov 		if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) {
821325ba852SDmitry Baryshkov 			priv->wq_edid_wait = 0;
822325ba852SDmitry Baryshkov 			wake_up(&priv->wq_edid);
823325ba852SDmitry Baryshkov 			handled = true;
824325ba852SDmitry Baryshkov 		}
825325ba852SDmitry Baryshkov 	}
826325ba852SDmitry Baryshkov 
827325ba852SDmitry Baryshkov 	return IRQ_RETVAL(handled);
828325ba852SDmitry Baryshkov }
829325ba852SDmitry Baryshkov 
830325ba852SDmitry Baryshkov static void
tda998x_write_if(struct tda998x_priv * priv,u8 bit,u16 addr,union hdmi_infoframe * frame)831325ba852SDmitry Baryshkov tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr,
832325ba852SDmitry Baryshkov 		 union hdmi_infoframe *frame)
833325ba852SDmitry Baryshkov {
834325ba852SDmitry Baryshkov 	u8 buf[MAX_WRITE_RANGE_BUF];
835325ba852SDmitry Baryshkov 	ssize_t len;
836325ba852SDmitry Baryshkov 
837325ba852SDmitry Baryshkov 	len = hdmi_infoframe_pack(frame, buf, sizeof(buf));
838325ba852SDmitry Baryshkov 	if (len < 0) {
839325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev,
840325ba852SDmitry Baryshkov 			"hdmi_infoframe_pack() type=0x%02x failed: %zd\n",
841325ba852SDmitry Baryshkov 			frame->any.type, len);
842325ba852SDmitry Baryshkov 		return;
843325ba852SDmitry Baryshkov 	}
844325ba852SDmitry Baryshkov 
845325ba852SDmitry Baryshkov 	reg_clear(priv, REG_DIP_IF_FLAGS, bit);
846325ba852SDmitry Baryshkov 	reg_write_range(priv, addr, buf, len);
847325ba852SDmitry Baryshkov 	reg_set(priv, REG_DIP_IF_FLAGS, bit);
848325ba852SDmitry Baryshkov }
849325ba852SDmitry Baryshkov 
tda998x_write_aif(struct tda998x_priv * priv,const struct hdmi_audio_infoframe * cea)850325ba852SDmitry Baryshkov static void tda998x_write_aif(struct tda998x_priv *priv,
851325ba852SDmitry Baryshkov 			      const struct hdmi_audio_infoframe *cea)
852325ba852SDmitry Baryshkov {
853325ba852SDmitry Baryshkov 	union hdmi_infoframe frame;
854325ba852SDmitry Baryshkov 
855325ba852SDmitry Baryshkov 	frame.audio = *cea;
856325ba852SDmitry Baryshkov 
857325ba852SDmitry Baryshkov 	tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame);
858325ba852SDmitry Baryshkov }
859325ba852SDmitry Baryshkov 
860325ba852SDmitry Baryshkov static void
tda998x_write_avi(struct tda998x_priv * priv,const struct drm_display_mode * mode)861325ba852SDmitry Baryshkov tda998x_write_avi(struct tda998x_priv *priv, const struct drm_display_mode *mode)
862325ba852SDmitry Baryshkov {
863325ba852SDmitry Baryshkov 	union hdmi_infoframe frame;
864325ba852SDmitry Baryshkov 
865325ba852SDmitry Baryshkov 	drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
866325ba852SDmitry Baryshkov 						 &priv->connector, mode);
867325ba852SDmitry Baryshkov 	frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
868325ba852SDmitry Baryshkov 	drm_hdmi_avi_infoframe_quant_range(&frame.avi, &priv->connector, mode,
869325ba852SDmitry Baryshkov 					   priv->rgb_quant_range);
870325ba852SDmitry Baryshkov 
871325ba852SDmitry Baryshkov 	tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame);
872325ba852SDmitry Baryshkov }
873325ba852SDmitry Baryshkov 
tda998x_write_vsi(struct tda998x_priv * priv,const struct drm_display_mode * mode)874325ba852SDmitry Baryshkov static void tda998x_write_vsi(struct tda998x_priv *priv,
875325ba852SDmitry Baryshkov 			      const struct drm_display_mode *mode)
876325ba852SDmitry Baryshkov {
877325ba852SDmitry Baryshkov 	union hdmi_infoframe frame;
878325ba852SDmitry Baryshkov 
879325ba852SDmitry Baryshkov 	if (drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
880325ba852SDmitry Baryshkov 							&priv->connector,
881325ba852SDmitry Baryshkov 							mode))
882325ba852SDmitry Baryshkov 		reg_clear(priv, REG_DIP_IF_FLAGS, DIP_IF_FLAGS_IF1);
883325ba852SDmitry Baryshkov 	else
884325ba852SDmitry Baryshkov 		tda998x_write_if(priv, DIP_IF_FLAGS_IF1, REG_IF1_HB0, &frame);
885325ba852SDmitry Baryshkov }
886325ba852SDmitry Baryshkov 
887325ba852SDmitry Baryshkov /* Audio support */
888325ba852SDmitry Baryshkov 
889325ba852SDmitry Baryshkov static const struct tda998x_audio_route tda998x_audio_route[AUDIO_ROUTE_NUM] = {
890325ba852SDmitry Baryshkov 	[AUDIO_ROUTE_I2S] = {
891325ba852SDmitry Baryshkov 		.ena_aclk = 1,
892325ba852SDmitry Baryshkov 		.mux_ap = MUX_AP_SELECT_I2S,
893325ba852SDmitry Baryshkov 		.aip_clksel = AIP_CLKSEL_AIP_I2S | AIP_CLKSEL_FS_ACLK,
894325ba852SDmitry Baryshkov 	},
895325ba852SDmitry Baryshkov 	[AUDIO_ROUTE_SPDIF] = {
896325ba852SDmitry Baryshkov 		.ena_aclk = 0,
897325ba852SDmitry Baryshkov 		.mux_ap = MUX_AP_SELECT_SPDIF,
898325ba852SDmitry Baryshkov 		.aip_clksel = AIP_CLKSEL_AIP_SPDIF | AIP_CLKSEL_FS_FS64SPDIF,
899325ba852SDmitry Baryshkov 	},
900325ba852SDmitry Baryshkov };
901325ba852SDmitry Baryshkov 
902325ba852SDmitry Baryshkov /* Configure the TDA998x audio data and clock routing. */
tda998x_derive_routing(struct tda998x_priv * priv,struct tda998x_audio_settings * s,unsigned int route)903325ba852SDmitry Baryshkov static int tda998x_derive_routing(struct tda998x_priv *priv,
904325ba852SDmitry Baryshkov 				  struct tda998x_audio_settings *s,
905325ba852SDmitry Baryshkov 				  unsigned int route)
906325ba852SDmitry Baryshkov {
907325ba852SDmitry Baryshkov 	s->route = &tda998x_audio_route[route];
908325ba852SDmitry Baryshkov 	s->ena_ap = priv->audio_port_enable[route];
909325ba852SDmitry Baryshkov 	if (s->ena_ap == 0) {
910325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev, "no audio configuration found\n");
911325ba852SDmitry Baryshkov 		return -EINVAL;
912325ba852SDmitry Baryshkov 	}
913325ba852SDmitry Baryshkov 
914325ba852SDmitry Baryshkov 	return 0;
915325ba852SDmitry Baryshkov }
916325ba852SDmitry Baryshkov 
917325ba852SDmitry Baryshkov /*
918325ba852SDmitry Baryshkov  * The audio clock divisor register controls a divider producing Audio_Clk_Out
919325ba852SDmitry Baryshkov  * from SERclk by dividing it by 2^n where 0 <= n <= 5.  We don't know what
920325ba852SDmitry Baryshkov  * Audio_Clk_Out or SERclk are. We guess SERclk is the same as TMDS clock.
921325ba852SDmitry Baryshkov  *
922325ba852SDmitry Baryshkov  * It seems that Audio_Clk_Out must be the smallest value that is greater
923325ba852SDmitry Baryshkov  * than 128*fs, otherwise audio does not function. There is some suggestion
924325ba852SDmitry Baryshkov  * that 126*fs is a better value.
925325ba852SDmitry Baryshkov  */
tda998x_get_adiv(struct tda998x_priv * priv,unsigned int fs)926325ba852SDmitry Baryshkov static u8 tda998x_get_adiv(struct tda998x_priv *priv, unsigned int fs)
927325ba852SDmitry Baryshkov {
928325ba852SDmitry Baryshkov 	unsigned long min_audio_clk = fs * 128;
929325ba852SDmitry Baryshkov 	unsigned long ser_clk = priv->tmds_clock * 1000;
930325ba852SDmitry Baryshkov 	u8 adiv;
931325ba852SDmitry Baryshkov 
932325ba852SDmitry Baryshkov 	for (adiv = AUDIO_DIV_SERCLK_32; adiv != AUDIO_DIV_SERCLK_1; adiv--)
933325ba852SDmitry Baryshkov 		if (ser_clk > min_audio_clk << adiv)
934325ba852SDmitry Baryshkov 			break;
935325ba852SDmitry Baryshkov 
936325ba852SDmitry Baryshkov 	dev_dbg(&priv->hdmi->dev,
937325ba852SDmitry Baryshkov 		"ser_clk=%luHz fs=%uHz min_aclk=%luHz adiv=%d\n",
938325ba852SDmitry Baryshkov 		ser_clk, fs, min_audio_clk, adiv);
939325ba852SDmitry Baryshkov 
940325ba852SDmitry Baryshkov 	return adiv;
941325ba852SDmitry Baryshkov }
942325ba852SDmitry Baryshkov 
943325ba852SDmitry Baryshkov /*
944325ba852SDmitry Baryshkov  * In auto-CTS mode, the TDA998x uses a "measured time stamp" counter to
945325ba852SDmitry Baryshkov  * generate the CTS value.  It appears that the "measured time stamp" is
946325ba852SDmitry Baryshkov  * the number of TDMS clock cycles within a number of audio input clock
947325ba852SDmitry Baryshkov  * cycles defined by the k and N parameters defined below, in a similar
948325ba852SDmitry Baryshkov  * way to that which is set out in the CTS generation in the HDMI spec.
949325ba852SDmitry Baryshkov  *
950325ba852SDmitry Baryshkov  *  tmdsclk ----> mts -> /m ---> CTS
951325ba852SDmitry Baryshkov  *                 ^
952325ba852SDmitry Baryshkov  *  sclk -> /k -> /N
953325ba852SDmitry Baryshkov  *
954325ba852SDmitry Baryshkov  * CTS = mts / m, where m is 2^M.
955325ba852SDmitry Baryshkov  * /k is a divider based on the K value below, K+1 for K < 4, or 8 for K >= 4
956325ba852SDmitry Baryshkov  * /N is a divider based on the HDMI specified N value.
957325ba852SDmitry Baryshkov  *
958325ba852SDmitry Baryshkov  * This produces the following equation:
959325ba852SDmitry Baryshkov  *  CTS = tmds_clock * k * N / (sclk * m)
960325ba852SDmitry Baryshkov  *
961325ba852SDmitry Baryshkov  * When combined with the sink-side equation, and realising that sclk is
962325ba852SDmitry Baryshkov  * bclk_ratio * fs, we end up with:
963325ba852SDmitry Baryshkov  *  k = m * bclk_ratio / 128.
964325ba852SDmitry Baryshkov  *
965325ba852SDmitry Baryshkov  * Note: S/PDIF always uses a bclk_ratio of 64.
966325ba852SDmitry Baryshkov  */
tda998x_derive_cts_n(struct tda998x_priv * priv,struct tda998x_audio_settings * settings,unsigned int ratio)967325ba852SDmitry Baryshkov static int tda998x_derive_cts_n(struct tda998x_priv *priv,
968325ba852SDmitry Baryshkov 				struct tda998x_audio_settings *settings,
969325ba852SDmitry Baryshkov 				unsigned int ratio)
970325ba852SDmitry Baryshkov {
971325ba852SDmitry Baryshkov 	switch (ratio) {
972325ba852SDmitry Baryshkov 	case 16:
973325ba852SDmitry Baryshkov 		settings->cts_n = CTS_N_M(3) | CTS_N_K(0);
974325ba852SDmitry Baryshkov 		break;
975325ba852SDmitry Baryshkov 	case 32:
976325ba852SDmitry Baryshkov 		settings->cts_n = CTS_N_M(3) | CTS_N_K(1);
977325ba852SDmitry Baryshkov 		break;
978325ba852SDmitry Baryshkov 	case 48:
979325ba852SDmitry Baryshkov 		settings->cts_n = CTS_N_M(3) | CTS_N_K(2);
980325ba852SDmitry Baryshkov 		break;
981325ba852SDmitry Baryshkov 	case 64:
982325ba852SDmitry Baryshkov 		settings->cts_n = CTS_N_M(3) | CTS_N_K(3);
983325ba852SDmitry Baryshkov 		break;
984325ba852SDmitry Baryshkov 	case 128:
985325ba852SDmitry Baryshkov 		settings->cts_n = CTS_N_M(0) | CTS_N_K(0);
986325ba852SDmitry Baryshkov 		break;
987325ba852SDmitry Baryshkov 	default:
988325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev, "unsupported bclk ratio %ufs\n",
989325ba852SDmitry Baryshkov 			ratio);
990325ba852SDmitry Baryshkov 		return -EINVAL;
991325ba852SDmitry Baryshkov 	}
992325ba852SDmitry Baryshkov 	return 0;
993325ba852SDmitry Baryshkov }
994325ba852SDmitry Baryshkov 
tda998x_audio_mute(struct tda998x_priv * priv,bool on)995325ba852SDmitry Baryshkov static void tda998x_audio_mute(struct tda998x_priv *priv, bool on)
996325ba852SDmitry Baryshkov {
997325ba852SDmitry Baryshkov 	if (on) {
998325ba852SDmitry Baryshkov 		reg_set(priv, REG_SOFTRESET, SOFTRESET_AUDIO);
999325ba852SDmitry Baryshkov 		reg_clear(priv, REG_SOFTRESET, SOFTRESET_AUDIO);
1000325ba852SDmitry Baryshkov 		reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
1001325ba852SDmitry Baryshkov 	} else {
1002325ba852SDmitry Baryshkov 		reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
1003325ba852SDmitry Baryshkov 	}
1004325ba852SDmitry Baryshkov }
1005325ba852SDmitry Baryshkov 
tda998x_configure_audio(struct tda998x_priv * priv)1006325ba852SDmitry Baryshkov static void tda998x_configure_audio(struct tda998x_priv *priv)
1007325ba852SDmitry Baryshkov {
1008325ba852SDmitry Baryshkov 	const struct tda998x_audio_settings *settings = &priv->audio;
1009325ba852SDmitry Baryshkov 	u8 buf[6], adiv;
1010325ba852SDmitry Baryshkov 	u32 n;
1011325ba852SDmitry Baryshkov 
1012325ba852SDmitry Baryshkov 	/* If audio is not configured, there is nothing to do. */
1013325ba852SDmitry Baryshkov 	if (settings->ena_ap == 0)
1014325ba852SDmitry Baryshkov 		return;
1015325ba852SDmitry Baryshkov 
1016325ba852SDmitry Baryshkov 	adiv = tda998x_get_adiv(priv, settings->sample_rate);
1017325ba852SDmitry Baryshkov 
1018325ba852SDmitry Baryshkov 	/* Enable audio ports */
1019325ba852SDmitry Baryshkov 	reg_write(priv, REG_ENA_AP, settings->ena_ap);
1020325ba852SDmitry Baryshkov 	reg_write(priv, REG_ENA_ACLK, settings->route->ena_aclk);
1021325ba852SDmitry Baryshkov 	reg_write(priv, REG_MUX_AP, settings->route->mux_ap);
1022325ba852SDmitry Baryshkov 	reg_write(priv, REG_I2S_FORMAT, settings->i2s_format);
1023325ba852SDmitry Baryshkov 	reg_write(priv, REG_AIP_CLKSEL, settings->route->aip_clksel);
1024325ba852SDmitry Baryshkov 	reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT |
1025325ba852SDmitry Baryshkov 					AIP_CNTRL_0_ACR_MAN);	/* auto CTS */
1026325ba852SDmitry Baryshkov 	reg_write(priv, REG_CTS_N, settings->cts_n);
1027325ba852SDmitry Baryshkov 	reg_write(priv, REG_AUDIO_DIV, adiv);
1028325ba852SDmitry Baryshkov 
1029325ba852SDmitry Baryshkov 	/*
1030325ba852SDmitry Baryshkov 	 * This is the approximate value of N, which happens to be
1031325ba852SDmitry Baryshkov 	 * the recommended values for non-coherent clocks.
1032325ba852SDmitry Baryshkov 	 */
1033325ba852SDmitry Baryshkov 	n = 128 * settings->sample_rate / 1000;
1034325ba852SDmitry Baryshkov 
1035325ba852SDmitry Baryshkov 	/* Write the CTS and N values */
1036325ba852SDmitry Baryshkov 	buf[0] = 0x44;
1037325ba852SDmitry Baryshkov 	buf[1] = 0x42;
1038325ba852SDmitry Baryshkov 	buf[2] = 0x01;
1039325ba852SDmitry Baryshkov 	buf[3] = n;
1040325ba852SDmitry Baryshkov 	buf[4] = n >> 8;
1041325ba852SDmitry Baryshkov 	buf[5] = n >> 16;
1042325ba852SDmitry Baryshkov 	reg_write_range(priv, REG_ACR_CTS_0, buf, 6);
1043325ba852SDmitry Baryshkov 
1044325ba852SDmitry Baryshkov 	/* Reset CTS generator */
1045325ba852SDmitry Baryshkov 	reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
1046325ba852SDmitry Baryshkov 	reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
1047325ba852SDmitry Baryshkov 
1048325ba852SDmitry Baryshkov 	/* Write the channel status
1049325ba852SDmitry Baryshkov 	 * The REG_CH_STAT_B-registers skip IEC958 AES2 byte, because
1050325ba852SDmitry Baryshkov 	 * there is a separate register for each I2S wire.
1051325ba852SDmitry Baryshkov 	 */
1052325ba852SDmitry Baryshkov 	buf[0] = settings->status[0];
1053325ba852SDmitry Baryshkov 	buf[1] = settings->status[1];
1054325ba852SDmitry Baryshkov 	buf[2] = settings->status[3];
1055325ba852SDmitry Baryshkov 	buf[3] = settings->status[4];
1056325ba852SDmitry Baryshkov 	reg_write_range(priv, REG_CH_STAT_B(0), buf, 4);
1057325ba852SDmitry Baryshkov 
1058325ba852SDmitry Baryshkov 	tda998x_audio_mute(priv, true);
1059325ba852SDmitry Baryshkov 	msleep(20);
1060325ba852SDmitry Baryshkov 	tda998x_audio_mute(priv, false);
1061325ba852SDmitry Baryshkov 
1062325ba852SDmitry Baryshkov 	tda998x_write_aif(priv, &settings->cea);
1063325ba852SDmitry Baryshkov }
1064325ba852SDmitry Baryshkov 
tda998x_audio_hw_params(struct device * dev,void * data,struct hdmi_codec_daifmt * daifmt,struct hdmi_codec_params * params)1065325ba852SDmitry Baryshkov static int tda998x_audio_hw_params(struct device *dev, void *data,
1066325ba852SDmitry Baryshkov 				   struct hdmi_codec_daifmt *daifmt,
1067325ba852SDmitry Baryshkov 				   struct hdmi_codec_params *params)
1068325ba852SDmitry Baryshkov {
1069325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = dev_get_drvdata(dev);
1070325ba852SDmitry Baryshkov 	unsigned int bclk_ratio;
1071325ba852SDmitry Baryshkov 	bool spdif = daifmt->fmt == HDMI_SPDIF;
1072325ba852SDmitry Baryshkov 	int ret;
1073325ba852SDmitry Baryshkov 	struct tda998x_audio_settings audio = {
1074325ba852SDmitry Baryshkov 		.sample_rate = params->sample_rate,
1075325ba852SDmitry Baryshkov 		.cea = params->cea,
1076325ba852SDmitry Baryshkov 	};
1077325ba852SDmitry Baryshkov 
1078325ba852SDmitry Baryshkov 	memcpy(audio.status, params->iec.status,
1079325ba852SDmitry Baryshkov 	       min(sizeof(audio.status), sizeof(params->iec.status)));
1080325ba852SDmitry Baryshkov 
1081325ba852SDmitry Baryshkov 	switch (daifmt->fmt) {
1082325ba852SDmitry Baryshkov 	case HDMI_I2S:
1083325ba852SDmitry Baryshkov 		audio.i2s_format = I2S_FORMAT_PHILIPS;
1084325ba852SDmitry Baryshkov 		break;
1085325ba852SDmitry Baryshkov 	case HDMI_LEFT_J:
1086325ba852SDmitry Baryshkov 		audio.i2s_format = I2S_FORMAT_LEFT_J;
1087325ba852SDmitry Baryshkov 		break;
1088325ba852SDmitry Baryshkov 	case HDMI_RIGHT_J:
1089325ba852SDmitry Baryshkov 		audio.i2s_format = I2S_FORMAT_RIGHT_J;
1090325ba852SDmitry Baryshkov 		break;
1091325ba852SDmitry Baryshkov 	case HDMI_SPDIF:
1092325ba852SDmitry Baryshkov 		audio.i2s_format = 0;
1093325ba852SDmitry Baryshkov 		break;
1094325ba852SDmitry Baryshkov 	default:
1095325ba852SDmitry Baryshkov 		dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt);
1096325ba852SDmitry Baryshkov 		return -EINVAL;
1097325ba852SDmitry Baryshkov 	}
1098325ba852SDmitry Baryshkov 
1099325ba852SDmitry Baryshkov 	if (!spdif &&
1100325ba852SDmitry Baryshkov 	    (daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
1101325ba852SDmitry Baryshkov 	     daifmt->bit_clk_provider || daifmt->frame_clk_provider)) {
1102325ba852SDmitry Baryshkov 		dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
1103325ba852SDmitry Baryshkov 			daifmt->bit_clk_inv, daifmt->frame_clk_inv,
1104325ba852SDmitry Baryshkov 			daifmt->bit_clk_provider,
1105325ba852SDmitry Baryshkov 			daifmt->frame_clk_provider);
1106325ba852SDmitry Baryshkov 		return -EINVAL;
1107325ba852SDmitry Baryshkov 	}
1108325ba852SDmitry Baryshkov 
1109325ba852SDmitry Baryshkov 	ret = tda998x_derive_routing(priv, &audio, AUDIO_ROUTE_I2S + spdif);
1110325ba852SDmitry Baryshkov 	if (ret < 0)
1111325ba852SDmitry Baryshkov 		return ret;
1112325ba852SDmitry Baryshkov 
1113325ba852SDmitry Baryshkov 	bclk_ratio = spdif ? 64 : params->sample_width * 2;
1114325ba852SDmitry Baryshkov 	ret = tda998x_derive_cts_n(priv, &audio, bclk_ratio);
1115325ba852SDmitry Baryshkov 	if (ret < 0)
1116325ba852SDmitry Baryshkov 		return ret;
1117325ba852SDmitry Baryshkov 
1118325ba852SDmitry Baryshkov 	mutex_lock(&priv->audio_mutex);
1119325ba852SDmitry Baryshkov 	priv->audio = audio;
1120325ba852SDmitry Baryshkov 	if (priv->supports_infoframes && priv->sink_has_audio)
1121325ba852SDmitry Baryshkov 		tda998x_configure_audio(priv);
1122325ba852SDmitry Baryshkov 	mutex_unlock(&priv->audio_mutex);
1123325ba852SDmitry Baryshkov 
1124325ba852SDmitry Baryshkov 	return 0;
1125325ba852SDmitry Baryshkov }
1126325ba852SDmitry Baryshkov 
tda998x_audio_shutdown(struct device * dev,void * data)1127325ba852SDmitry Baryshkov static void tda998x_audio_shutdown(struct device *dev, void *data)
1128325ba852SDmitry Baryshkov {
1129325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = dev_get_drvdata(dev);
1130325ba852SDmitry Baryshkov 
1131325ba852SDmitry Baryshkov 	mutex_lock(&priv->audio_mutex);
1132325ba852SDmitry Baryshkov 
1133325ba852SDmitry Baryshkov 	reg_write(priv, REG_ENA_AP, 0);
1134325ba852SDmitry Baryshkov 	priv->audio.ena_ap = 0;
1135325ba852SDmitry Baryshkov 
1136325ba852SDmitry Baryshkov 	mutex_unlock(&priv->audio_mutex);
1137325ba852SDmitry Baryshkov }
1138325ba852SDmitry Baryshkov 
tda998x_audio_mute_stream(struct device * dev,void * data,bool enable,int direction)1139325ba852SDmitry Baryshkov static int tda998x_audio_mute_stream(struct device *dev, void *data,
1140325ba852SDmitry Baryshkov 				     bool enable, int direction)
1141325ba852SDmitry Baryshkov {
1142325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = dev_get_drvdata(dev);
1143325ba852SDmitry Baryshkov 
1144325ba852SDmitry Baryshkov 	mutex_lock(&priv->audio_mutex);
1145325ba852SDmitry Baryshkov 
1146325ba852SDmitry Baryshkov 	tda998x_audio_mute(priv, enable);
1147325ba852SDmitry Baryshkov 
1148325ba852SDmitry Baryshkov 	mutex_unlock(&priv->audio_mutex);
1149325ba852SDmitry Baryshkov 	return 0;
1150325ba852SDmitry Baryshkov }
1151325ba852SDmitry Baryshkov 
tda998x_audio_get_eld(struct device * dev,void * data,uint8_t * buf,size_t len)1152325ba852SDmitry Baryshkov static int tda998x_audio_get_eld(struct device *dev, void *data,
1153325ba852SDmitry Baryshkov 				 uint8_t *buf, size_t len)
1154325ba852SDmitry Baryshkov {
1155325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = dev_get_drvdata(dev);
1156325ba852SDmitry Baryshkov 
1157325ba852SDmitry Baryshkov 	mutex_lock(&priv->audio_mutex);
1158325ba852SDmitry Baryshkov 	memcpy(buf, priv->connector.eld,
1159325ba852SDmitry Baryshkov 	       min(sizeof(priv->connector.eld), len));
1160325ba852SDmitry Baryshkov 	mutex_unlock(&priv->audio_mutex);
1161325ba852SDmitry Baryshkov 
1162325ba852SDmitry Baryshkov 	return 0;
1163325ba852SDmitry Baryshkov }
1164325ba852SDmitry Baryshkov 
1165325ba852SDmitry Baryshkov static const struct hdmi_codec_ops audio_codec_ops = {
1166325ba852SDmitry Baryshkov 	.hw_params = tda998x_audio_hw_params,
1167325ba852SDmitry Baryshkov 	.audio_shutdown = tda998x_audio_shutdown,
1168325ba852SDmitry Baryshkov 	.mute_stream = tda998x_audio_mute_stream,
1169325ba852SDmitry Baryshkov 	.get_eld = tda998x_audio_get_eld,
1170325ba852SDmitry Baryshkov };
1171325ba852SDmitry Baryshkov 
tda998x_audio_codec_init(struct tda998x_priv * priv,struct device * dev)1172325ba852SDmitry Baryshkov static int tda998x_audio_codec_init(struct tda998x_priv *priv,
1173325ba852SDmitry Baryshkov 				    struct device *dev)
1174325ba852SDmitry Baryshkov {
1175325ba852SDmitry Baryshkov 	struct hdmi_codec_pdata codec_data = {
1176325ba852SDmitry Baryshkov 		.ops = &audio_codec_ops,
1177325ba852SDmitry Baryshkov 		.max_i2s_channels = 2,
1178325ba852SDmitry Baryshkov 		.no_i2s_capture = 1,
1179325ba852SDmitry Baryshkov 		.no_spdif_capture = 1,
1180325ba852SDmitry Baryshkov 		.no_capture_mute = 1,
1181325ba852SDmitry Baryshkov 	};
1182325ba852SDmitry Baryshkov 
1183325ba852SDmitry Baryshkov 	if (priv->audio_port_enable[AUDIO_ROUTE_I2S])
1184325ba852SDmitry Baryshkov 		codec_data.i2s = 1;
1185325ba852SDmitry Baryshkov 	if (priv->audio_port_enable[AUDIO_ROUTE_SPDIF])
1186325ba852SDmitry Baryshkov 		codec_data.spdif = 1;
1187325ba852SDmitry Baryshkov 
1188325ba852SDmitry Baryshkov 	priv->audio_pdev = platform_device_register_data(
1189325ba852SDmitry Baryshkov 		dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
1190325ba852SDmitry Baryshkov 		&codec_data, sizeof(codec_data));
1191325ba852SDmitry Baryshkov 
1192325ba852SDmitry Baryshkov 	return PTR_ERR_OR_ZERO(priv->audio_pdev);
1193325ba852SDmitry Baryshkov }
1194325ba852SDmitry Baryshkov 
1195325ba852SDmitry Baryshkov /* DRM connector functions */
1196325ba852SDmitry Baryshkov 
1197325ba852SDmitry Baryshkov static enum drm_connector_status
tda998x_connector_detect(struct drm_connector * connector,bool force)1198325ba852SDmitry Baryshkov tda998x_connector_detect(struct drm_connector *connector, bool force)
1199325ba852SDmitry Baryshkov {
1200325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
1201325ba852SDmitry Baryshkov 	u8 val = cec_read(priv, REG_CEC_RXSHPDLEV);
1202325ba852SDmitry Baryshkov 
1203325ba852SDmitry Baryshkov 	return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
1204325ba852SDmitry Baryshkov 			connector_status_disconnected;
1205325ba852SDmitry Baryshkov }
1206325ba852SDmitry Baryshkov 
tda998x_connector_destroy(struct drm_connector * connector)1207325ba852SDmitry Baryshkov static void tda998x_connector_destroy(struct drm_connector *connector)
1208325ba852SDmitry Baryshkov {
1209325ba852SDmitry Baryshkov 	drm_connector_cleanup(connector);
1210325ba852SDmitry Baryshkov }
1211325ba852SDmitry Baryshkov 
1212325ba852SDmitry Baryshkov static const struct drm_connector_funcs tda998x_connector_funcs = {
1213325ba852SDmitry Baryshkov 	.reset = drm_atomic_helper_connector_reset,
1214325ba852SDmitry Baryshkov 	.fill_modes = drm_helper_probe_single_connector_modes,
1215325ba852SDmitry Baryshkov 	.detect = tda998x_connector_detect,
1216325ba852SDmitry Baryshkov 	.destroy = tda998x_connector_destroy,
1217325ba852SDmitry Baryshkov 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1218325ba852SDmitry Baryshkov 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1219325ba852SDmitry Baryshkov };
1220325ba852SDmitry Baryshkov 
read_edid_block(void * data,u8 * buf,unsigned int blk,size_t length)1221325ba852SDmitry Baryshkov static int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length)
1222325ba852SDmitry Baryshkov {
1223325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = data;
1224325ba852SDmitry Baryshkov 	u8 offset, segptr;
1225325ba852SDmitry Baryshkov 	int ret, i;
1226325ba852SDmitry Baryshkov 
1227325ba852SDmitry Baryshkov 	offset = (blk & 1) ? 128 : 0;
1228325ba852SDmitry Baryshkov 	segptr = blk / 2;
1229325ba852SDmitry Baryshkov 
1230325ba852SDmitry Baryshkov 	mutex_lock(&priv->edid_mutex);
1231325ba852SDmitry Baryshkov 
1232325ba852SDmitry Baryshkov 	reg_write(priv, REG_DDC_ADDR, 0xa0);
1233325ba852SDmitry Baryshkov 	reg_write(priv, REG_DDC_OFFS, offset);
1234325ba852SDmitry Baryshkov 	reg_write(priv, REG_DDC_SEGM_ADDR, 0x60);
1235325ba852SDmitry Baryshkov 	reg_write(priv, REG_DDC_SEGM, segptr);
1236325ba852SDmitry Baryshkov 
1237325ba852SDmitry Baryshkov 	/* enable reading EDID: */
1238325ba852SDmitry Baryshkov 	priv->wq_edid_wait = 1;
1239325ba852SDmitry Baryshkov 	reg_write(priv, REG_EDID_CTRL, 0x1);
1240325ba852SDmitry Baryshkov 
1241325ba852SDmitry Baryshkov 	/* flag must be cleared by sw: */
1242325ba852SDmitry Baryshkov 	reg_write(priv, REG_EDID_CTRL, 0x0);
1243325ba852SDmitry Baryshkov 
1244325ba852SDmitry Baryshkov 	/* wait for block read to complete: */
1245325ba852SDmitry Baryshkov 	if (priv->hdmi->irq) {
1246325ba852SDmitry Baryshkov 		i = wait_event_timeout(priv->wq_edid,
1247325ba852SDmitry Baryshkov 					!priv->wq_edid_wait,
1248325ba852SDmitry Baryshkov 					msecs_to_jiffies(100));
1249325ba852SDmitry Baryshkov 		if (i < 0) {
1250325ba852SDmitry Baryshkov 			dev_err(&priv->hdmi->dev, "read edid wait err %d\n", i);
1251325ba852SDmitry Baryshkov 			ret = i;
1252325ba852SDmitry Baryshkov 			goto failed;
1253325ba852SDmitry Baryshkov 		}
1254325ba852SDmitry Baryshkov 	} else {
1255325ba852SDmitry Baryshkov 		for (i = 100; i > 0; i--) {
1256325ba852SDmitry Baryshkov 			msleep(1);
1257325ba852SDmitry Baryshkov 			ret = reg_read(priv, REG_INT_FLAGS_2);
1258325ba852SDmitry Baryshkov 			if (ret < 0)
1259325ba852SDmitry Baryshkov 				goto failed;
1260325ba852SDmitry Baryshkov 			if (ret & INT_FLAGS_2_EDID_BLK_RD)
1261325ba852SDmitry Baryshkov 				break;
1262325ba852SDmitry Baryshkov 		}
1263325ba852SDmitry Baryshkov 	}
1264325ba852SDmitry Baryshkov 
1265325ba852SDmitry Baryshkov 	if (i == 0) {
1266325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev, "read edid timeout\n");
1267325ba852SDmitry Baryshkov 		ret = -ETIMEDOUT;
1268325ba852SDmitry Baryshkov 		goto failed;
1269325ba852SDmitry Baryshkov 	}
1270325ba852SDmitry Baryshkov 
1271325ba852SDmitry Baryshkov 	ret = reg_read_range(priv, REG_EDID_DATA_0, buf, length);
1272325ba852SDmitry Baryshkov 	if (ret != length) {
1273325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev, "failed to read edid block %d: %d\n",
1274325ba852SDmitry Baryshkov 			blk, ret);
1275325ba852SDmitry Baryshkov 		goto failed;
1276325ba852SDmitry Baryshkov 	}
1277325ba852SDmitry Baryshkov 
1278325ba852SDmitry Baryshkov 	ret = 0;
1279325ba852SDmitry Baryshkov 
1280325ba852SDmitry Baryshkov  failed:
1281325ba852SDmitry Baryshkov 	mutex_unlock(&priv->edid_mutex);
1282325ba852SDmitry Baryshkov 	return ret;
1283325ba852SDmitry Baryshkov }
1284325ba852SDmitry Baryshkov 
tda998x_connector_get_modes(struct drm_connector * connector)1285325ba852SDmitry Baryshkov static int tda998x_connector_get_modes(struct drm_connector *connector)
1286325ba852SDmitry Baryshkov {
1287325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
1288325ba852SDmitry Baryshkov 	const struct drm_edid *drm_edid;
1289325ba852SDmitry Baryshkov 	int n;
1290325ba852SDmitry Baryshkov 
1291325ba852SDmitry Baryshkov 	/*
1292325ba852SDmitry Baryshkov 	 * If we get killed while waiting for the HPD timeout, return
1293325ba852SDmitry Baryshkov 	 * no modes found: we are not in a restartable path, so we
1294325ba852SDmitry Baryshkov 	 * can't handle signals gracefully.
1295325ba852SDmitry Baryshkov 	 */
1296325ba852SDmitry Baryshkov 	if (tda998x_edid_delay_wait(priv))
1297325ba852SDmitry Baryshkov 		return 0;
1298325ba852SDmitry Baryshkov 
1299325ba852SDmitry Baryshkov 	if (priv->rev == TDA19988)
1300325ba852SDmitry Baryshkov 		reg_clear(priv, REG_TX4, TX4_PD_RAM);
1301325ba852SDmitry Baryshkov 
1302325ba852SDmitry Baryshkov 	drm_edid = drm_edid_read_custom(connector, read_edid_block, priv);
1303325ba852SDmitry Baryshkov 
1304325ba852SDmitry Baryshkov 	if (priv->rev == TDA19988)
1305325ba852SDmitry Baryshkov 		reg_set(priv, REG_TX4, TX4_PD_RAM);
1306325ba852SDmitry Baryshkov 
1307325ba852SDmitry Baryshkov 	drm_edid_connector_update(connector, drm_edid);
1308325ba852SDmitry Baryshkov 	cec_notifier_set_phys_addr(priv->cec_notify,
1309325ba852SDmitry Baryshkov 				   connector->display_info.source_physical_address);
1310325ba852SDmitry Baryshkov 
1311325ba852SDmitry Baryshkov 	if (!drm_edid) {
1312325ba852SDmitry Baryshkov 		dev_warn(&priv->hdmi->dev, "failed to read EDID\n");
1313325ba852SDmitry Baryshkov 		return 0;
1314325ba852SDmitry Baryshkov 	}
1315325ba852SDmitry Baryshkov 
1316325ba852SDmitry Baryshkov 	mutex_lock(&priv->audio_mutex);
1317325ba852SDmitry Baryshkov 	n = drm_edid_connector_add_modes(connector);
1318325ba852SDmitry Baryshkov 	priv->sink_has_audio = connector->display_info.has_audio;
1319325ba852SDmitry Baryshkov 	mutex_unlock(&priv->audio_mutex);
1320325ba852SDmitry Baryshkov 
1321325ba852SDmitry Baryshkov 	drm_edid_free(drm_edid);
1322325ba852SDmitry Baryshkov 
1323325ba852SDmitry Baryshkov 	return n;
1324325ba852SDmitry Baryshkov }
1325325ba852SDmitry Baryshkov 
1326325ba852SDmitry Baryshkov static struct drm_encoder *
tda998x_connector_best_encoder(struct drm_connector * connector)1327325ba852SDmitry Baryshkov tda998x_connector_best_encoder(struct drm_connector *connector)
1328325ba852SDmitry Baryshkov {
1329325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
1330325ba852SDmitry Baryshkov 
1331325ba852SDmitry Baryshkov 	return priv->bridge.encoder;
1332325ba852SDmitry Baryshkov }
1333325ba852SDmitry Baryshkov 
1334325ba852SDmitry Baryshkov static
1335325ba852SDmitry Baryshkov const struct drm_connector_helper_funcs tda998x_connector_helper_funcs = {
1336325ba852SDmitry Baryshkov 	.get_modes = tda998x_connector_get_modes,
1337325ba852SDmitry Baryshkov 	.best_encoder = tda998x_connector_best_encoder,
1338325ba852SDmitry Baryshkov };
1339325ba852SDmitry Baryshkov 
tda998x_connector_init(struct tda998x_priv * priv,struct drm_device * drm)1340325ba852SDmitry Baryshkov static int tda998x_connector_init(struct tda998x_priv *priv,
1341325ba852SDmitry Baryshkov 				  struct drm_device *drm)
1342325ba852SDmitry Baryshkov {
1343325ba852SDmitry Baryshkov 	struct drm_connector *connector = &priv->connector;
1344325ba852SDmitry Baryshkov 	int ret;
1345325ba852SDmitry Baryshkov 
1346325ba852SDmitry Baryshkov 	connector->interlace_allowed = 1;
1347325ba852SDmitry Baryshkov 
1348325ba852SDmitry Baryshkov 	if (priv->hdmi->irq)
1349325ba852SDmitry Baryshkov 		connector->polled = DRM_CONNECTOR_POLL_HPD;
1350325ba852SDmitry Baryshkov 	else
1351325ba852SDmitry Baryshkov 		connector->polled = DRM_CONNECTOR_POLL_CONNECT |
1352325ba852SDmitry Baryshkov 			DRM_CONNECTOR_POLL_DISCONNECT;
1353325ba852SDmitry Baryshkov 
1354325ba852SDmitry Baryshkov 	drm_connector_helper_add(connector, &tda998x_connector_helper_funcs);
1355325ba852SDmitry Baryshkov 	ret = drm_connector_init(drm, connector, &tda998x_connector_funcs,
1356325ba852SDmitry Baryshkov 				 DRM_MODE_CONNECTOR_HDMIA);
1357325ba852SDmitry Baryshkov 	if (ret)
1358325ba852SDmitry Baryshkov 		return ret;
1359325ba852SDmitry Baryshkov 
1360325ba852SDmitry Baryshkov 	drm_connector_attach_encoder(&priv->connector,
1361325ba852SDmitry Baryshkov 				     priv->bridge.encoder);
1362325ba852SDmitry Baryshkov 
1363325ba852SDmitry Baryshkov 	return 0;
1364325ba852SDmitry Baryshkov }
1365325ba852SDmitry Baryshkov 
1366325ba852SDmitry Baryshkov /* DRM bridge functions */
1367325ba852SDmitry Baryshkov 
tda998x_bridge_attach(struct drm_bridge * bridge,struct drm_encoder * encoder,enum drm_bridge_attach_flags flags)1368325ba852SDmitry Baryshkov static int tda998x_bridge_attach(struct drm_bridge *bridge,
136998007a0dSMaxime Ripard 				 struct drm_encoder *encoder,
1370325ba852SDmitry Baryshkov 				 enum drm_bridge_attach_flags flags)
1371325ba852SDmitry Baryshkov {
1372325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
1373325ba852SDmitry Baryshkov 
1374325ba852SDmitry Baryshkov 	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
1375325ba852SDmitry Baryshkov 		DRM_ERROR("Fix bridge driver to make connector optional!");
1376325ba852SDmitry Baryshkov 		return -EINVAL;
1377325ba852SDmitry Baryshkov 	}
1378325ba852SDmitry Baryshkov 
1379325ba852SDmitry Baryshkov 	return tda998x_connector_init(priv, bridge->dev);
1380325ba852SDmitry Baryshkov }
1381325ba852SDmitry Baryshkov 
tda998x_bridge_detach(struct drm_bridge * bridge)1382325ba852SDmitry Baryshkov static void tda998x_bridge_detach(struct drm_bridge *bridge)
1383325ba852SDmitry Baryshkov {
1384325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
1385325ba852SDmitry Baryshkov 
1386325ba852SDmitry Baryshkov 	drm_connector_cleanup(&priv->connector);
1387325ba852SDmitry Baryshkov }
1388325ba852SDmitry Baryshkov 
tda998x_bridge_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * info,const struct drm_display_mode * mode)1389325ba852SDmitry Baryshkov static enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge,
1390325ba852SDmitry Baryshkov 				     const struct drm_display_info *info,
1391325ba852SDmitry Baryshkov 				     const struct drm_display_mode *mode)
1392325ba852SDmitry Baryshkov {
1393325ba852SDmitry Baryshkov 	/* TDA19988 dotclock can go up to 165MHz */
1394325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
1395325ba852SDmitry Baryshkov 
1396325ba852SDmitry Baryshkov 	if (mode->clock > ((priv->rev == TDA19988) ? 165000 : 150000))
1397325ba852SDmitry Baryshkov 		return MODE_CLOCK_HIGH;
1398325ba852SDmitry Baryshkov 	if (mode->htotal >= BIT(13))
1399325ba852SDmitry Baryshkov 		return MODE_BAD_HVALUE;
1400325ba852SDmitry Baryshkov 	if (mode->vtotal >= BIT(11))
1401325ba852SDmitry Baryshkov 		return MODE_BAD_VVALUE;
1402325ba852SDmitry Baryshkov 	return MODE_OK;
1403325ba852SDmitry Baryshkov }
1404325ba852SDmitry Baryshkov 
tda998x_bridge_enable(struct drm_bridge * bridge)1405325ba852SDmitry Baryshkov static void tda998x_bridge_enable(struct drm_bridge *bridge)
1406325ba852SDmitry Baryshkov {
1407325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
1408325ba852SDmitry Baryshkov 
1409325ba852SDmitry Baryshkov 	if (!priv->is_on) {
1410325ba852SDmitry Baryshkov 		/* enable video ports, audio will be enabled later */
1411325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENA_VP_0, 0xff);
1412325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENA_VP_1, 0xff);
1413325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENA_VP_2, 0xff);
1414325ba852SDmitry Baryshkov 		/* set muxing after enabling ports: */
1415325ba852SDmitry Baryshkov 		reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
1416325ba852SDmitry Baryshkov 		reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
1417325ba852SDmitry Baryshkov 		reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
1418325ba852SDmitry Baryshkov 
1419325ba852SDmitry Baryshkov 		priv->is_on = true;
1420325ba852SDmitry Baryshkov 	}
1421325ba852SDmitry Baryshkov }
1422325ba852SDmitry Baryshkov 
tda998x_bridge_disable(struct drm_bridge * bridge)1423325ba852SDmitry Baryshkov static void tda998x_bridge_disable(struct drm_bridge *bridge)
1424325ba852SDmitry Baryshkov {
1425325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
1426325ba852SDmitry Baryshkov 
1427325ba852SDmitry Baryshkov 	if (priv->is_on) {
1428325ba852SDmitry Baryshkov 		/* disable video ports */
1429325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENA_VP_0, 0x00);
1430325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENA_VP_1, 0x00);
1431325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENA_VP_2, 0x00);
1432325ba852SDmitry Baryshkov 
1433325ba852SDmitry Baryshkov 		priv->is_on = false;
1434325ba852SDmitry Baryshkov 	}
1435325ba852SDmitry Baryshkov }
1436325ba852SDmitry Baryshkov 
tda998x_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)1437325ba852SDmitry Baryshkov static void tda998x_bridge_mode_set(struct drm_bridge *bridge,
1438325ba852SDmitry Baryshkov 				    const struct drm_display_mode *mode,
1439325ba852SDmitry Baryshkov 				    const struct drm_display_mode *adjusted_mode)
1440325ba852SDmitry Baryshkov {
1441325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
1442325ba852SDmitry Baryshkov 	unsigned long tmds_clock;
1443325ba852SDmitry Baryshkov 	u16 ref_pix, ref_line, n_pix, n_line;
1444325ba852SDmitry Baryshkov 	u16 hs_pix_s, hs_pix_e;
1445325ba852SDmitry Baryshkov 	u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e;
1446325ba852SDmitry Baryshkov 	u16 vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e;
1447325ba852SDmitry Baryshkov 	u16 vwin1_line_s, vwin1_line_e;
1448325ba852SDmitry Baryshkov 	u16 vwin2_line_s, vwin2_line_e;
1449325ba852SDmitry Baryshkov 	u16 de_pix_s, de_pix_e;
1450325ba852SDmitry Baryshkov 	u8 reg, div, rep, sel_clk;
1451325ba852SDmitry Baryshkov 
1452325ba852SDmitry Baryshkov 	/*
1453325ba852SDmitry Baryshkov 	 * Since we are "computer" like, our source invariably produces
1454325ba852SDmitry Baryshkov 	 * full-range RGB.  If the monitor supports full-range, then use
1455325ba852SDmitry Baryshkov 	 * it, otherwise reduce to limited-range.
1456325ba852SDmitry Baryshkov 	 */
1457325ba852SDmitry Baryshkov 	priv->rgb_quant_range =
1458325ba852SDmitry Baryshkov 		priv->connector.display_info.rgb_quant_range_selectable ?
1459325ba852SDmitry Baryshkov 		HDMI_QUANTIZATION_RANGE_FULL :
1460325ba852SDmitry Baryshkov 		drm_default_rgb_quant_range(adjusted_mode);
1461325ba852SDmitry Baryshkov 
1462325ba852SDmitry Baryshkov 	/*
1463325ba852SDmitry Baryshkov 	 * Internally TDA998x is using ITU-R BT.656 style sync but
1464325ba852SDmitry Baryshkov 	 * we get VESA style sync. TDA998x is using a reference pixel
1465325ba852SDmitry Baryshkov 	 * relative to ITU to sync to the input frame and for output
1466325ba852SDmitry Baryshkov 	 * sync generation. Currently, we are using reference detection
1467325ba852SDmitry Baryshkov 	 * from HS/VS, i.e. REFPIX/REFLINE denote frame start sync point
1468325ba852SDmitry Baryshkov 	 * which is position of rising VS with coincident rising HS.
1469325ba852SDmitry Baryshkov 	 *
1470325ba852SDmitry Baryshkov 	 * Now there is some issues to take care of:
1471325ba852SDmitry Baryshkov 	 * - HDMI data islands require sync-before-active
1472325ba852SDmitry Baryshkov 	 * - TDA998x register values must be > 0 to be enabled
1473325ba852SDmitry Baryshkov 	 * - REFLINE needs an additional offset of +1
1474325ba852SDmitry Baryshkov 	 * - REFPIX needs an addtional offset of +1 for UYUV and +3 for RGB
1475325ba852SDmitry Baryshkov 	 *
1476325ba852SDmitry Baryshkov 	 * So we add +1 to all horizontal and vertical register values,
1477325ba852SDmitry Baryshkov 	 * plus an additional +3 for REFPIX as we are using RGB input only.
1478325ba852SDmitry Baryshkov 	 */
1479325ba852SDmitry Baryshkov 	n_pix        = mode->htotal;
1480325ba852SDmitry Baryshkov 	n_line       = mode->vtotal;
1481325ba852SDmitry Baryshkov 
1482325ba852SDmitry Baryshkov 	hs_pix_e     = mode->hsync_end - mode->hdisplay;
1483325ba852SDmitry Baryshkov 	hs_pix_s     = mode->hsync_start - mode->hdisplay;
1484325ba852SDmitry Baryshkov 	de_pix_e     = mode->htotal;
1485325ba852SDmitry Baryshkov 	de_pix_s     = mode->htotal - mode->hdisplay;
1486325ba852SDmitry Baryshkov 	ref_pix      = 3 + hs_pix_s;
1487325ba852SDmitry Baryshkov 
1488325ba852SDmitry Baryshkov 	/*
1489325ba852SDmitry Baryshkov 	 * Attached LCD controllers may generate broken sync. Allow
1490325ba852SDmitry Baryshkov 	 * those to adjust the position of the rising VS edge by adding
1491325ba852SDmitry Baryshkov 	 * HSKEW to ref_pix.
1492325ba852SDmitry Baryshkov 	 */
1493325ba852SDmitry Baryshkov 	if (adjusted_mode->flags & DRM_MODE_FLAG_HSKEW)
1494325ba852SDmitry Baryshkov 		ref_pix += adjusted_mode->hskew;
1495325ba852SDmitry Baryshkov 
1496325ba852SDmitry Baryshkov 	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0) {
1497325ba852SDmitry Baryshkov 		ref_line     = 1 + mode->vsync_start - mode->vdisplay;
1498325ba852SDmitry Baryshkov 		vwin1_line_s = mode->vtotal - mode->vdisplay - 1;
1499325ba852SDmitry Baryshkov 		vwin1_line_e = vwin1_line_s + mode->vdisplay;
1500325ba852SDmitry Baryshkov 		vs1_pix_s    = vs1_pix_e = hs_pix_s;
1501325ba852SDmitry Baryshkov 		vs1_line_s   = mode->vsync_start - mode->vdisplay;
1502325ba852SDmitry Baryshkov 		vs1_line_e   = vs1_line_s +
1503325ba852SDmitry Baryshkov 			       mode->vsync_end - mode->vsync_start;
1504325ba852SDmitry Baryshkov 		vwin2_line_s = vwin2_line_e = 0;
1505325ba852SDmitry Baryshkov 		vs2_pix_s    = vs2_pix_e  = 0;
1506325ba852SDmitry Baryshkov 		vs2_line_s   = vs2_line_e = 0;
1507325ba852SDmitry Baryshkov 	} else {
1508325ba852SDmitry Baryshkov 		ref_line     = 1 + (mode->vsync_start - mode->vdisplay)/2;
1509325ba852SDmitry Baryshkov 		vwin1_line_s = (mode->vtotal - mode->vdisplay)/2;
1510325ba852SDmitry Baryshkov 		vwin1_line_e = vwin1_line_s + mode->vdisplay/2;
1511325ba852SDmitry Baryshkov 		vs1_pix_s    = vs1_pix_e = hs_pix_s;
1512325ba852SDmitry Baryshkov 		vs1_line_s   = (mode->vsync_start - mode->vdisplay)/2;
1513325ba852SDmitry Baryshkov 		vs1_line_e   = vs1_line_s +
1514325ba852SDmitry Baryshkov 			       (mode->vsync_end - mode->vsync_start)/2;
1515325ba852SDmitry Baryshkov 		vwin2_line_s = vwin1_line_s + mode->vtotal/2;
1516325ba852SDmitry Baryshkov 		vwin2_line_e = vwin2_line_s + mode->vdisplay/2;
1517325ba852SDmitry Baryshkov 		vs2_pix_s    = vs2_pix_e = hs_pix_s + mode->htotal/2;
1518325ba852SDmitry Baryshkov 		vs2_line_s   = vs1_line_s + mode->vtotal/2 ;
1519325ba852SDmitry Baryshkov 		vs2_line_e   = vs2_line_s +
1520325ba852SDmitry Baryshkov 			       (mode->vsync_end - mode->vsync_start)/2;
1521325ba852SDmitry Baryshkov 	}
1522325ba852SDmitry Baryshkov 
1523325ba852SDmitry Baryshkov 	/*
1524325ba852SDmitry Baryshkov 	 * Select pixel repeat depending on the double-clock flag
1525325ba852SDmitry Baryshkov 	 * (which means we have to repeat each pixel once.)
1526325ba852SDmitry Baryshkov 	 */
1527325ba852SDmitry Baryshkov 	rep = mode->flags & DRM_MODE_FLAG_DBLCLK ? 1 : 0;
1528325ba852SDmitry Baryshkov 	sel_clk = SEL_CLK_ENA_SC_CLK | SEL_CLK_SEL_CLK1 |
1529325ba852SDmitry Baryshkov 		  SEL_CLK_SEL_VRF_CLK(rep ? 2 : 0);
1530325ba852SDmitry Baryshkov 
1531325ba852SDmitry Baryshkov 	/* the TMDS clock is scaled up by the pixel repeat */
1532325ba852SDmitry Baryshkov 	tmds_clock = mode->clock * (1 + rep);
1533325ba852SDmitry Baryshkov 
1534325ba852SDmitry Baryshkov 	/*
1535325ba852SDmitry Baryshkov 	 * The divisor is power-of-2. The TDA9983B datasheet gives
1536325ba852SDmitry Baryshkov 	 * this as ranges of Msample/s, which is 10x the TMDS clock:
1537325ba852SDmitry Baryshkov 	 *   0 - 800 to 1500 Msample/s
1538325ba852SDmitry Baryshkov 	 *   1 - 400 to 800 Msample/s
1539325ba852SDmitry Baryshkov 	 *   2 - 200 to 400 Msample/s
1540325ba852SDmitry Baryshkov 	 *   3 - as 2 above
1541325ba852SDmitry Baryshkov 	 */
1542325ba852SDmitry Baryshkov 	for (div = 0; div < 3; div++)
1543325ba852SDmitry Baryshkov 		if (80000 >> div <= tmds_clock)
1544325ba852SDmitry Baryshkov 			break;
1545325ba852SDmitry Baryshkov 
1546325ba852SDmitry Baryshkov 	mutex_lock(&priv->audio_mutex);
1547325ba852SDmitry Baryshkov 
1548325ba852SDmitry Baryshkov 	priv->tmds_clock = tmds_clock;
1549325ba852SDmitry Baryshkov 
1550325ba852SDmitry Baryshkov 	/* mute the audio FIFO: */
1551325ba852SDmitry Baryshkov 	reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
1552325ba852SDmitry Baryshkov 
1553325ba852SDmitry Baryshkov 	/* set HDMI HDCP mode off: */
1554325ba852SDmitry Baryshkov 	reg_write(priv, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
1555325ba852SDmitry Baryshkov 	reg_clear(priv, REG_TX33, TX33_HDMI);
1556325ba852SDmitry Baryshkov 	reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(0));
1557325ba852SDmitry Baryshkov 
1558325ba852SDmitry Baryshkov 	/* no pre-filter or interpolator: */
1559325ba852SDmitry Baryshkov 	reg_write(priv, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) |
1560325ba852SDmitry Baryshkov 			HVF_CNTRL_0_INTPOL(0));
1561325ba852SDmitry Baryshkov 	reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_PREFILT);
1562325ba852SDmitry Baryshkov 	reg_write(priv, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
1563325ba852SDmitry Baryshkov 	reg_write(priv, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) |
1564325ba852SDmitry Baryshkov 			VIP_CNTRL_4_BLC(0));
1565325ba852SDmitry Baryshkov 
1566325ba852SDmitry Baryshkov 	reg_clear(priv, REG_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IZ);
1567325ba852SDmitry Baryshkov 	reg_clear(priv, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR |
1568325ba852SDmitry Baryshkov 					  PLL_SERIAL_3_SRL_DE);
1569325ba852SDmitry Baryshkov 	reg_write(priv, REG_SERIALIZER, 0);
1570325ba852SDmitry Baryshkov 	reg_write(priv, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR(0));
1571325ba852SDmitry Baryshkov 
1572325ba852SDmitry Baryshkov 	reg_write(priv, REG_RPT_CNTRL, RPT_CNTRL_REPEAT(rep));
1573325ba852SDmitry Baryshkov 	reg_write(priv, REG_SEL_CLK, sel_clk);
1574325ba852SDmitry Baryshkov 	reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
1575325ba852SDmitry Baryshkov 			PLL_SERIAL_2_SRL_PR(rep));
1576325ba852SDmitry Baryshkov 
1577325ba852SDmitry Baryshkov 	/* set color matrix according to output rgb quant range */
1578325ba852SDmitry Baryshkov 	if (priv->rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) {
1579325ba852SDmitry Baryshkov 		static u8 tda998x_full_to_limited_range[] = {
1580325ba852SDmitry Baryshkov 			MAT_CONTRL_MAT_SC(2),
1581325ba852SDmitry Baryshkov 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1582325ba852SDmitry Baryshkov 			0x03, 0x6f, 0x00, 0x00, 0x00, 0x00,
1583325ba852SDmitry Baryshkov 			0x00, 0x00, 0x03, 0x6f, 0x00, 0x00,
1584325ba852SDmitry Baryshkov 			0x00, 0x00, 0x00, 0x00, 0x03, 0x6f,
1585325ba852SDmitry Baryshkov 			0x00, 0x40, 0x00, 0x40, 0x00, 0x40
1586325ba852SDmitry Baryshkov 		};
1587325ba852SDmitry Baryshkov 		reg_clear(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);
1588325ba852SDmitry Baryshkov 		reg_write_range(priv, REG_MAT_CONTRL,
1589325ba852SDmitry Baryshkov 				tda998x_full_to_limited_range,
1590325ba852SDmitry Baryshkov 				sizeof(tda998x_full_to_limited_range));
1591325ba852SDmitry Baryshkov 	} else {
1592325ba852SDmitry Baryshkov 		reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP |
1593325ba852SDmitry Baryshkov 					MAT_CONTRL_MAT_SC(1));
1594325ba852SDmitry Baryshkov 		reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC);
1595325ba852SDmitry Baryshkov 	}
1596325ba852SDmitry Baryshkov 
1597325ba852SDmitry Baryshkov 	/* set BIAS tmds value: */
1598325ba852SDmitry Baryshkov 	reg_write(priv, REG_ANA_GENERAL, 0x09);
1599325ba852SDmitry Baryshkov 
1600325ba852SDmitry Baryshkov 	/*
1601325ba852SDmitry Baryshkov 	 * Sync on rising HSYNC/VSYNC
1602325ba852SDmitry Baryshkov 	 */
1603325ba852SDmitry Baryshkov 	reg = VIP_CNTRL_3_SYNC_HS;
1604325ba852SDmitry Baryshkov 
1605325ba852SDmitry Baryshkov 	/*
1606325ba852SDmitry Baryshkov 	 * TDA19988 requires high-active sync at input stage,
1607325ba852SDmitry Baryshkov 	 * so invert low-active sync provided by master encoder here
1608325ba852SDmitry Baryshkov 	 */
1609325ba852SDmitry Baryshkov 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1610325ba852SDmitry Baryshkov 		reg |= VIP_CNTRL_3_H_TGL;
1611325ba852SDmitry Baryshkov 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1612325ba852SDmitry Baryshkov 		reg |= VIP_CNTRL_3_V_TGL;
1613325ba852SDmitry Baryshkov 	reg_write(priv, REG_VIP_CNTRL_3, reg);
1614325ba852SDmitry Baryshkov 
1615325ba852SDmitry Baryshkov 	reg_write(priv, REG_VIDFORMAT, 0x00);
1616325ba852SDmitry Baryshkov 	reg_write16(priv, REG_REFPIX_MSB, ref_pix);
1617325ba852SDmitry Baryshkov 	reg_write16(priv, REG_REFLINE_MSB, ref_line);
1618325ba852SDmitry Baryshkov 	reg_write16(priv, REG_NPIX_MSB, n_pix);
1619325ba852SDmitry Baryshkov 	reg_write16(priv, REG_NLINE_MSB, n_line);
1620325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_LINE_STRT_1_MSB, vs1_line_s);
1621325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_PIX_STRT_1_MSB, vs1_pix_s);
1622325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_LINE_END_1_MSB, vs1_line_e);
1623325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_PIX_END_1_MSB, vs1_pix_e);
1624325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_LINE_STRT_2_MSB, vs2_line_s);
1625325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_PIX_STRT_2_MSB, vs2_pix_s);
1626325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_LINE_END_2_MSB, vs2_line_e);
1627325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VS_PIX_END_2_MSB, vs2_pix_e);
1628325ba852SDmitry Baryshkov 	reg_write16(priv, REG_HS_PIX_START_MSB, hs_pix_s);
1629325ba852SDmitry Baryshkov 	reg_write16(priv, REG_HS_PIX_STOP_MSB, hs_pix_e);
1630325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VWIN_START_1_MSB, vwin1_line_s);
1631325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VWIN_END_1_MSB, vwin1_line_e);
1632325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VWIN_START_2_MSB, vwin2_line_s);
1633325ba852SDmitry Baryshkov 	reg_write16(priv, REG_VWIN_END_2_MSB, vwin2_line_e);
1634325ba852SDmitry Baryshkov 	reg_write16(priv, REG_DE_START_MSB, de_pix_s);
1635325ba852SDmitry Baryshkov 	reg_write16(priv, REG_DE_STOP_MSB, de_pix_e);
1636325ba852SDmitry Baryshkov 
1637325ba852SDmitry Baryshkov 	if (priv->rev == TDA19988) {
1638325ba852SDmitry Baryshkov 		/* let incoming pixels fill the active space (if any) */
1639325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENABLE_SPACE, 0x00);
1640325ba852SDmitry Baryshkov 	}
1641325ba852SDmitry Baryshkov 
1642325ba852SDmitry Baryshkov 	/*
1643325ba852SDmitry Baryshkov 	 * Always generate sync polarity relative to input sync and
1644325ba852SDmitry Baryshkov 	 * revert input stage toggled sync at output stage
1645325ba852SDmitry Baryshkov 	 */
1646325ba852SDmitry Baryshkov 	reg = TBG_CNTRL_1_DWIN_DIS | TBG_CNTRL_1_TGL_EN;
1647325ba852SDmitry Baryshkov 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
1648325ba852SDmitry Baryshkov 		reg |= TBG_CNTRL_1_H_TGL;
1649325ba852SDmitry Baryshkov 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
1650325ba852SDmitry Baryshkov 		reg |= TBG_CNTRL_1_V_TGL;
1651325ba852SDmitry Baryshkov 	reg_write(priv, REG_TBG_CNTRL_1, reg);
1652325ba852SDmitry Baryshkov 
1653325ba852SDmitry Baryshkov 	/* must be last register set: */
1654325ba852SDmitry Baryshkov 	reg_write(priv, REG_TBG_CNTRL_0, 0);
1655325ba852SDmitry Baryshkov 
1656325ba852SDmitry Baryshkov 	/* CEA-861B section 6 says that:
1657325ba852SDmitry Baryshkov 	 * CEA version 1 (CEA-861) has no support for infoframes.
1658325ba852SDmitry Baryshkov 	 * CEA version 2 (CEA-861A) supports version 1 AVI infoframes,
1659325ba852SDmitry Baryshkov 	 * and optional basic audio.
1660325ba852SDmitry Baryshkov 	 * CEA version 3 (CEA-861B) supports version 1 and 2 AVI infoframes,
1661325ba852SDmitry Baryshkov 	 * and optional digital audio, with audio infoframes.
1662325ba852SDmitry Baryshkov 	 *
1663325ba852SDmitry Baryshkov 	 * Since we only support generation of version 2 AVI infoframes,
1664325ba852SDmitry Baryshkov 	 * ignore CEA version 2 and below (iow, behave as if we're a
1665325ba852SDmitry Baryshkov 	 * CEA-861 source.)
1666325ba852SDmitry Baryshkov 	 */
1667325ba852SDmitry Baryshkov 	priv->supports_infoframes = priv->connector.display_info.cea_rev >= 3;
1668325ba852SDmitry Baryshkov 
1669325ba852SDmitry Baryshkov 	if (priv->supports_infoframes) {
1670325ba852SDmitry Baryshkov 		/* We need to turn HDMI HDCP stuff on to get audio through */
1671325ba852SDmitry Baryshkov 		reg &= ~TBG_CNTRL_1_DWIN_DIS;
1672325ba852SDmitry Baryshkov 		reg_write(priv, REG_TBG_CNTRL_1, reg);
1673325ba852SDmitry Baryshkov 		reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(1));
1674325ba852SDmitry Baryshkov 		reg_set(priv, REG_TX33, TX33_HDMI);
1675325ba852SDmitry Baryshkov 
1676325ba852SDmitry Baryshkov 		tda998x_write_avi(priv, adjusted_mode);
1677325ba852SDmitry Baryshkov 		tda998x_write_vsi(priv, adjusted_mode);
1678325ba852SDmitry Baryshkov 
1679325ba852SDmitry Baryshkov 		if (priv->sink_has_audio)
1680325ba852SDmitry Baryshkov 			tda998x_configure_audio(priv);
1681325ba852SDmitry Baryshkov 	}
1682325ba852SDmitry Baryshkov 
1683325ba852SDmitry Baryshkov 	mutex_unlock(&priv->audio_mutex);
1684325ba852SDmitry Baryshkov }
1685325ba852SDmitry Baryshkov 
1686325ba852SDmitry Baryshkov static const struct drm_bridge_funcs tda998x_bridge_funcs = {
1687325ba852SDmitry Baryshkov 	.attach = tda998x_bridge_attach,
1688325ba852SDmitry Baryshkov 	.detach = tda998x_bridge_detach,
1689325ba852SDmitry Baryshkov 	.mode_valid = tda998x_bridge_mode_valid,
1690325ba852SDmitry Baryshkov 	.disable = tda998x_bridge_disable,
1691325ba852SDmitry Baryshkov 	.mode_set = tda998x_bridge_mode_set,
1692325ba852SDmitry Baryshkov 	.enable = tda998x_bridge_enable,
1693325ba852SDmitry Baryshkov };
1694325ba852SDmitry Baryshkov 
1695325ba852SDmitry Baryshkov /* I2C driver functions */
1696325ba852SDmitry Baryshkov 
tda998x_get_audio_ports(struct tda998x_priv * priv,struct device_node * np)1697325ba852SDmitry Baryshkov static int tda998x_get_audio_ports(struct tda998x_priv *priv,
1698325ba852SDmitry Baryshkov 				   struct device_node *np)
1699325ba852SDmitry Baryshkov {
1700325ba852SDmitry Baryshkov 	const u32 *port_data;
1701325ba852SDmitry Baryshkov 	u32 size;
1702325ba852SDmitry Baryshkov 	int i;
1703325ba852SDmitry Baryshkov 
1704325ba852SDmitry Baryshkov 	port_data = of_get_property(np, "audio-ports", &size);
1705325ba852SDmitry Baryshkov 	if (!port_data)
1706325ba852SDmitry Baryshkov 		return 0;
1707325ba852SDmitry Baryshkov 
1708325ba852SDmitry Baryshkov 	size /= sizeof(u32);
1709325ba852SDmitry Baryshkov 	if (size > 2 * ARRAY_SIZE(priv->audio_port_enable) || size % 2 != 0) {
1710325ba852SDmitry Baryshkov 		dev_err(&priv->hdmi->dev,
1711325ba852SDmitry Baryshkov 			"Bad number of elements in audio-ports dt-property\n");
1712325ba852SDmitry Baryshkov 		return -EINVAL;
1713325ba852SDmitry Baryshkov 	}
1714325ba852SDmitry Baryshkov 
1715325ba852SDmitry Baryshkov 	size /= 2;
1716325ba852SDmitry Baryshkov 
1717325ba852SDmitry Baryshkov 	for (i = 0; i < size; i++) {
1718325ba852SDmitry Baryshkov 		unsigned int route;
1719325ba852SDmitry Baryshkov 		u8 afmt = be32_to_cpup(&port_data[2*i]);
1720325ba852SDmitry Baryshkov 		u8 ena_ap = be32_to_cpup(&port_data[2*i+1]);
1721325ba852SDmitry Baryshkov 
1722325ba852SDmitry Baryshkov 		switch (afmt) {
1723325ba852SDmitry Baryshkov 		case TDA998x_I2S:
1724325ba852SDmitry Baryshkov 			route = AUDIO_ROUTE_I2S;
1725325ba852SDmitry Baryshkov 			break;
1726325ba852SDmitry Baryshkov 		case TDA998x_SPDIF:
1727325ba852SDmitry Baryshkov 			route = AUDIO_ROUTE_SPDIF;
1728325ba852SDmitry Baryshkov 			break;
1729325ba852SDmitry Baryshkov 		default:
1730325ba852SDmitry Baryshkov 			dev_err(&priv->hdmi->dev,
1731325ba852SDmitry Baryshkov 				"Bad audio format %u\n", afmt);
1732325ba852SDmitry Baryshkov 			return -EINVAL;
1733325ba852SDmitry Baryshkov 		}
1734325ba852SDmitry Baryshkov 
1735325ba852SDmitry Baryshkov 		if (!ena_ap) {
1736325ba852SDmitry Baryshkov 			dev_err(&priv->hdmi->dev, "invalid zero port config\n");
1737325ba852SDmitry Baryshkov 			continue;
1738325ba852SDmitry Baryshkov 		}
1739325ba852SDmitry Baryshkov 
1740325ba852SDmitry Baryshkov 		if (priv->audio_port_enable[route]) {
1741325ba852SDmitry Baryshkov 			dev_err(&priv->hdmi->dev,
1742325ba852SDmitry Baryshkov 				"%s format already configured\n",
1743325ba852SDmitry Baryshkov 				route == AUDIO_ROUTE_SPDIF ? "SPDIF" : "I2S");
1744325ba852SDmitry Baryshkov 			return -EINVAL;
1745325ba852SDmitry Baryshkov 		}
1746325ba852SDmitry Baryshkov 
1747325ba852SDmitry Baryshkov 		priv->audio_port_enable[route] = ena_ap;
1748325ba852SDmitry Baryshkov 	}
1749325ba852SDmitry Baryshkov 	return 0;
1750325ba852SDmitry Baryshkov }
1751325ba852SDmitry Baryshkov 
tda998x_destroy(struct device * dev)1752325ba852SDmitry Baryshkov static void tda998x_destroy(struct device *dev)
1753325ba852SDmitry Baryshkov {
1754325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = dev_get_drvdata(dev);
1755325ba852SDmitry Baryshkov 
1756325ba852SDmitry Baryshkov 	drm_bridge_remove(&priv->bridge);
1757325ba852SDmitry Baryshkov 
1758325ba852SDmitry Baryshkov 	/* disable all IRQs and free the IRQ handler */
1759325ba852SDmitry Baryshkov 	cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
1760325ba852SDmitry Baryshkov 	reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
1761325ba852SDmitry Baryshkov 
1762325ba852SDmitry Baryshkov 	if (priv->audio_pdev)
1763325ba852SDmitry Baryshkov 		platform_device_unregister(priv->audio_pdev);
1764325ba852SDmitry Baryshkov 
1765325ba852SDmitry Baryshkov 	if (priv->hdmi->irq)
1766325ba852SDmitry Baryshkov 		free_irq(priv->hdmi->irq, priv);
1767325ba852SDmitry Baryshkov 
17688fa7292fSThomas Gleixner 	timer_delete_sync(&priv->edid_delay_timer);
1769325ba852SDmitry Baryshkov 	cancel_work_sync(&priv->detect_work);
1770325ba852SDmitry Baryshkov 
1771325ba852SDmitry Baryshkov 	i2c_unregister_device(priv->cec);
1772325ba852SDmitry Baryshkov 
1773325ba852SDmitry Baryshkov 	cec_notifier_conn_unregister(priv->cec_notify);
1774325ba852SDmitry Baryshkov }
1775325ba852SDmitry Baryshkov 
tda998x_create(struct device * dev)1776325ba852SDmitry Baryshkov static int tda998x_create(struct device *dev)
1777325ba852SDmitry Baryshkov {
1778325ba852SDmitry Baryshkov 	struct i2c_client *client = to_i2c_client(dev);
1779325ba852SDmitry Baryshkov 	struct device_node *np = client->dev.of_node;
1780325ba852SDmitry Baryshkov 	struct i2c_board_info cec_info;
1781325ba852SDmitry Baryshkov 	struct tda998x_priv *priv;
1782325ba852SDmitry Baryshkov 	u32 video;
1783325ba852SDmitry Baryshkov 	int rev_lo, rev_hi, ret;
1784325ba852SDmitry Baryshkov 
17857fe58bf1SLuca Ceresoli 	priv = devm_drm_bridge_alloc(dev, struct tda998x_priv, bridge, &tda998x_bridge_funcs);
17867fe58bf1SLuca Ceresoli 	if (IS_ERR(priv))
17877fe58bf1SLuca Ceresoli 		return PTR_ERR(priv);
1788325ba852SDmitry Baryshkov 
1789325ba852SDmitry Baryshkov 	dev_set_drvdata(dev, priv);
1790325ba852SDmitry Baryshkov 
1791325ba852SDmitry Baryshkov 	mutex_init(&priv->mutex);	/* protect the page access */
1792325ba852SDmitry Baryshkov 	mutex_init(&priv->audio_mutex); /* protect access from audio thread */
1793325ba852SDmitry Baryshkov 	mutex_init(&priv->edid_mutex);
1794325ba852SDmitry Baryshkov 	INIT_LIST_HEAD(&priv->bridge.list);
1795325ba852SDmitry Baryshkov 	init_waitqueue_head(&priv->edid_delay_waitq);
1796325ba852SDmitry Baryshkov 	timer_setup(&priv->edid_delay_timer, tda998x_edid_delay_done, 0);
1797325ba852SDmitry Baryshkov 	INIT_WORK(&priv->detect_work, tda998x_detect_work);
1798325ba852SDmitry Baryshkov 
1799325ba852SDmitry Baryshkov 	priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3);
1800325ba852SDmitry Baryshkov 	priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1);
1801325ba852SDmitry Baryshkov 	priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5);
1802325ba852SDmitry Baryshkov 
1803325ba852SDmitry Baryshkov 	/* CEC I2C address bound to TDA998x I2C addr by configuration pins */
1804325ba852SDmitry Baryshkov 	priv->cec_addr = 0x34 + (client->addr & 0x03);
1805325ba852SDmitry Baryshkov 	priv->current_page = 0xff;
1806325ba852SDmitry Baryshkov 	priv->hdmi = client;
1807325ba852SDmitry Baryshkov 
1808325ba852SDmitry Baryshkov 	/* wake up the device: */
1809325ba852SDmitry Baryshkov 	cec_write(priv, REG_CEC_ENAMODS,
1810325ba852SDmitry Baryshkov 			CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI);
1811325ba852SDmitry Baryshkov 
1812325ba852SDmitry Baryshkov 	tda998x_reset(priv);
1813325ba852SDmitry Baryshkov 
1814325ba852SDmitry Baryshkov 	/* read version: */
1815325ba852SDmitry Baryshkov 	rev_lo = reg_read(priv, REG_VERSION_LSB);
1816325ba852SDmitry Baryshkov 	if (rev_lo < 0) {
1817325ba852SDmitry Baryshkov 		dev_err(dev, "failed to read version: %d\n", rev_lo);
1818325ba852SDmitry Baryshkov 		return rev_lo;
1819325ba852SDmitry Baryshkov 	}
1820325ba852SDmitry Baryshkov 
1821325ba852SDmitry Baryshkov 	rev_hi = reg_read(priv, REG_VERSION_MSB);
1822325ba852SDmitry Baryshkov 	if (rev_hi < 0) {
1823325ba852SDmitry Baryshkov 		dev_err(dev, "failed to read version: %d\n", rev_hi);
1824325ba852SDmitry Baryshkov 		return rev_hi;
1825325ba852SDmitry Baryshkov 	}
1826325ba852SDmitry Baryshkov 
1827325ba852SDmitry Baryshkov 	priv->rev = rev_lo | rev_hi << 8;
1828325ba852SDmitry Baryshkov 
1829325ba852SDmitry Baryshkov 	/* mask off feature bits: */
1830325ba852SDmitry Baryshkov 	priv->rev &= ~0x30; /* not-hdcp and not-scalar bit */
1831325ba852SDmitry Baryshkov 
1832325ba852SDmitry Baryshkov 	switch (priv->rev) {
1833325ba852SDmitry Baryshkov 	case TDA9989N2:
1834325ba852SDmitry Baryshkov 		dev_info(dev, "found TDA9989 n2");
1835325ba852SDmitry Baryshkov 		break;
1836325ba852SDmitry Baryshkov 	case TDA19989:
1837325ba852SDmitry Baryshkov 		dev_info(dev, "found TDA19989");
1838325ba852SDmitry Baryshkov 		break;
1839325ba852SDmitry Baryshkov 	case TDA19989N2:
1840325ba852SDmitry Baryshkov 		dev_info(dev, "found TDA19989 n2");
1841325ba852SDmitry Baryshkov 		break;
1842325ba852SDmitry Baryshkov 	case TDA19988:
1843325ba852SDmitry Baryshkov 		dev_info(dev, "found TDA19988");
1844325ba852SDmitry Baryshkov 		break;
1845325ba852SDmitry Baryshkov 	default:
1846325ba852SDmitry Baryshkov 		dev_err(dev, "found unsupported device: %04x\n", priv->rev);
1847325ba852SDmitry Baryshkov 		return -ENXIO;
1848325ba852SDmitry Baryshkov 	}
1849325ba852SDmitry Baryshkov 
1850325ba852SDmitry Baryshkov 	/* after reset, enable DDC: */
1851325ba852SDmitry Baryshkov 	reg_write(priv, REG_DDC_DISABLE, 0x00);
1852325ba852SDmitry Baryshkov 
1853325ba852SDmitry Baryshkov 	/* set clock on DDC channel: */
1854325ba852SDmitry Baryshkov 	reg_write(priv, REG_TX3, 39);
1855325ba852SDmitry Baryshkov 
1856325ba852SDmitry Baryshkov 	/* if necessary, disable multi-master: */
1857325ba852SDmitry Baryshkov 	if (priv->rev == TDA19989)
1858325ba852SDmitry Baryshkov 		reg_set(priv, REG_I2C_MASTER, I2C_MASTER_DIS_MM);
1859325ba852SDmitry Baryshkov 
1860325ba852SDmitry Baryshkov 	cec_write(priv, REG_CEC_FRO_IM_CLK_CTRL,
1861325ba852SDmitry Baryshkov 			CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL);
1862325ba852SDmitry Baryshkov 
1863325ba852SDmitry Baryshkov 	/* ensure interrupts are disabled */
1864325ba852SDmitry Baryshkov 	cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
1865325ba852SDmitry Baryshkov 
1866325ba852SDmitry Baryshkov 	/* clear pending interrupts */
1867325ba852SDmitry Baryshkov 	cec_read(priv, REG_CEC_RXSHPDINT);
1868325ba852SDmitry Baryshkov 	reg_read(priv, REG_INT_FLAGS_0);
1869325ba852SDmitry Baryshkov 	reg_read(priv, REG_INT_FLAGS_1);
1870325ba852SDmitry Baryshkov 	reg_read(priv, REG_INT_FLAGS_2);
1871325ba852SDmitry Baryshkov 
1872325ba852SDmitry Baryshkov 	/* initialize the optional IRQ */
1873325ba852SDmitry Baryshkov 	if (client->irq) {
1874325ba852SDmitry Baryshkov 		unsigned long irq_flags;
1875325ba852SDmitry Baryshkov 
1876325ba852SDmitry Baryshkov 		/* init read EDID waitqueue and HDP work */
1877325ba852SDmitry Baryshkov 		init_waitqueue_head(&priv->wq_edid);
1878325ba852SDmitry Baryshkov 
1879325ba852SDmitry Baryshkov 		irq_flags =
1880325ba852SDmitry Baryshkov 			irqd_get_trigger_type(irq_get_irq_data(client->irq));
1881325ba852SDmitry Baryshkov 
1882325ba852SDmitry Baryshkov 		priv->cec_glue.irq_flags = irq_flags;
1883325ba852SDmitry Baryshkov 
1884325ba852SDmitry Baryshkov 		irq_flags |= IRQF_SHARED | IRQF_ONESHOT;
1885325ba852SDmitry Baryshkov 		ret = request_threaded_irq(client->irq, NULL,
1886325ba852SDmitry Baryshkov 					   tda998x_irq_thread, irq_flags,
1887325ba852SDmitry Baryshkov 					   "tda998x", priv);
1888325ba852SDmitry Baryshkov 		if (ret) {
1889325ba852SDmitry Baryshkov 			dev_err(dev, "failed to request IRQ#%u: %d\n",
1890325ba852SDmitry Baryshkov 				client->irq, ret);
1891325ba852SDmitry Baryshkov 			goto err_irq;
1892325ba852SDmitry Baryshkov 		}
1893325ba852SDmitry Baryshkov 
1894325ba852SDmitry Baryshkov 		/* enable HPD irq */
1895325ba852SDmitry Baryshkov 		cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD);
1896325ba852SDmitry Baryshkov 	}
1897325ba852SDmitry Baryshkov 
1898325ba852SDmitry Baryshkov 	priv->cec_notify = cec_notifier_conn_register(dev, NULL, NULL);
1899325ba852SDmitry Baryshkov 	if (!priv->cec_notify) {
1900325ba852SDmitry Baryshkov 		ret = -ENOMEM;
1901325ba852SDmitry Baryshkov 		goto fail;
1902325ba852SDmitry Baryshkov 	}
1903325ba852SDmitry Baryshkov 
1904325ba852SDmitry Baryshkov 	priv->cec_glue.parent = dev;
1905325ba852SDmitry Baryshkov 	priv->cec_glue.data = priv;
1906325ba852SDmitry Baryshkov 	priv->cec_glue.init = tda998x_cec_hook_init;
1907325ba852SDmitry Baryshkov 	priv->cec_glue.exit = tda998x_cec_hook_exit;
1908325ba852SDmitry Baryshkov 	priv->cec_glue.open = tda998x_cec_hook_open;
1909325ba852SDmitry Baryshkov 	priv->cec_glue.release = tda998x_cec_hook_release;
1910325ba852SDmitry Baryshkov 
1911325ba852SDmitry Baryshkov 	/*
1912325ba852SDmitry Baryshkov 	 * Some TDA998x are actually two I2C devices merged onto one piece
1913325ba852SDmitry Baryshkov 	 * of silicon: TDA9989 and TDA19989 combine the HDMI transmitter
1914325ba852SDmitry Baryshkov 	 * with a slightly modified TDA9950 CEC device.  The CEC device
1915325ba852SDmitry Baryshkov 	 * is at the TDA9950 address, with the address pins strapped across
1916325ba852SDmitry Baryshkov 	 * to the TDA998x address pins.  Hence, it always has the same
1917325ba852SDmitry Baryshkov 	 * offset.
1918325ba852SDmitry Baryshkov 	 */
1919325ba852SDmitry Baryshkov 	memset(&cec_info, 0, sizeof(cec_info));
1920325ba852SDmitry Baryshkov 	strscpy(cec_info.type, "tda9950", sizeof(cec_info.type));
1921325ba852SDmitry Baryshkov 	cec_info.addr = priv->cec_addr;
1922325ba852SDmitry Baryshkov 	cec_info.platform_data = &priv->cec_glue;
1923325ba852SDmitry Baryshkov 	cec_info.irq = client->irq;
1924325ba852SDmitry Baryshkov 
1925325ba852SDmitry Baryshkov 	priv->cec = i2c_new_client_device(client->adapter, &cec_info);
1926325ba852SDmitry Baryshkov 	if (IS_ERR(priv->cec)) {
1927325ba852SDmitry Baryshkov 		ret = PTR_ERR(priv->cec);
1928325ba852SDmitry Baryshkov 		goto fail;
1929325ba852SDmitry Baryshkov 	}
1930325ba852SDmitry Baryshkov 
1931325ba852SDmitry Baryshkov 	/* enable EDID read irq: */
1932325ba852SDmitry Baryshkov 	reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
1933325ba852SDmitry Baryshkov 
1934325ba852SDmitry Baryshkov 	if (np) {
1935325ba852SDmitry Baryshkov 		/* get the device tree parameters */
1936325ba852SDmitry Baryshkov 		ret = of_property_read_u32(np, "video-ports", &video);
1937325ba852SDmitry Baryshkov 		if (ret == 0) {
1938325ba852SDmitry Baryshkov 			priv->vip_cntrl_0 = video >> 16;
1939325ba852SDmitry Baryshkov 			priv->vip_cntrl_1 = video >> 8;
1940325ba852SDmitry Baryshkov 			priv->vip_cntrl_2 = video;
1941325ba852SDmitry Baryshkov 		}
1942325ba852SDmitry Baryshkov 
1943325ba852SDmitry Baryshkov 		ret = tda998x_get_audio_ports(priv, np);
1944325ba852SDmitry Baryshkov 		if (ret)
1945325ba852SDmitry Baryshkov 			goto fail;
1946325ba852SDmitry Baryshkov 
1947325ba852SDmitry Baryshkov 		if (priv->audio_port_enable[AUDIO_ROUTE_I2S] ||
1948325ba852SDmitry Baryshkov 		    priv->audio_port_enable[AUDIO_ROUTE_SPDIF])
1949325ba852SDmitry Baryshkov 			tda998x_audio_codec_init(priv, &client->dev);
1950325ba852SDmitry Baryshkov 	}
1951325ba852SDmitry Baryshkov 
1952325ba852SDmitry Baryshkov #ifdef CONFIG_OF
1953325ba852SDmitry Baryshkov 	priv->bridge.of_node = dev->of_node;
1954325ba852SDmitry Baryshkov #endif
1955325ba852SDmitry Baryshkov 
1956325ba852SDmitry Baryshkov 	drm_bridge_add(&priv->bridge);
1957325ba852SDmitry Baryshkov 
1958325ba852SDmitry Baryshkov 	return 0;
1959325ba852SDmitry Baryshkov 
1960325ba852SDmitry Baryshkov fail:
1961325ba852SDmitry Baryshkov 	tda998x_destroy(dev);
1962325ba852SDmitry Baryshkov err_irq:
1963325ba852SDmitry Baryshkov 	return ret;
1964325ba852SDmitry Baryshkov }
1965325ba852SDmitry Baryshkov 
1966325ba852SDmitry Baryshkov /* DRM encoder functions */
1967325ba852SDmitry Baryshkov 
tda998x_encoder_init(struct device * dev,struct drm_device * drm)1968325ba852SDmitry Baryshkov static int tda998x_encoder_init(struct device *dev, struct drm_device *drm)
1969325ba852SDmitry Baryshkov {
1970325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = dev_get_drvdata(dev);
1971325ba852SDmitry Baryshkov 	u32 crtcs = 0;
1972325ba852SDmitry Baryshkov 	int ret;
1973325ba852SDmitry Baryshkov 
1974325ba852SDmitry Baryshkov 	if (dev->of_node)
1975325ba852SDmitry Baryshkov 		crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
1976325ba852SDmitry Baryshkov 
1977325ba852SDmitry Baryshkov 	/* If no CRTCs were found, fall back to our old behaviour */
1978325ba852SDmitry Baryshkov 	if (crtcs == 0) {
1979325ba852SDmitry Baryshkov 		dev_warn(dev, "Falling back to first CRTC\n");
1980325ba852SDmitry Baryshkov 		crtcs = 1 << 0;
1981325ba852SDmitry Baryshkov 	}
1982325ba852SDmitry Baryshkov 
1983325ba852SDmitry Baryshkov 	priv->encoder.possible_crtcs = crtcs;
1984325ba852SDmitry Baryshkov 
1985325ba852SDmitry Baryshkov 	ret = drm_simple_encoder_init(drm, &priv->encoder,
1986325ba852SDmitry Baryshkov 				      DRM_MODE_ENCODER_TMDS);
1987325ba852SDmitry Baryshkov 	if (ret)
1988325ba852SDmitry Baryshkov 		goto err_encoder;
1989325ba852SDmitry Baryshkov 
1990325ba852SDmitry Baryshkov 	ret = drm_bridge_attach(&priv->encoder, &priv->bridge, NULL, 0);
1991325ba852SDmitry Baryshkov 	if (ret)
1992325ba852SDmitry Baryshkov 		goto err_bridge;
1993325ba852SDmitry Baryshkov 
1994325ba852SDmitry Baryshkov 	return 0;
1995325ba852SDmitry Baryshkov 
1996325ba852SDmitry Baryshkov err_bridge:
1997325ba852SDmitry Baryshkov 	drm_encoder_cleanup(&priv->encoder);
1998325ba852SDmitry Baryshkov err_encoder:
1999325ba852SDmitry Baryshkov 	return ret;
2000325ba852SDmitry Baryshkov }
2001325ba852SDmitry Baryshkov 
tda998x_bind(struct device * dev,struct device * master,void * data)2002325ba852SDmitry Baryshkov static int tda998x_bind(struct device *dev, struct device *master, void *data)
2003325ba852SDmitry Baryshkov {
2004325ba852SDmitry Baryshkov 	struct drm_device *drm = data;
2005325ba852SDmitry Baryshkov 
2006325ba852SDmitry Baryshkov 	return tda998x_encoder_init(dev, drm);
2007325ba852SDmitry Baryshkov }
2008325ba852SDmitry Baryshkov 
tda998x_unbind(struct device * dev,struct device * master,void * data)2009325ba852SDmitry Baryshkov static void tda998x_unbind(struct device *dev, struct device *master,
2010325ba852SDmitry Baryshkov 			   void *data)
2011325ba852SDmitry Baryshkov {
2012325ba852SDmitry Baryshkov 	struct tda998x_priv *priv = dev_get_drvdata(dev);
2013325ba852SDmitry Baryshkov 
2014325ba852SDmitry Baryshkov 	drm_encoder_cleanup(&priv->encoder);
2015325ba852SDmitry Baryshkov }
2016325ba852SDmitry Baryshkov 
2017325ba852SDmitry Baryshkov static const struct component_ops tda998x_ops = {
2018325ba852SDmitry Baryshkov 	.bind = tda998x_bind,
2019325ba852SDmitry Baryshkov 	.unbind = tda998x_unbind,
2020325ba852SDmitry Baryshkov };
2021325ba852SDmitry Baryshkov 
2022325ba852SDmitry Baryshkov static int
tda998x_probe(struct i2c_client * client)2023325ba852SDmitry Baryshkov tda998x_probe(struct i2c_client *client)
2024325ba852SDmitry Baryshkov {
2025325ba852SDmitry Baryshkov 	int ret;
2026325ba852SDmitry Baryshkov 
2027325ba852SDmitry Baryshkov 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
2028325ba852SDmitry Baryshkov 		dev_warn(&client->dev, "adapter does not support I2C\n");
2029325ba852SDmitry Baryshkov 		return -EIO;
2030325ba852SDmitry Baryshkov 	}
2031325ba852SDmitry Baryshkov 
2032325ba852SDmitry Baryshkov 	ret = tda998x_create(&client->dev);
2033325ba852SDmitry Baryshkov 	if (ret)
2034325ba852SDmitry Baryshkov 		return ret;
2035325ba852SDmitry Baryshkov 
2036325ba852SDmitry Baryshkov 	ret = component_add(&client->dev, &tda998x_ops);
2037325ba852SDmitry Baryshkov 	if (ret)
2038325ba852SDmitry Baryshkov 		tda998x_destroy(&client->dev);
2039325ba852SDmitry Baryshkov 	return ret;
2040325ba852SDmitry Baryshkov }
2041325ba852SDmitry Baryshkov 
tda998x_remove(struct i2c_client * client)2042325ba852SDmitry Baryshkov static void tda998x_remove(struct i2c_client *client)
2043325ba852SDmitry Baryshkov {
2044325ba852SDmitry Baryshkov 	component_del(&client->dev, &tda998x_ops);
2045325ba852SDmitry Baryshkov 	tda998x_destroy(&client->dev);
2046325ba852SDmitry Baryshkov }
2047325ba852SDmitry Baryshkov 
2048325ba852SDmitry Baryshkov #ifdef CONFIG_OF
2049325ba852SDmitry Baryshkov static const struct of_device_id tda998x_dt_ids[] = {
2050325ba852SDmitry Baryshkov 	{ .compatible = "nxp,tda998x", },
2051325ba852SDmitry Baryshkov 	{ }
2052325ba852SDmitry Baryshkov };
2053325ba852SDmitry Baryshkov MODULE_DEVICE_TABLE(of, tda998x_dt_ids);
2054325ba852SDmitry Baryshkov #endif
2055325ba852SDmitry Baryshkov 
2056325ba852SDmitry Baryshkov static const struct i2c_device_id tda998x_ids[] = {
2057325ba852SDmitry Baryshkov 	{ "tda998x" },
2058325ba852SDmitry Baryshkov 	{ }
2059325ba852SDmitry Baryshkov };
2060325ba852SDmitry Baryshkov MODULE_DEVICE_TABLE(i2c, tda998x_ids);
2061325ba852SDmitry Baryshkov 
2062325ba852SDmitry Baryshkov static struct i2c_driver tda998x_driver = {
2063325ba852SDmitry Baryshkov 	.probe = tda998x_probe,
2064325ba852SDmitry Baryshkov 	.remove = tda998x_remove,
2065325ba852SDmitry Baryshkov 	.driver = {
2066325ba852SDmitry Baryshkov 		.name = "tda998x",
2067325ba852SDmitry Baryshkov 		.of_match_table = of_match_ptr(tda998x_dt_ids),
2068325ba852SDmitry Baryshkov 	},
2069325ba852SDmitry Baryshkov 	.id_table = tda998x_ids,
2070325ba852SDmitry Baryshkov };
2071325ba852SDmitry Baryshkov 
2072325ba852SDmitry Baryshkov module_i2c_driver(tda998x_driver);
2073325ba852SDmitry Baryshkov 
2074325ba852SDmitry Baryshkov MODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
2075325ba852SDmitry Baryshkov MODULE_DESCRIPTION("NXP Semiconductors TDA998X HDMI Encoder");
2076325ba852SDmitry Baryshkov MODULE_LICENSE("GPL");
2077